Skip to content

Commit 33fb45b

Browse files
committed
libsec: add chacha20 poly1305 aead, allow 64 bit iv's for chacha,
add tsmemcmp() http://9legacy.org/9legacy/patch/libsec-chacha-iv.diff
1 parent 9fa547e commit 33fb45b

File tree

6 files changed

+192
-10
lines changed

6 files changed

+192
-10
lines changed

include/libsec.h

+10-2
Original file line numberDiff line numberDiff line change
@@ -104,13 +104,18 @@ struct Chachastate
104104
};
105105
};
106106
int rounds;
107+
int ivwords;
107108
};
108109

109-
void setupChachastate(Chachastate*, uchar*, usize, uchar*, int);
110-
void chacha_setblock(Chachastate*, u32int);
110+
void setupChachastate(Chachastate*, uchar*, usize, uchar*, ulong, int);
111+
void chacha_setiv(Chachastate *, uchar*);
112+
void chacha_setblock(Chachastate*, u64int);
111113
void chacha_encrypt(uchar*, usize, Chachastate*);
112114
void chacha_encrypt2(uchar*, uchar*, usize, Chachastate*);
113115

116+
void ccpoly_encrypt(uchar *dat, ulong ndat, uchar *aad, ulong naad, uchar tag[16], Chachastate *cs);
117+
int ccpoly_decrypt(uchar *dat, ulong ndat, uchar *aad, ulong naad, uchar tag[16], Chachastate *cs);
118+
114119
/*
115120
* DES definitions
116121
*/
@@ -451,3 +456,6 @@ void pbkdf2_x(uchar *p, ulong plen, uchar *s, ulong slen, ulong rounds, uchar *d
451456
/* hmac-based key derivation function (rfc5869) */
452457
void hkdf_x(uchar *salt, ulong nsalt, uchar *info, ulong ninfo, uchar *key, ulong nkey, uchar *d, ulong dlen,
453458
DigestState* (*x)(uchar*, ulong, uchar*, ulong, uchar*, DigestState*), int xlen);
459+
460+
/* timing safe memcmp() */
461+
int tsmemcmp(void*, void*, ulong);

libsec/Makefile

+2
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ OFILES=\
5555
pbkdf2.$O\
5656
hkdf.$O\
5757
poly1305.$O\
58+
ccpoly.$O\
59+
tsmemcmp.$O\
5860

5961
default: $(LIB)
6062
$(LIB): $(OFILES)

libsec/ccpoly.c

+84
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
#include <u.h>
2+
#include <libc.h>
3+
#include <libsec.h>
4+
5+
static void
6+
ccpolyotk(Chachastate *cs, DigestState *ds)
7+
{
8+
uchar otk[ChachaBsize];
9+
10+
memset(ds, 0, sizeof(*ds));
11+
memset(otk, 0, 32);
12+
chacha_setblock(cs, 0);
13+
chacha_encrypt(otk, ChachaBsize, cs);
14+
poly1305(nil, 0, otk, 32, nil, ds);
15+
}
16+
17+
static void
18+
ccpolymac(uchar *buf, ulong nbuf, DigestState *ds)
19+
{
20+
static uchar zeros[16] = {0};
21+
ulong npad;
22+
23+
if(nbuf == 0)
24+
return;
25+
poly1305(buf, nbuf, nil, 0, nil, ds);
26+
npad = nbuf % 16;
27+
if(npad == 0)
28+
return;
29+
poly1305(zeros, 16 - npad, nil, 0, nil, ds);
30+
}
31+
32+
static void
33+
ccpolytag(ulong ndat, ulong naad, uchar tag[16], DigestState *ds)
34+
{
35+
uchar info[16];
36+
37+
info[0] = naad;
38+
info[1] = naad>>8;
39+
info[2] = naad>>16;
40+
info[3] = naad>>24;
41+
info[4] = 0;
42+
info[5] = 0;
43+
info[6] = 0;
44+
info[7] = 0;
45+
46+
info[8] = ndat;
47+
info[9] = ndat>>8;
48+
info[10] = ndat>>16;
49+
info[11] = ndat>>24;
50+
info[12] = 0;
51+
info[13] = 0;
52+
info[14] = 0;
53+
info[15] = 0;
54+
55+
poly1305(info, 16, nil, 0, tag, ds);
56+
}
57+
58+
void
59+
ccpoly_encrypt(uchar *dat, ulong ndat, uchar *aad, ulong naad, uchar tag[16], Chachastate *cs)
60+
{
61+
DigestState ds;
62+
63+
ccpolyotk(cs, &ds);
64+
ccpolymac(aad, naad, &ds);
65+
chacha_encrypt(dat, ndat, cs);
66+
ccpolymac(dat, ndat, &ds);
67+
ccpolytag(ndat, naad, tag, &ds);
68+
}
69+
70+
int
71+
ccpoly_decrypt(uchar *dat, ulong ndat, uchar *aad, ulong naad, uchar tag[16], Chachastate *cs)
72+
{
73+
DigestState ds;
74+
uchar tmp[16];
75+
76+
ccpolyotk(cs, &ds);
77+
ccpolymac(aad, naad, &ds);
78+
ccpolymac(dat, ndat, &ds);
79+
ccpolytag(ndat, naad, tmp, &ds);
80+
if(tsmemcmp(tag, tmp, 16) != 0)
81+
return -1;
82+
chacha_encrypt(dat, ndat, cs);
83+
return 0;
84+
}

libsec/chacha.c

+17-5
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,12 @@ load(u32int *d, uchar *s, int nw)
5454
}
5555

