Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

libsec: pbkdf2, hkdf_x(), poly1305, chacha20 poly1305 aead, allow 64 bit iv's for chacha, tsmemcmp() #22

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 22 additions & 3 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 @@ -183,6 +188,7 @@ enum
MD4dlen= 16, /* MD4 digest length */
MD5dlen= 16, /* MD5 digest length */
AESdlen= 16, /* TODO: see rfc */
Poly1305dlen= 16, /* Poly1305 digest length */

Hmacblksz = 64, /* in bytes; from rfc2104 */
};
Expand All @@ -192,7 +198,7 @@ struct DigestState
{
uvlong len;
union {
u32int state[8];
u32int state[16];
u64int bstate[8];
};
uchar buf[256];
Expand Down Expand Up @@ -234,6 +240,8 @@ MD5state* md5unpickle(char*);
char* sha1pickle(SHA1state*);
SHA1state* sha1unpickle(char*);

DigestState* poly1305(uchar*, ulong, uchar*, ulong, uchar*, DigestState*);

/*
* random number generation
*/
Expand Down Expand Up @@ -440,3 +448,14 @@ int okThumbprint(uchar *sha1, Thumbprint *ok);
/* readcert.c */
uchar *readcert(char *filename, int *pcertlen);
PEMChain*readcertchain(char *filename);

/* password-based key derivation function 2 (rfc2898) */
void pbkdf2_x(uchar *p, ulong plen, uchar *s, ulong slen, ulong rounds, uchar *d, ulong dlen,
DigestState* (*x)(uchar*, ulong, uchar*, ulong, uchar*, DigestState*), int xlen);

/* 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);
5 changes: 5 additions & 0 deletions libsec/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ OFILES=\
sha2_128.$O\
sha2block128.$O\
smallprimes.$O\
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);
}
36 changes: 36 additions & 0 deletions libsec/hkdf.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#include "os.h"
#include <libsec.h>

/* 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)
{
uchar prk[256], tmp[256], cnt;
DigestState *ds;

assert(xlen <= sizeof(tmp));

memset(tmp, 0, xlen);
if(nsalt == 0){
salt = tmp;
nsalt = xlen;
}
/* note that salt and key are swapped in this case */
(*x)(key, nkey, salt, nsalt, prk, nil);
ds = nil;
for(cnt=1;; cnt++) {
if(ninfo > 0)
ds = (*x)(info, ninfo, prk, xlen, nil, ds);
(*x)(&cnt, 1, prk, xlen, tmp, ds);
if(dlen <= xlen){
memmove(d, tmp, dlen);
break;
}
memmove(d, tmp, xlen);
dlen -= xlen;
d += xlen;
ds = (*x)(tmp, xlen, prk, xlen, nil, nil);
}
}
34 changes: 34 additions & 0 deletions libsec/pbkdf2.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#include "os.h"
#include <libsec.h>

/* rfc2898 */
void
pbkdf2_x(p, plen, s, slen, rounds, d, dlen, x, xlen)
uchar *p, *s, *d;
ulong plen, slen, dlen, rounds;
DigestState* (*x)(uchar*, ulong, uchar*, ulong, uchar*, DigestState*);
int xlen;
{
uchar block[256], tmp[256];
ulong i, j, k, n;
DigestState *ds;

assert(xlen <= sizeof(tmp));

for(i = 1; dlen > 0; i++, d += n, dlen -= n){
tmp[3] = i;
tmp[2] = i >> 8;
tmp[1] = i >> 16;
tmp[0] = i >> 24;
ds = (*x)(s, slen, p, plen, nil, nil);
(*x)(tmp, 4, p, plen, block, ds);
memmove(tmp, block, xlen);
for(j = 1; j < rounds; j++){
(*x)(tmp, xlen, p, plen, tmp, nil);
for(k=0; k<xlen; k++)
block[k] ^= tmp[k];
}
n = dlen > xlen ? xlen : dlen;
memmove(d, block, n);
}
}
Loading
Loading