Skip to content

Commit

Permalink
libsec: add chacha20 poly1305 aead, allow 64 bit iv's for chacha,
Browse files Browse the repository at this point in the history
  • Loading branch information
adriangrigore committed Jul 30, 2024
1 parent 9fa547e commit 33fb45b
Show file tree
Hide file tree
Showing 6 changed files with 192 additions and 10 deletions.
12 changes: 10 additions & 2 deletions include/libsec.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,13 +104,18 @@ struct Chachastate
};
};
int rounds;
int ivwords;
};

void setupChachastate(Chachastate*, uchar*, usize, uchar*, int);
void chacha_setblock(Chachastate*, u32int);
void setupChachastate(Chachastate*, uchar*, usize, uchar*, ulong, int);
void chacha_setiv(Chachastate *, uchar*);
void chacha_setblock(Chachastate*, u64int);
void chacha_encrypt(uchar*, usize, Chachastate*);
void chacha_encrypt2(uchar*, uchar*, usize, Chachastate*);

void ccpoly_encrypt(uchar *dat, ulong ndat, uchar *aad, ulong naad, uchar tag[16], Chachastate *cs);
int ccpoly_decrypt(uchar *dat, ulong ndat, uchar *aad, ulong naad, uchar tag[16], Chachastate *cs);

/*
* DES definitions
*/
Expand Down Expand Up @@ -451,3 +456,6 @@ void pbkdf2_x(uchar *p, ulong plen, uchar *s, ulong slen, ulong rounds, uchar *d
/* hmac-based key derivation function (rfc5869) */
void hkdf_x(uchar *salt, ulong nsalt, uchar *info, ulong ninfo, uchar *key, ulong nkey, uchar *d, ulong dlen,
DigestState* (*x)(uchar*, ulong, uchar*, ulong, uchar*, DigestState*), int xlen);

/* timing safe memcmp() */
int tsmemcmp(void*, void*, ulong);
2 changes: 2 additions & 0 deletions libsec/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ OFILES=\
pbkdf2.$O\
hkdf.$O\
poly1305.$O\
ccpoly.$O\
tsmemcmp.$O\

default: $(LIB)
$(LIB): $(OFILES)
Expand Down
84 changes: 84 additions & 0 deletions libsec/ccpoly.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
#include <u.h>
#include <libc.h>
#include <libsec.h>

static void
ccpolyotk(Chachastate *cs, DigestState *ds)
{
uchar otk[ChachaBsize];

memset(ds, 0, sizeof(*ds));
memset(otk, 0, 32);
chacha_setblock(cs, 0);
chacha_encrypt(otk, ChachaBsize, cs);
poly1305(nil, 0, otk, 32, nil, ds);
}

static void
ccpolymac(uchar *buf, ulong nbuf, DigestState *ds)
{
static uchar zeros[16] = {0};
ulong npad;

if(nbuf == 0)
return;
poly1305(buf, nbuf, nil, 0, nil, ds);
npad = nbuf % 16;
if(npad == 0)
return;
poly1305(zeros, 16 - npad, nil, 0, nil, ds);
}

static void
ccpolytag(ulong ndat, ulong naad, uchar tag[16], DigestState *ds)
{
uchar info[16];

info[0] = naad;
info[1] = naad>>8;
info[2] = naad>>16;
info[3] = naad>>24;
info[4] = 0;
info[5] = 0;
info[6] = 0;
info[7] = 0;

info[8] = ndat;
info[9] = ndat>>8;
info[10] = ndat>>16;
info[11] = ndat>>24;
info[12] = 0;
info[13] = 0;
info[14] = 0;
info[15] = 0;

poly1305(info, 16, nil, 0, tag, ds);
}

void
ccpoly_encrypt(uchar *dat, ulong ndat, uchar *aad, ulong naad, uchar tag[16], Chachastate *cs)
{
DigestState ds;

ccpolyotk(cs, &ds);
ccpolymac(aad, naad, &ds);
chacha_encrypt(dat, ndat, cs);
ccpolymac(dat, ndat, &ds);
ccpolytag(ndat, naad, tag, &ds);
}

int
ccpoly_decrypt(uchar *dat, ulong ndat, uchar *aad, ulong naad, uchar tag[16], Chachastate *cs)
{
DigestState ds;
uchar tmp[16];

ccpolyotk(cs, &ds);
ccpolymac(aad, naad, &ds);
ccpolymac(dat, ndat, &ds);
ccpolytag(ndat, naad, tmp, &ds);
if(tsmemcmp(tag, tmp, 16) != 0)
return -1;
chacha_encrypt(dat, ndat, cs);
return 0;
}
22 changes: 17 additions & 5 deletions libsec/chacha.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,12 @@ load(u32int *d, uchar *s, int nw)
}