5656
void
57-
setupChachastate(Chachastate *s, uchar *key, usize keylen, uchar *iv, int rounds)
57+
setupChachastate(Chachastate *s, uchar *key, usize keylen, uchar *iv, ulong ivlen, int rounds)
5858
{
5959
if(keylen != 256/8 && keylen != 128/8)
6060
sysfatal("invalid chacha key length");
61+
if(ivlen != 96/8 && ivlen != 64/8)
62+
sysfatal("invalid chacha iv length");
6163
if(rounds == 0)
6264
rounds = 20;
6365
s->rounds = rounds;
@@ -69,19 +71,28 @@ setupChachastate(Chachastate *s, uchar *key, usize keylen, uchar *iv, int rounds
6971
load(&s->input[4], key, 4);
7072
load(&s->input[8], key, 4);
7173
}
74+
s->ivwords = ivlen/sizeof(u32int);
7275
s->input[12] = 0;
76+
s->input[13] = 0;
7377
if(iv == nil){
74-
s->input[13] = 0;
7578
s->input[14] = 0;
7679
s->input[15] = 0;
7780
}else
78-
load(&s->input[13], iv, 3);
81+
chacha_setiv(s, iv);
7982
}
8083

8184
void
82-
chacha_setblock(Chachastate *s, u32int blockno)
85+
chacha_setiv(Chachastate *s, uchar *iv)
86+
{
87+
load(&s->input[16 - s->ivwords], iv, s->ivwords);
88+
}
89+
90+
void
91+
chacha_setblock(Chachastate *s, u64int blockno)
8392
{
8493
s->input[12] = blockno;
94+
if(s->ivwords == 2)
95+
s->input[13] = blockno>>32;
8596
}
8697

8798
static void
@@ -148,7 +159,8 @@ encryptblock(Chachastate *s, uchar *src, uchar *dst)
148159
}
149160
#endif
150161

151-
s->input[12]++;
162+
if(++s->input[12] == 0 && s->ivwords == 2)
163+
s->input[13]++;
152164
}
153165

154166
void

libsec/chachatest.c

