ref: 45b7d60bf385aa9ac0bab7bb8c694f8221893024
parent: 0db4f40629762d1be583c49756cbcfc2561cb0fa
author: cinap_lenrek <[email protected]>
date: Tue Oct 17 17:34:01 EDT 2017
libsec: add AES CFB and AES OFB stream ciphers
--- a/sys/include/ape/libsec.h
+++ b/sys/include/ape/libsec.h
@@ -29,6 +29,7 @@
struct AESstate
{
ulong setup;
+ ulong offset;
int rounds;
int keybytes;
uchar key[AESmaxkey]; /* unexpanded key */
@@ -45,6 +46,9 @@
void setupAESstate(AESstate *s, uchar key[], int keybytes, uchar *ivec);
void aesCBCencrypt(uchar *p, int len, AESstate *s);
void aesCBCdecrypt(uchar *p, int len, AESstate *s);
+void aesCFBencrypt(uchar *p, int len, AESstate *s);
+void aesCFBdecrypt(uchar *p, int len, AESstate *s);
+void aesOFBencrypt(uchar *p, int len, AESstate *s);
void setupAESXCBCstate(AESstate *s);
uchar* aesXCBCmac(uchar *p, int len, AESstate *s);
--- a/sys/include/libsec.h
+++ b/sys/include/libsec.h
@@ -21,6 +21,7 @@
struct AESstate
{
ulong setup;
+ ulong offset;
int rounds;
int keybytes;
uchar key[AESmaxkey]; /* unexpanded key */
@@ -37,6 +38,9 @@
void setupAESstate(AESstate *s, uchar key[], int keybytes, uchar *ivec);
void aesCBCencrypt(uchar *p, int len, AESstate *s);
void aesCBCdecrypt(uchar *p, int len, AESstate *s);
+void aesCFBencrypt(uchar *p, int len, AESstate *s);
+void aesCFBdecrypt(uchar *p, int len, AESstate *s);
+void aesOFBencrypt(uchar *p, int len, AESstate *s);
void setupAESXCBCstate(AESstate *s);
uchar* aesXCBCmac(uchar *p, int len, AESstate *s);
--- a/sys/man/2/aes
+++ b/sys/man/2/aes
@@ -1,6 +1,6 @@
.TH AES 2
.SH NAME
-setupAESstate, aesCBCencrypt, aesCBCdecrypt, setupAESXCBCstate, aesXCBCmac, setupAESGCMstate - advanced encryption standard (rijndael)
+setupAESstate, aesCBCencrypt, aesCBCdecrypt, aesCFBencrypt, aesCFBdecrypt, aesOFBencrypt, setupAESXCBCstate, aesXCBCmac, setupAESGCMstate - advanced encryption standard (rijndael)
.SH SYNOPSIS
.B #include <u.h>
.br
@@ -28,6 +28,15 @@
void aesCBCdecrypt(uchar *p, int len, AESstate *s)
.PP
.B
+void aesCFBencrypt(uchar *p, int len, AESstate *s)
+.PP
+.B
+void aesCFBdecrypt(uchar *p, int len, AESstate *s)
+.PP
+.B
+void aesOFBencrypt(uchar *p, int len, AESstate *s)
+.PP
+.B
void setupAESXCBCstate(AESstate *s)
.PP
.B
@@ -53,11 +62,18 @@
are the block ciphers, corresponding to
.IR des (2)'s
.IR block_cipher .
-.IR SetupAESstate ,
-.IR aesCBCencrypt ,
+.IR AesCBCencrypt ,
and
.I aesCBCdecrypt
implement cipher-block-chaining encryption.
+.IR AesCFBencrypt ,
+.I aesCFBdecrypt
+and
+.I aesOFBencrypt
+implement cipher-feedback- and output-feedback-mode
+stream cipher encryption.
+.IR SetupAESstate
+is used to initialize the state of the above encryption modes.
.I SetupAESXCBCstate
and
.I aesXCBCmac
--- a/sys/src/ape/lib/sec/port/mkfile
+++ b/sys/src/ape/lib/sec/port/mkfile
@@ -4,7 +4,8 @@
LIB=/$objtype/lib/ape/libsec.a
CFILES = des.c desmodes.c desECB.c desCBC.c des3ECB.c des3CBC.c\
- aes.c aes_gcm.c blowfish.c \
+ aes.c aesCBC.c aesCFB.c aesOFB.c aesXCBmac.c aes_gcm.c \
+ blowfish.c \
hmac.c md5.c md5block.c md4.c sha1.c sha1block.c\
sha2_64.c sha2_128.c sha2block64.c sha2block128.c\
sha1pickle.c md5pickle.c\
--- a/sys/src/libsec/port/aes.c
+++ b/sys/src/libsec/port/aes.c
@@ -42,20 +42,6 @@
static const u32 Td2[256];
static const u32 Td3[256];
static const u8 Te4[256];
-static uchar basekey[3][16] = {
- {
- 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
- 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
- },
- {
- 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
- 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
- },
- {
- 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
- 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
- },
-};
static int aes_setupEnc(ulong rk[/*4*(Nr + 1)*/], const uchar cipherKey[],
int keyBits);
@@ -65,6 +51,11 @@
void aes_encrypt(const ulong rk[], int Nr, const uchar pt[16], uchar ct[16]);
void aes_decrypt(const ulong rk[], int Nr, const uchar ct[16], uchar pt[16]);
+#define GETU32(pt) (((u32)(pt)[0]<<24) ^ ((u32)(pt)[1]<<16) ^ \
+ ((u32)(pt)[2]<< 8) ^ ((u32)(pt)[3]))
+#define PUTU32(ct, st) { (ct)[0] = (u8)((st)>>24); (ct)[1] = (u8)((st)>>16); \
+ (ct)[2] = (u8)((st)>> 8); (ct)[3] = (u8)(st); }
+
void
setupAESstate(AESstate *s, uchar key[], int keybytes, uchar *ivec)
{
@@ -82,141 +73,6 @@
}
/*
- * AES-XCBC-MAC-96 message authentication, per rfc3566.
- */
-
-void
-setupAESXCBCstate(AESstate *s) /* was setupmac96 */
-{
- int i, j;
- uint q[16 / sizeof(uint)];
- uchar *p;
-
- assert(s->keybytes == 16);
- for(i = 0; i < 3; i++)
- aes_encrypt(s->ekey, s->rounds, basekey[i],
- s->mackey + AESbsize*i);
-
- p = s->mackey;
- memset(q, 0, AESbsize);
-
- /*
- * put the in the right endian. once figured, probably better
- * to use some fcall macros.
- * keys for encryption in local endianness for the algorithm...
- * only key1 is used for encryption;
- * BUG!!: I think this is what I got wrong.
- */
- for(i = 0; i < 16 / sizeof(uint); i ++){
- for(j = 0; j < sizeof(uint); j++)
- q[i] |= p[sizeof(uint)-j-1] << 8*j;
- p += sizeof(uint);
- }
- memmove(s->mackey, q, 16);
-}
-
-/*
- * Not dealing with > 128-bit keys, not dealing with strange corner cases like
- * empty message. Should be fine for AES-XCBC-MAC-96.
- */
-uchar*
-aesXCBCmac(uchar *p, int len, AESstate *s)
-{
- uchar *p2, *ip, *eip, *mackey;
- uchar q[AESbsize];
-
- assert(s->keybytes == 16); /* more complicated for bigger */
- memset(s->ivec, 0, AESbsize); /* E[0] is 0+ */
-
- for(; len > AESbsize; len -= AESbsize){
- memmove(q, p, AESbsize);
- p2 = q;
- ip = s->ivec;
- for(eip = ip + AESbsize; ip < eip; )
- *p2++ ^= *ip++;
- aes_encrypt((ulong *)s->mackey, s->rounds, q, s->ivec);
- p += AESbsize;
- }
- /* the last one */
-
- memmove(q, p, len);
- p2 = q+len;
- if(len == AESbsize)
- mackey = s->mackey + AESbsize; /* k2 */
- else{
- mackey = s->mackey+2*AESbsize; /* k3 */
- *p2++ = 1 << 7; /* padding */
- len = AESbsize - len - 1;
- memset(p2, 0, len);
- }
-
- ip = s->ivec;
- p2 = q;
- for(eip = ip + AESbsize; ip < eip; )
- *p2++ ^= *ip++ ^ *mackey++;
- aes_encrypt((ulong *)s->mackey, s->rounds, q, s->ivec);
- return s->ivec; /* only the 12 bytes leftmost */
-}
-
-/*
- * Define by analogy with desCBCencrypt; AES modes are not standardized yet.
- * Because of the way that non-multiple-of-16 buffers are handled,
- * the decryptor must be fed buffers of the same size as the encryptor.
- */
-void
-aesCBCencrypt(uchar *p, int len, AESstate *s)
-{
- uchar *p2, *ip, *eip;
- uchar q[AESbsize];
-
- for(; len >= AESbsize; len -= AESbsize){
- p2 = p;
- ip = s->ivec;
- for(eip = ip+AESbsize; ip < eip; )
- *p2++ ^= *ip++;
- aes_encrypt(s->ekey, s->rounds, p, q);
- memmove(s->ivec, q, AESbsize);
- memmove(p, q, AESbsize);
- p += AESbsize;
- }
-
- if(len > 0){
- ip = s->ivec;
- aes_encrypt(s->ekey, s->rounds, ip, q);
- memmove(s->ivec, q, AESbsize);
- for(eip = ip+len; ip < eip; )
- *p++ ^= *ip++;
- }
-}
-
-void
-aesCBCdecrypt(uchar *p, int len, AESstate *s)
-{
- uchar *ip, *eip, *tp;
- uchar tmp[AESbsize], q[AESbsize];
-
- for(; len >= AESbsize; len -= AESbsize){
- memmove(tmp, p, AESbsize);
- aes_decrypt(s->dkey, s->rounds, p, q);
- memmove(p, q, AESbsize);
- tp = tmp;
- ip = s->ivec;
- for(eip = ip+AESbsize; ip < eip; ){
- *p++ ^= *ip;
- *ip++ = *tp++;
- }
- }
-
- if(len > 0){
- ip = s->ivec;
- aes_encrypt(s->ekey, s->rounds, ip, q);
- memmove(s->ivec, q, AESbsize);
- for(eip = ip+len; ip < eip; )
- *p++ ^= *ip++;
- }
-}
-
-/*
* this function has been changed for plan 9.
* Expand the cipher key into the encryption and decryption key schedules.
*
@@ -954,11 +810,6 @@
0x1B000000, 0x36000000,
/* for 128-bit blocks, Rijndael never uses more than 10 rcon values */
};
-
-#define GETU32(pt) (((u32)(pt)[0]<<24) ^ ((u32)(pt)[1]<<16) ^ \
- ((u32)(pt)[2]<< 8) ^ ((u32)(pt)[3]))
-#define PUTU32(ct, st) { (ct)[0] = (u8)((st)>>24); (ct)[1] = (u8)((st)>>16); \
- (ct)[2] = (u8)((st)>> 8); (ct)[3] = (u8)(st); }
/*
* Expand the cipher key into the encryption key schedule.
--- /dev/null
+++ b/sys/src/libsec/port/aesCBC.c
@@ -1,0 +1,60 @@
+#include "os.h"
+#include <libsec.h>
+
+/*
+ * Define by analogy with desCBCencrypt; AES modes are not standardized yet.
+ * Because of the way that non-multiple-of-16 buffers are handled,
+ * the decryptor must be fed buffers of the same size as the encryptor.
+ */
+void
+aesCBCencrypt(uchar *p, int len, AESstate *s)
+{
+ uchar *p2, *ip, *eip;
+ uchar q[AESbsize];
+
+ for(; len >= AESbsize; len -= AESbsize){
+ p2 = p;
+ ip = s->ivec;
+ for(eip = ip+AESbsize; ip < eip; )
+ *p2++ ^= *ip++;
+ aes_encrypt(s->ekey, s->rounds, p, q);
+ memmove(s->ivec, q, AESbsize);
+ memmove(p, q, AESbsize);
+ p += AESbsize;
+ }
+
+ if(len > 0){
+ ip = s->ivec;
+ aes_encrypt(s->ekey, s->rounds, ip, q);
+ memmove(s->ivec, q, AESbsize);
+ for(eip = ip+len; ip < eip; )
+ *p++ ^= *ip++;
+ }
+}
+
+void
+aesCBCdecrypt(uchar *p, int len, AESstate *s)
+{
+ uchar *ip, *eip, *tp;
+ uchar tmp[AESbsize], q[AESbsize];
+
+ for(; len >= AESbsize; len -= AESbsize){
+ memmove(tmp, p, AESbsize);
+ aes_decrypt(s->dkey, s->rounds, p, q);
+ memmove(p, q, AESbsize);
+ tp = tmp;
+ ip = s->ivec;
+ for(eip = ip+AESbsize; ip < eip; ){
+ *p++ ^= *ip;
+ *ip++ = *tp++;
+ }
+ }
+
+ if(len > 0){
+ ip = s->ivec;
+ aes_encrypt(s->ekey, s->rounds, ip, q);
+ memmove(s->ivec, q, AESbsize);
+ for(eip = ip+len; ip < eip; )
+ *p++ ^= *ip++;
+ }
+}
--- /dev/null
+++ b/sys/src/libsec/port/aesCFB.c
@@ -1,0 +1,50 @@
+#include "os.h"
+#include <libsec.h>
+
+typedef ulong u32;
+
+void
+aesCFBencrypt(uchar *p, int len, AESstate *s)
+{
+ u32 a, o = s->offset;
+
+ while(len > 0){
+ if(o % 16){
+ Odd:
+ a = (s->ivec[o++ % 16] ^= *p), *p++ = a, len--;
+ continue;
+ }
+ aes_encrypt(s->ekey, s->rounds, s->ivec, s->ivec);
+ if(len < 16 || ((p-(uchar*)0) & 3) != 0)
+ goto Odd;
+ ((u32*)p)[0] = (((u32*)s->ivec)[0] ^= ((u32*)p)[0]);
+ ((u32*)p)[1] = (((u32*)s->ivec)[1] ^= ((u32*)p)[1]);
+ ((u32*)p)[2] = (((u32*)s->ivec)[2] ^= ((u32*)p)[2]);
+ ((u32*)p)[3] = (((u32*)s->ivec)[3] ^= ((u32*)p)[3]);
+ o += 16, p += 16, len -= 16;
+ }
+ s->offset = o;
+}
+
+void
+aesCFBdecrypt(uchar *p, int len, AESstate *s)
+{
+ u32 a, o = s->offset;
+
+ while(len > 0){
+ if(o % 16){
+ Odd:
+ a = *p, *p++ ^= s->ivec[o % 16], s->ivec[o++ % 16] = a, len--;
+ continue;
+ }
+ aes_encrypt(s->ekey, s->rounds, s->ivec, s->ivec);
+ if(len < 16 || ((p-(uchar*)0) & 3) != 0)
+ goto Odd;
+ a = ((u32*)p)[0], ((u32*)p)[0] ^= ((u32*)s->ivec)[0], ((u32*)s->ivec)[0] = a;
+ a = ((u32*)p)[1], ((u32*)p)[1] ^= ((u32*)s->ivec)[1], ((u32*)s->ivec)[1] = a;
+ a = ((u32*)p)[2], ((u32*)p)[2] ^= ((u32*)s->ivec)[2], ((u32*)s->ivec)[2] = a;
+ a = ((u32*)p)[3], ((u32*)p)[3] ^= ((u32*)s->ivec)[3], ((u32*)s->ivec)[3] = a;
+ o += 16, p += 16, len -= 16;
+ }
+ s->offset = o;
+}
--- /dev/null
+++ b/sys/src/libsec/port/aesOFB.c
@@ -1,0 +1,28 @@
+#include "os.h"
+#include <libsec.h>
+
+typedef ulong u32;
+
+void
+aesOFBencrypt(uchar *p, int len, AESstate *s)
+{
+ u32 o = s->offset;
+
+ while(len > 0){
+ if(o % 16){
+ Odd:
+ *p++ ^= s->ivec[o++ % 16], len--;
+ continue;
+ }
+ aes_encrypt(s->ekey, s->rounds, s->ivec, s->ivec);
+ if(len < 16 || ((p-(uchar*)0) & 3) != 0)
+ goto Odd;
+ ((u32*)p)[0] ^= ((u32*)s->ivec)[0];
+ ((u32*)p)[1] ^= ((u32*)s->ivec)[1];
+ ((u32*)p)[2] ^= ((u32*)s->ivec)[2];
+ ((u32*)p)[3] ^= ((u32*)s->ivec)[3];
+ o += 16, p += 16, len -= 16;
+ }
+ s->offset = o;
+}
+
--- /dev/null
+++ b/sys/src/libsec/port/aesXCBmac.c
@@ -1,0 +1,93 @@
+#include "os.h"
+#include <libsec.h>
+
+/*
+ * AES-XCBC-MAC-96 message authentication, per rfc3566.
+ */
+static uchar basekey[3][16] = {
+ {
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ },
+ {
+ 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+ 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+ },
+ {
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+ },
+};
+
+void
+setupAESXCBCstate(AESstate *s) /* was setupmac96 */
+{
+ int i, j;
+ uint q[16 / sizeof(uint)];
+ uchar *p;
+
+ assert(s->keybytes == 16);
+ for(i = 0; i < 3; i++)
+ aes_encrypt(s->ekey, s->rounds, basekey[i],
+ s->mackey + AESbsize*i);
+
+ p = s->mackey;
+ memset(q, 0, AESbsize);
+
+ /*
+ * put the in the right endian. once figured, probably better
+ * to use some fcall macros.
+ * keys for encryption in local endianness for the algorithm...
+ * only key1 is used for encryption;
+ * BUG!!: I think this is what I got wrong.
+ */
+ for(i = 0; i < 16 / sizeof(uint); i ++){
+ for(j = 0; j < sizeof(uint); j++)
+ q[i] |= p[sizeof(uint)-j-1] << 8*j;
+ p += sizeof(uint);
+ }
+ memmove(s->mackey, q, 16);
+}
+
+/*
+ * Not dealing with > 128-bit keys, not dealing with strange corner cases like
+ * empty message. Should be fine for AES-XCBC-MAC-96.
+ */
+uchar*
+aesXCBCmac(uchar *p, int len, AESstate *s)
+{
+ uchar *p2, *ip, *eip, *mackey;
+ uchar q[AESbsize];
+
+ assert(s->keybytes == 16); /* more complicated for bigger */
+ memset(s->ivec, 0, AESbsize); /* E[0] is 0+ */
+
+ for(; len > AESbsize; len -= AESbsize){
+ memmove(q, p, AESbsize);
+ p2 = q;
+ ip = s->ivec;
+ for(eip = ip + AESbsize; ip < eip; )
+ *p2++ ^= *ip++;
+ aes_encrypt((ulong *)s->mackey, s->rounds, q, s->ivec);
+ p += AESbsize;
+ }
+ /* the last one */
+
+ memmove(q, p, len);
+ p2 = q+len;
+ if(len == AESbsize)
+ mackey = s->mackey + AESbsize; /* k2 */
+ else{
+ mackey = s->mackey+2*AESbsize; /* k3 */
+ *p2++ = 1 << 7; /* padding */
+ len = AESbsize - len - 1;
+ memset(p2, 0, len);
+ }
+
+ ip = s->ivec;
+ p2 = q;
+ for(eip = ip + AESbsize; ip < eip; )
+ *p2++ ^= *ip++ ^ *mackey++;
+ aes_encrypt((ulong *)s->mackey, s->rounds, q, s->ivec);
+ return s->ivec; /* only the 12 bytes leftmost */
+}
--- a/sys/src/libsec/port/mkfile
+++ b/sys/src/libsec/port/mkfile
@@ -3,7 +3,8 @@
LIB=/$objtype/lib/libsec.a
CFILES = des.c desmodes.c desECB.c desCBC.c des3ECB.c des3CBC.c\
- aes.c aes_gcm.c blowfish.c \
+ aes.c aesCBC.c aesCFB.c aesOFB.c aesXCBmac.c aes_gcm.c \
+ blowfish.c \
hmac.c md5.c md5block.c md4.c sha1.c sha1block.c\
sha2_64.c sha2_128.c sha2block64.c sha2block128.c\
sha1pickle.c md5pickle.c\