void
setupChachastate(Chachastate *s, uchar *key, usize keylen, uchar *iv, int rounds)
setupChachastate(Chachastate *s, uchar *key, usize keylen, uchar *iv, ulong ivlen, int rounds)
{
if(keylen != 256/8 && keylen != 128/8)
sysfatal("invalid chacha key length");
if(ivlen != 96/8 && ivlen != 64/8)
sysfatal("invalid chacha iv length");
if(rounds == 0)
rounds = 20;
s->rounds = rounds;
Expand All @@ -69,19 +71,28 @@ setupChachastate(Chachastate *s, uchar *key, usize keylen, uchar *iv, int rounds
load(&s->input[4], key, 4);
load(&s->input[8], key, 4);
}
s->ivwords = ivlen/sizeof(u32int);
s->input[12] = 0;
s->input[13] = 0;
if(iv == nil){
s->input[13] = 0;
s->input[14] = 0;
s->input[15] = 0;
}else
load(&s->input[13], iv, 3);
chacha_setiv(s, iv);
}

void
chacha_setblock(Chachastate *s, u32int blockno)
chacha_setiv(Chachastate *s, uchar *iv)
{
load(&s->input[16 - s->ivwords], iv, s->ivwords);
}

void
chacha_setblock(Chachastate *s, u64int blockno)
{
s->input[12] = blockno;
if(s->ivwords == 2)
s->input[13] = blockno>>32;
}

static void
Expand Down Expand Up @@ -148,7 +159,8 @@ encryptblock(Chachastate *s, uchar *src, uchar *dst)
}
#endif

s->input[12]++;
if(++s->input[12] == 0 && s->ivwords == 2)
s->input[13]++;
}

void
Expand Down
56 changes: 53 additions & 3 deletions libsec/chachatest.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ 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] = {
uchar rfcref[] = {
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,
Expand All @@ -42,10 +42,26 @@ uchar rfcref[3*ChachaBsize] = {
0x87, 0x4d
};

uchar ccpaad[] = {
0x50, 0x51, 0x52, 0x53, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
};
uchar ccpkey[] = {
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
};
uchar ccpiv[] = {
0x07, 0x00, 0x00, 0x00,
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
};
uchar ccptag[] = {
0x1a, 0xe1, 0x0b, 0x59, 0x4f, 0x09, 0xe2, 0x6a, 0x7e, 0x90, 0x2e, 0xcb, 0xd0, 0x60, 0x06, 0x91,
};

void
main(int argc, char **argv)
{
Chachastate s;
uchar tag[16];
int n;

ARGBEGIN{
Expand All @@ -54,17 +70,51 @@ main(int argc, char **argv)
print("key:\n");
printblock(rfckey, sizeof(rfckey));
n = strlen(rfctext);
setupChachastate(&s, rfckey, sizeof(rfckey), rfcnonce, 0);
setupChachastate(&s, rfckey, sizeof(rfckey), rfcnonce, sizeof(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){
if(memcmp(rfcout, rfcref, sizeof(rfcref)) != 0){
print("failure of vision\n");
exits("wrong");
}
print("\n");

print("ccpoly key:\n");
printblock(ccpkey, sizeof(ccpkey));

print("ccpoly iv:\n");
printblock(ccpiv, sizeof(ccpiv));

setupChachastate(&s, ccpkey, sizeof(ccpkey), ccpiv, sizeof(ccpiv), 20);

memmove(rfcout, rfctext, sizeof(rfctext)-1);
ccpoly_encrypt(rfcout, sizeof(rfctext)-1, ccpaad, sizeof(ccpaad), tag, &s);

print("ccpoly cipher:\n");
printblock(rfcout, sizeof(rfctext)-1);

print("ccpoly tag:\n");
printblock(tag, sizeof(tag));

if(memcmp(tag, ccptag, sizeof(tag)) != 0){
print("bad ccpoly tag\n");
exits("wrong");
}

if(ccpoly_decrypt(rfcout, sizeof(rfctext)-1, ccpaad, sizeof(ccpaad), tag, &s) != 0){
print("ccpoly decryption failed\n");
exits("wrong");
}

if(memcmp(rfcout, rfctext, sizeof(rfctext)-1) != 0){
print("ccpoly bad decryption\n");
exits("wrong");
}

print("passed\n");
exits(nil);
}
26 changes: 26 additions & 0 deletions libsec/tsmemcmp.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#include <u.h>
#include <libc.h>
#include <libsec.h>

/*
* timing safe memcmp()
*/
int
tsmemcmp(void *a1, void *a2, ulong n)
{
int lt, gt, c1, c2, r, m;
uchar *s1, *s2;

r = m = 0;
s1 = a1;
s2 = a2;
while(n--){
c1 = *s1++;
c2 = *s2++;
lt = (c1 - c2) >> 8;
gt = (c2 - c1) >> 8;
r |= (lt - gt) & ~m;
m |= lt | gt;
}
return r;
}

0 comments on commit 33fb45b

Please sign in to comment.