+53-3
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ u32int rfccount = 1;
3131
char rfctext[] = "Ladies and Gentlemen of the class of '99: If I could offer you only one tip for the future, "
3232
"sunscreen would be it.";
3333
uchar rfcout[3*ChachaBsize];
34-
uchar rfcref[3*ChachaBsize] = {
34+
uchar rfcref[] = {
3535
0x6e, 0x2e, 0x35, 0x9a, 0x25, 0x68, 0xf9, 0x80, 0x41, 0xba, 0x07, 0x28, 0xdd, 0x0d, 0x69, 0x81,
3636
0xe9, 0x7e, 0x7a, 0xec, 0x1d, 0x43, 0x60, 0xc2, 0x0a, 0x27, 0xaf, 0xcc, 0xfd, 0x9f, 0xae, 0x0b,
3737
0xf9, 0x1b, 0x65, 0xc5, 0x52, 0x47, 0x33, 0xab, 0x8f, 0x59, 0x3d, 0xab, 0xcd, 0x62, 0xb3, 0x57,
@@ -42,10 +42,26 @@ uchar rfcref[3*ChachaBsize] = {
4242
0x87, 0x4d
4343
};
4444

45+
uchar ccpaad[] = {
46+
0x50, 0x51, 0x52, 0x53, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
47+
};
48+
uchar ccpkey[] = {
49+
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
50+
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
51+
};
52+
uchar ccpiv[] = {
53+
0x07, 0x00, 0x00, 0x00,
54+
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
55+
};
56+
uchar ccptag[] = {
57+
0x1a, 0xe1, 0x0b, 0x59, 0x4f, 0x09, 0xe2, 0x6a, 0x7e, 0x90, 0x2e, 0xcb, 0xd0, 0x60, 0x06, 0x91,
58+
};
59+
4560
void
4661
main(int argc, char **argv)
4762
{
4863
Chachastate s;
64+
uchar tag[16];
4965
int n;
5066

5167
ARGBEGIN{
@@ -54,17 +70,51 @@ main(int argc, char **argv)
5470
print("key:\n");
5571
printblock(rfckey, sizeof(rfckey));
5672
n = strlen(rfctext);
57-
setupChachastate(&s, rfckey, sizeof(rfckey), rfcnonce, 0);
73+
setupChachastate(&s, rfckey, sizeof(rfckey), rfcnonce, sizeof(rfcnonce), 0);
5874
chacha_setblock(&s, rfccount);
5975
print("rfc in:\n");
6076
printblock((uchar*)rfctext, n);
6177
chacha_encrypt2((uchar*)rfctext, rfcout, n, &s);
6278
print("rfc out:\n");
6379
printblock(rfcout, n);
64-
if(memcmp(rfcout, rfcref, sizeof(rfcout)) != 0){
80+
if(memcmp(rfcout, rfcref, sizeof(rfcref)) != 0){
6581
print("failure of vision\n");
6682
exits("wrong");
6783
}
84+
print("\n");
85+
86+
print("ccpoly key:\n");
87+
printblock(ccpkey, sizeof(ccpkey));
88+
89+
print("ccpoly iv:\n");
90+
printblock(ccpiv, sizeof(ccpiv));
91+
92+
setupChachastate(&s, ccpkey, sizeof(ccpkey), ccpiv, sizeof(ccpiv), 20);
93+
94+
memmove(rfcout, rfctext, sizeof(rfctext)-1);
95+
ccpoly_encrypt(rfcout, sizeof(rfctext)-1, ccpaad, sizeof(ccpaad), tag, &s);
96+
97+
print("ccpoly cipher:\n");
98+
printblock(rfcout, sizeof(rfctext)-1);
99+
100+
print("ccpoly tag:\n");
101+
printblock(tag, sizeof(tag));
102+
103+
if(memcmp(tag, ccptag, sizeof(tag)) != 0){
104+
print("bad ccpoly tag\n");
105+
exits("wrong");
106+
}
107+
108+
if(ccpoly_decrypt(rfcout, sizeof(rfctext)-1, ccpaad, sizeof(ccpaad), tag, &s) != 0){
109+
print("ccpoly decryption failed\n");
110+
exits("wrong");
111+
}
112+
113+
if(memcmp(rfcout, rfctext, sizeof(rfctext)-1) != 0){
114+
print("ccpoly bad decryption\n");
115+
exits("wrong");
116+
}
117+
68118
print("passed\n");
69119
exits(nil);
70120
}

libsec/tsmemcmp.c

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#include <u.h>
2+
#include <libc.h>
3+
#include <libsec.h>
4+
5+
/*
6+
* timing safe memcmp()
7+
*/
8+
int
9+
tsmemcmp(void *a1, void *a2, ulong n)
10+
{
11+
int lt, gt, c1, c2, r, m;
12+
uchar *s1, *s2;
13+
14+
r = m = 0;
15+
s1 = a1;
16+
s2 = a2;
17+
while(n--){
18+
c1 = *s1++;
19+
c2 = *s2++;
20+
lt = (c1 - c2) >> 8;
21+
gt = (c2 - c1) >> 8;
22+
r |= (lt - gt) & ~m;
23+
m |= lt | gt;
24+
}
25+
return r;
26+
}

0 commit comments

Comments
 (0)