shithub: riscv

Download patch

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\