-
Notifications
You must be signed in to change notification settings - Fork 23
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add ChaCha20 stream cipher (RFC7539). http://9legacy.org/9legacy/patch/libsec-chacha.diff
- Loading branch information
1 parent
7eafb1e
commit e5931ae
Showing
4 changed files
with
282 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,6 +5,7 @@ LIB=libsec.a | |
OFILES=\ | ||
aes.$O\ | ||
blowfish.$O\ | ||
chacha.$O\ | ||
decodepem.$O\ | ||
des.$O\ | ||
des3CBC.$O\ | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,175 @@ | ||
/* | ||
Adapted from chacha-merged.c version 20080118 | ||
D. J. Bernstein | ||
Public domain. | ||
modified for use in Plan 9 and Inferno (no algorithmic changes), | ||
and including the changes to block number and nonce defined in RFC7539 | ||
*/ | ||
|
||
#include <u.h> | ||
#include <libc.h> | ||
#include <libsec.h> | ||
|
||
enum{ | ||
Blockwords= ChachaBsize/sizeof(u32int) | ||
}; | ||
|
||
/* little-endian data order */ | ||
#define GET4(p) ((((((p)[3]<<8) | (p)[2])<<8) | (p)[1])<<8 | (p)[0]) | ||
#define PUT4(p, v) (((p)[0]=v), (v>>=8), ((p)[1]=v), (v>>=8), ((p)[2]=v), (v>>=8), ((p)[3]=v)) | ||
|
||
#define ROTATE(v,c) ((u32int)((v) << (c)) | ((v) >> (32 - (c)))) | ||
|
||
#define QUARTERROUND(ia,ib,ic,id) { \ | ||
u32int a, b, c, d, t;\ | ||
a = x[ia]; b = x[ib]; c = x[ic]; d = x[id]; \ | ||
a += b; t = d^a; d = ROTATE(t,16); \ | ||
c += d; t = b^c; b = ROTATE(t,12); \ | ||
a += b; t = d^a; d = ROTATE(t, 8); \ | ||
c += d; t = b^c; b = ROTATE(t, 7); \ | ||
x[ia] = a; x[ib] = b; x[ic] = c; x[id] = d; \ | ||
} | ||
|
||
#define ENCRYPT(s, x, y, d) {\ | ||
u32int v; \ | ||
uchar *sp, *dp; \ | ||
sp = (s); \ | ||
v = GET4(sp); \ | ||
v ^= (x)+(y); \ | ||
dp = (d); \ | ||
PUT4(dp, v); \ | ||
} | ||
|
||
static uchar sigma[16] = "expand 32-byte k"; | ||
static uchar tau[16] = "expand 16-byte k"; | ||
|
||
static void | ||
load(u32int *d, uchar *s, int nw) | ||
{ | ||
int i; | ||
|
||
for(i = 0; i < nw; i++, s+=4) | ||
d[i] = GET4(s); | ||
} | ||
|
||
void | ||
setupChachastate(Chachastate *s, uchar *key, usize keylen, uchar *iv, int rounds) | ||
{ | ||
if(keylen != 256/8 && keylen != 128/8) | ||
sysfatal("invalid chacha key length"); | ||
if(rounds == 0) | ||
rounds = 20; | ||
s->rounds = rounds; | ||
if(keylen == 256/8) { /* recommended */ | ||
load(&s->input[0], sigma, 4); | ||
load(&s->input[4], key, 8); | ||
}else{ | ||
load(&s->input[0], tau, 4); | ||
load(&s->input[4], key, 4); | ||
load(&s->input[8], key, 4); | ||
} | ||
s->input[12] = 0; | ||
if(iv == nil){ | ||
s->input[13] = 0; | ||
s->input[14] = 0; | ||
s->input[15] = 0; | ||
}else | ||
load(&s->input[13], iv, 3); | ||
} | ||
|
||
void | ||
chacha_setblock(Chachastate *s, u32int blockno) | ||
{ | ||
s->input[12] = blockno; | ||
} | ||
|
||
static void | ||
encryptblock(Chachastate *s, uchar *src, uchar *dst) | ||
{ | ||
u32int x[Blockwords]; | ||
int i, rounds; | ||
|
||
rounds = s->rounds; | ||
x[0] = s->input[0]; | ||
x[1] = s->input[1]; | ||
x[2] = s->input[2]; | ||
x[3] = s->input[3]; | ||
x[4] = s->input[4]; | ||
x[5] = s->input[5]; | ||
x[6] = s->input[6]; | ||
x[7] = s->input[7]; | ||
x[8] = s->input[8]; | ||
x[9] = s->input[9]; | ||
x[10] = s->input[10]; | ||
x[11] = s->input[11]; | ||
x[12] = s->input[12]; | ||
x[13] = s->input[13]; | ||
x[14] = s->input[14]; | ||
x[15] = s->input[15]; | ||
|
||
for(i = rounds; i > 0; i -= 2) { | ||
QUARTERROUND(0, 4, 8,12) | ||
QUARTERROUND(1, 5, 9,13) | ||
QUARTERROUND(2, 6,10,14) | ||
QUARTERROUND(3, 7,11,15) | ||
|
||
QUARTERROUND(0, 5,10,15) | ||
QUARTERROUND(1, 6,11,12) | ||
QUARTERROUND(2, 7, 8,13) | ||
QUARTERROUND(3, 4, 9,14) | ||
} | ||
|
||
#ifdef FULL_UNROLL | ||
ENCRYPT(src+0*4, x[0], s->input[0], dst+0*4); | ||
ENCRYPT(src+1*4, x[1], s->input[1], dst+1*4); | ||
ENCRYPT(src+2*4, x[2], s->input[2], dst+2*4); | ||
ENCRYPT(src+3*4, x[3], s->input[3], dst+3*4); | ||
ENCRYPT(src+4*4, x[4], s->input[4], dst+4*4); | ||
ENCRYPT(src+5*4, x[5], s->input[5], dst+5*4); | ||
ENCRYPT(src+6*4, x[6], s->input[6], dst+6*4); | ||
ENCRYPT(src+7*4, x[7], s->input[7], dst+7*4); | ||
ENCRYPT(src+8*4, x[8], s->input[8], dst+8*4); | ||
ENCRYPT(src+9*4, x[9], s->input[9], dst+9*4); | ||
ENCRYPT(src+10*4, x[10], s->input[10], dst+10*4); | ||
ENCRYPT(src+11*4, x[11], s->input[11], dst+11*4); | ||
ENCRYPT(src+12*4, x[12], s->input[12], dst+12*4); | ||
ENCRYPT(src+13*4, x[13], s->input[13], dst+13*4); | ||
ENCRYPT(src+14*4, x[14], s->input[14], dst+14*4); | ||
ENCRYPT(src+15*4, x[15], s->input[15], dst+15*4); | ||
#else | ||
for(i=0; i<nelem(x); i+=4){ | ||
ENCRYPT(src, x[i], s->input[i], dst); | ||
ENCRYPT(src+4, x[i+1], s->input[i+1], dst+4); | ||
ENCRYPT(src+8, x[i+2], s->input[i+2], dst+8); | ||
ENCRYPT(src+12, x[i+3], s->input[i+3], dst+12); | ||
src += 16; | ||
dst += 16; | ||
} | ||
#endif | ||
|
||
s->input[12]++; | ||
} | ||
|
||
void | ||
chacha_encrypt2(uchar *src, uchar *dst, usize bytes, Chachastate *s) | ||
{ | ||
uchar tmp[ChachaBsize]; | ||
|
||
for(; bytes >= ChachaBsize; bytes -= ChachaBsize){ | ||
encryptblock(s, src, dst); | ||
src += ChachaBsize; | ||
dst += ChachaBsize; | ||
} | ||
if(bytes > 0){ | ||
memmove(tmp, src, bytes); | ||
encryptblock(s, tmp, tmp); | ||
memmove(dst, tmp, bytes); | ||
} | ||
} | ||
|
||
void | ||
chacha_encrypt(uchar *buf, usize bytes, Chachastate *s) | ||
{ | ||
chacha_encrypt2(buf, buf, bytes, s); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
#include <u.h> | ||
#include <libc.h> | ||
#include <libsec.h> | ||
|
||
static void | ||
printblock(uchar *b, usize n) | ||
{ | ||
int i; | ||
|
||
for(i=0; i+8<=n; i+=8){ | ||
print("%#.2ux %#.2ux %#.2ux %#.2ux %#.2ux %#.2ux %#.2ux %#.2ux\n", | ||
b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]); | ||
b += 8; | ||
} | ||
if(i < n){ | ||
print("%#.2ux", *b++); | ||
while(++i < n) | ||
print(" %#.2ux", *b++); | ||
print("\n"); | ||
} | ||
} | ||
|
||
/* test vector from RFC7539 */ | ||
uchar rfckey[] = { | ||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, | ||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, | ||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, | ||
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f}; | ||
uchar rfcnonce[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x00}; | ||
u32int rfccount = 1; | ||
char rfctext[] = "Ladies and Gentlemen of the class of '99: If I could offer you only one tip for the future, " | ||
"sunscreen would be it."; | ||
uchar rfcout[3*ChachaBsize]; | ||
uchar rfcref[3*ChachaBsize] = { | ||
0x6e, 0x2e, 0x35, 0x9a, 0x25, 0x68, 0xf9, 0x80, 0x41, 0xba, 0x07, 0x28, 0xdd, 0x0d, 0x69, 0x81, | ||
0xe9, 0x7e, 0x7a, 0xec, 0x1d, 0x43, 0x60, 0xc2, 0x0a, 0x27, 0xaf, 0xcc, 0xfd, 0x9f, 0xae, 0x0b, | ||
0xf9, 0x1b, 0x65, 0xc5, 0x52, 0x47, 0x33, 0xab, 0x8f, 0x59, 0x3d, 0xab, 0xcd, 0x62, 0xb3, 0x57, | ||
0x16, 0x39, 0xd6, 0x24, 0xe6, 0x51, 0x52, 0xab, 0x8f, 0x53, 0x0c, 0x35, 0x9f, 0x08, 0x61, 0xd8, | ||
0x07, 0xca, 0x0d, 0xbf, 0x50, 0x0d, 0x6a, 0x61, 0x56, 0xa3, 0x8e, 0x08, 0x8a, 0x22, 0xb6, 0x5e, | ||
0x52, 0xbc, 0x51, 0x4d, 0x16, 0xcc, 0xf8, 0x06, 0x81, 0x8c, 0xe9, 0x1a, 0xb7, 0x79, 0x37, 0x36, | ||
0x5a, 0xf9, 0x0b, 0xbf, 0x74, 0xa3, 0x5b, 0xe6, 0xb4, 0x0b, 0x8e, 0xed, 0xf2, 0x78, 0x5e, 0x42, | ||
0x87, 0x4d | ||
}; | ||
|
||
void | ||
main(int argc, char **argv) | ||
{ | ||
Chachastate s; | ||
int n; | ||
|
||
ARGBEGIN{ | ||
}ARGEND | ||
print("rfc7539:\n"); | ||
print("key:\n"); | ||
printblock(rfckey, sizeof(rfckey)); | ||
n = strlen(rfctext); | ||
setupChachastate(&s, rfckey, sizeof(rfckey), rfcnonce, 0); | ||
chacha_setblock(&s, rfccount); | ||
print("rfc in:\n"); | ||
printblock((uchar*)rfctext, n); | ||
chacha_encrypt2((uchar*)rfctext, rfcout, n, &s); | ||
print("rfc out:\n"); | ||
printblock(rfcout, n); | ||
if(memcmp(rfcout, rfcref, sizeof(rfcout)) != 0){ | ||
print("failure of vision\n"); | ||
exits("wrong"); | ||
} | ||
print("passed\n"); | ||
exits(nil); | ||
} |