From 8a73650874a68575fb7b93a44f3bba352c50288a Mon Sep 17 00:00:00 2001 From: cinap_lenrek Date: Sat, 27 Aug 2016 20:23:55 +0200 Subject: [PATCH 1/9] libc: add poolisoverlap() and definitions for Pool *secrmem --- sys/include/pool.h | 2 ++ sys/man/2/pool | 12 +++++++++++- sys/src/libc/port/pool.c | 13 +++++++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/sys/include/pool.h b/sys/include/pool.h index 571373e9f..5f7fada45 100644 --- a/sys/include/pool.h +++ b/sys/include/pool.h @@ -35,6 +35,7 @@ extern void* poolalloc(Pool*, ulong); extern void* poolallocalign(Pool*, ulong, ulong, long, ulong); extern void poolfree(Pool*, void*); extern ulong poolmsize(Pool*, void*); +extern int poolisoverlap(Pool*, void*, ulong); extern void* poolrealloc(Pool*, void*, ulong); extern void poolcheck(Pool*); extern int poolcompact(Pool*); @@ -43,6 +44,7 @@ extern void pooldump(Pool*); extern Pool* mainmem; extern Pool* imagmem; +extern Pool* secrmem; enum { /* flags */ POOL_ANTAGONISM = 1<<0, diff --git a/sys/man/2/pool b/sys/man/2/pool index a44b57d4d..b637e3d7c 100644 --- a/sys/man/2/pool +++ b/sys/man/2/pool @@ -1,6 +1,6 @@ .TH POOL 2 .SH NAME -poolalloc, poolallocalign, poolfree, poolmsize, poolrealloc, poolcompact, poolcheck, poolblockcheck, +poolalloc, poolallocalign, poolfree, poolmsize, poolisoverlap, poolrealloc, poolcompact, poolcheck, poolblockcheck, pooldump \- general memory management routines .SH SYNOPSIS .B #include @@ -25,6 +25,9 @@ void poolfree(Pool* pool, void* ptr) ulong poolmsize(Pool* pool, void* ptr) .PP .B +int poolisoverlap(Pool* pool, void* ptr, ulong len) +.PP +.B void* poolrealloc(Pool* pool, void* ptr, ulong size) .PP .B @@ -109,6 +112,13 @@ that would usually go unused. .IR Poolmsize grows the block to encompass this extra space and returns the new size. .PP +.I Poolisoverlap +checks if the byte span +.BR [ptr , ptr + len) +overlaps the arenas of the specified +.BR pool , +returning non-zero when there is overlap or zero if none. +.PP The .I poolblockcheck and diff --git a/sys/src/libc/port/pool.c b/sys/src/libc/port/pool.c index 25ad52c57..546d5776a 100644 --- a/sys/src/libc/port/pool.c +++ b/sys/src/libc/port/pool.c @@ -1332,6 +1332,19 @@ poolmsize(Pool *p, void *v) return dsize; } +int +poolisoverlap(Pool *p, void *v, ulong n) +{ + Arena *a; + + p->lock(p); + for(a = p->arenalist; a != nil; a = a->down) + if((uchar*)v+n > (uchar*)a && (uchar*)v < (uchar*)a+a->asize) + break; + p->unlock(p); + return a != nil; +} + /* * Debugging */ From 0f97eb3a609cd892a0de1d61ef61e5b48be082d8 Mon Sep 17 00:00:00 2001 From: cinap_lenrek Date: Sat, 27 Aug 2016 20:33:03 +0200 Subject: [PATCH 2/9] kernel: add secalloc() and secfree() functions for secret memory allocation The kernel needs to keep cryptographic keys and cipher states confidential. secalloc() allocates memory from the secret pool which is protected from debuggers reading the memory thru devproc. secfree() releases the memory, overriding the data with garbage. --- sys/src/9/port/alloc.c | 55 ++++++++++++++++++++++++++++++++++++---- sys/src/9/port/devproc.c | 4 ++- sys/src/9/port/portfns.h | 2 ++ 3 files changed, 55 insertions(+), 6 deletions(-) diff --git a/sys/src/9/port/alloc.c b/sys/src/9/port/alloc.c index fc562bc55..963d60fd2 100644 --- a/sys/src/9/port/alloc.c +++ b/sys/src/9/port/alloc.c @@ -53,8 +53,27 @@ static Pool pimagmem = { .private= &pimagpriv, }; +static Private psecrpriv; +static Pool psecrmem = { + .name= "Secrets", + .maxsize= 16*1024*1024, + .minarena= 64*1024, + .quantum= 32, + .alloc= xalloc, + .merge= xmerge, + .flags= POOL_ANTAGONISM, + + .lock= plock, + .unlock= punlock, + .print= poolprint, + .panic= ppanic, + + .private= &psecrpriv, +}; + Pool* mainmem = &pmainmem; Pool* imagmem = &pimagmem; +Pool* secrmem = &psecrmem; /* * because we can't print while we're holding the locks, @@ -129,6 +148,7 @@ mallocsummary(void) { poolsummary(mainmem); poolsummary(imagmem); + poolsummary(secrmem); } /* everything from here down should be the same in libc, libdebugmalloc, and the kernel */ @@ -171,12 +191,9 @@ smalloc(ulong size) { void *v; - for(;;) { - v = poolalloc(mainmem, size+Npadlong*sizeof(ulong)); - if(v != nil) - break; + while((v = poolalloc(mainmem, size+Npadlong*sizeof(ulong))) == nil){ if(!waserror()){ - resrcwait(0); + resrcwait(nil); poperror(); } } @@ -278,6 +295,34 @@ calloc(ulong n, ulong szelem) return v; } +/* secret memory, used to back cryptographic keys and cipher states */ +void* +secalloc(ulong size) +{ + void *v; + + while((v = poolalloc(secrmem, size+Npadlong*sizeof(ulong))) == nil){ + if(!waserror()){ + resrcwait(nil); + poperror(); + } + } + if(Npadlong){ + v = (ulong*)v+Npadlong; + setmalloctag(v, getcallerpc(&size)); + setrealloctag(v, 0); + } + memset(v, 0, size); + return v; +} + +void +secfree(void *v) +{ + if(v != nil) + poolfree(secrmem, (ulong*)v-Npadlong); +} + void setmalloctag(void *v, uintptr pc) { diff --git a/sys/src/9/port/devproc.c b/sys/src/9/port/devproc.c index 49340adbb..9f9b9380b 100644 --- a/sys/src/9/port/devproc.c +++ b/sys/src/9/port/devproc.c @@ -9,6 +9,8 @@ #include "ureg.h" #include "edf.h" +#include + enum { Qdir, @@ -789,7 +791,7 @@ procread(Chan *c, void *va, long n, vlong off) if(addr < KZERO) return procctlmemio(c, p, addr, va, n, 1); - if(!iseve()) + if(!iseve() || poolisoverlap(secrmem, (uchar*)addr, n)) error(Eperm); /* validate kernel addresses */ diff --git a/sys/src/9/port/portfns.h b/sys/src/9/port/portfns.h index 4b639c3a1..bd0c6f16c 100644 --- a/sys/src/9/port/portfns.h +++ b/sys/src/9/port/portfns.h @@ -308,6 +308,8 @@ void sched(void); void scheddump(void); void schedinit(void); void (*screenputs)(char*, int); +void* secalloc(ulong); +void secfree(void*); long seconds(void); uintptr segattach(int, char *, uintptr, uintptr); void segclock(uintptr); From 0b8851ddb688e8de813196b7cd62f113edde2e3a Mon Sep 17 00:00:00 2001 From: cinap_lenrek Date: Sat, 27 Aug 2016 20:35:39 +0200 Subject: [PATCH 3/9] wifi: allocate cipher states in secret memory, do AESstate key setup once --- sys/src/9/pc/wifi.c | 154 +++++++++++++++++++++++++++++--------------- 1 file changed, 103 insertions(+), 51 deletions(-) diff --git a/sys/src/9/pc/wifi.c b/sys/src/9/pc/wifi.c index 8155b25e3..8325c0aa7 100644 --- a/sys/src/9/pc/wifi.c +++ b/sys/src/9/pc/wifi.c @@ -48,6 +48,7 @@ static uchar basicrates[] = { static Block* wifidecrypt(Wifi *, Wnode *, Block *); static Block* wifiencrypt(Wifi *, Wnode *, Block *); +static void freewifikeys(Wifi *, Wnode *); static uchar* srcaddr(Wifipkt *w) @@ -197,6 +198,7 @@ nodelookup(Wifi *wifi, uchar *bssid, int new) } if(!new) return nil; + freewifikeys(wifi, nn); memset(nn, 0, sizeof(Wnode)); memmove(nn->bssid, bssid, Eaddrlen); nn->lastseen = MACHP(0)->ticks; @@ -465,6 +467,23 @@ recvbeacon(Wifi *wifi, Wnode *wn, uchar *d, int len) } } +static void +freewifikeys(Wifi *wifi, Wnode *wn) +{ + int i; + + wlock(&wifi->crypt); + for(i=0; irxkey); i++){ + secfree(wn->rxkey[i]); + wn->rxkey[i] = nil; + } + for(i=0; itxkey); i++){ + secfree(wn->txkey[i]); + wn->txkey[i] = nil; + } + wunlock(&wifi->crypt); +} + static void wifideauth(Wifi *wifi, Wnode *wn) { @@ -474,8 +493,7 @@ wifideauth(Wifi *wifi, Wnode *wn) /* deassociate node, clear keys */ setstatus(wifi, wn, Sunauth); - memset(wn->rxkey, 0, sizeof(wn->rxkey)); - memset(wn->txkey, 0, sizeof(wn->txkey)); + freewifikeys(wifi, wn); wn->aid = 0; if(wn == wifi->bss){ @@ -789,11 +807,13 @@ static char *ciphers[] = { [CCMP] "ccmp", }; -static int -parsekey(Wkey *k, char *s) +static Wkey* +parsekey(char *s) { char buf[256], *p; - int i; + uchar key[32]; + int i, n; + Wkey *k; strncpy(buf, s, sizeof(buf)-1); buf[sizeof(buf)-1] = 0; @@ -801,20 +821,35 @@ parsekey(Wkey *k, char *s) *p++ = 0; else p = buf; - for(i=0; ikey, key, n); + break; + case CCMP: + if(n != 16) + return nil; + k = secalloc(sizeof(Wkey) + sizeof(AESstate)); + setupAESstate((AESstate*)k->key, key, n, nil); + break; + default: + return nil; } - if(i >= nelem(ciphers)) - return -1; - memset(k, 0, sizeof(Wkey)); - k->len = hextob(p, &p, k->key, sizeof(k->key)); + memset(key, 0, sizeof(key)); if(*p == '@') k->tsc = strtoull(++p, nil, 16); + k->len = n; k->cipher = i; - return 0; + return k; } void @@ -874,7 +909,7 @@ wifictl(Wifi *wifi, void *buf, long n) Cmdbuf *cb; Cmdtab *ct; Wnode *wn; - Wkey *k; + Wkey *k, **kk; cb = nil; if(waserror()){ @@ -931,8 +966,7 @@ wifictl(Wifi *wifi, void *buf, long n) memmove(wifi->bssid, addr, Eaddrlen); goto Findbss; case CMauth: - memset(wn->rxkey, 0, sizeof(wn->rxkey)); - memset(wn->txkey, 0, sizeof(wn->txkey)); + freewifikeys(wifi, wn); if(cb->f[1] == nil) wn->rsnelen = 0; else @@ -947,12 +981,24 @@ wifictl(Wifi *wifi, void *buf, long n) break; case CMrxkey0: case CMrxkey1: case CMrxkey2: case CMrxkey3: case CMrxkey4: case CMtxkey0: - if(ct->index < CMtxkey0) - k = &wn->rxkey[ct->index - CMrxkey0]; - else - k = &wn->txkey[ct->index - CMtxkey0]; - if(cb->f[1] == nil || parsekey(k, cb->f[1]) != 0) + if(cb->f[1] == nil) + error(Ebadarg); + k = parsekey(cb->f[1]); + if(k == nil) error("bad key"); + memset(cb->f[1], 0, strlen(cb->f[1])); + if(k->cipher == 0){ + secfree(k); + k = nil; + } + if(ct->index < CMtxkey0) + kk = &wn->rxkey[ct->index - CMrxkey0]; + else + kk = &wn->txkey[ct->index - CMtxkey0]; + wlock(&wifi->crypt); + secfree(*kk); + *kk = k; + wunlock(&wifi->crypt); if(ct->index >= CMtxkey0 && wn->status == Sblocked) setstatus(wifi, wn, Sassoc); break; @@ -968,6 +1014,7 @@ wifistat(Wifi *wifi, void *buf, long n, ulong off) static uchar zeros[Eaddrlen]; char *s, *p, *e; Wnode *wn; + Wkey *k; long now; int i; @@ -982,12 +1029,18 @@ wifistat(Wifi *wifi, void *buf, long n, ulong off) p = seprint(p, e, "channel: %.2d\n", wn->channel); /* only print key ciphers and key length */ - for(i = 0; irxkey); i++) - p = seprint(p, e, "rxkey%d: %s:[%d]\n", i, - ciphers[wn->rxkey[i].cipher], wn->rxkey[i].len); - for(i = 0; itxkey); i++) - p = seprint(p, e, "txkey%d: %s:[%d]\n", i, - ciphers[wn->txkey[i].cipher], wn->txkey[i].len); + rlock(&wifi->crypt); + for(i = 0; irxkey); i++){ + if((k = wn->rxkey[i]) != nil) + p = seprint(p, e, "rxkey%d: %s:[%d]\n", i, + ciphers[k->cipher], k->len); + } + for(i = 0; itxkey); i++){ + if((k = wn->txkey[i]) != nil) + p = seprint(p, e, "txkey%d: %s:[%d]\n", i, + ciphers[k->cipher], k->len); + } + runlock(&wifi->crypt); if(wn->brsnelen > 0){ p = seprint(p, e, "brsne: "); @@ -1018,17 +1071,21 @@ static void ccmpencrypt(Wkey *k, Wifipkt *w, Block *b, uvlong tsc); static int ccmpdecrypt(Wkey *k, Wifipkt *w, Block *b, uvlong tsc); static Block* -wifiencrypt(Wifi *, Wnode *wn, Block *b) +wifiencrypt(Wifi *wifi, Wnode *wn, Block *b) { uvlong tsc; int n, kid; Wifipkt *w; Wkey *k; + rlock(&wifi->crypt); + kid = 0; - k = &wn->txkey[kid]; - if(k->cipher == 0) + k = wn->txkey[kid]; + if(k == nil){ + runlock(&wifi->crypt); return b; + } n = wifihdrlen((Wifipkt*)b->rp); @@ -1052,8 +1109,6 @@ wifiencrypt(Wifi *, Wnode *wn, Block *b) b->rp[6] = tsc>>32; b->rp[7] = tsc>>40; b->rp += 8; - if(k->len != 32) - goto drop; tkipencrypt(k, w, b, tsc); break; case CCMP: @@ -1066,15 +1121,10 @@ wifiencrypt(Wifi *, Wnode *wn, Block *b) b->rp[6] = tsc>>32; b->rp[7] = tsc>>40; b->rp += 8; - if(k->len != 16) - goto drop; ccmpencrypt(k, w, b, tsc); break; - default: - drop: - free(b); - return nil; } + runlock(&wifi->crypt); b->rp = (uchar*)w; w->fc[1] |= 0x40; @@ -1082,13 +1132,15 @@ wifiencrypt(Wifi *, Wnode *wn, Block *b) } static Block* -wifidecrypt(Wifi *, Wnode *wn, Block *b) +wifidecrypt(Wifi *wifi, Wnode *wn, Block *b) { uvlong tsc; int n, kid; Wifipkt *w; Wkey *k; + rlock(&wifi->crypt); + w = (Wifipkt*)b->rp; n = wifihdrlen(w); b->rp += n; @@ -1101,7 +1153,9 @@ wifidecrypt(Wifi *, Wnode *wn, Block *b) if((w->a1[0] & 1) == 0) kid = 4; /* use peerwise key for non-unicast */ - k = &wn->rxkey[kid]; + k = wn->rxkey[kid]; + if(k == nil) + goto drop; switch(k->cipher){ case TKIP: tsc = (uvlong)b->rp[7]<<40 | @@ -1111,7 +1165,7 @@ wifidecrypt(Wifi *, Wnode *wn, Block *b) (uvlong)b->rp[0]<<8 | (uvlong)b->rp[2]; b->rp += 8; - if(tsc <= k->tsc || k->len != 32) + if(tsc <= k->tsc) goto drop; if(tkipdecrypt(k, w, b, tsc) != 0) goto drop; @@ -1124,16 +1178,18 @@ wifidecrypt(Wifi *, Wnode *wn, Block *b) (uvlong)b->rp[1]<<8 | (uvlong)b->rp[0]; b->rp += 8; - if(tsc <= k->tsc || k->len != 16) + if(tsc <= k->tsc) goto drop; if(ccmpdecrypt(k, w, b, tsc) != 0) goto drop; break; default: drop: + runlock(&wifi->crypt); freeb(b); return nil; } + runlock(&wifi->crypt); k->tsc = tsc; b->rp -= n; @@ -1564,12 +1620,10 @@ aesCCMdecrypt(int L, int M, uchar *N /* N[15-L] */, } static int -setupCCMP(Wkey *k, Wifipkt *w, uvlong tsc, uchar nonce[13], uchar auth[32], AESstate *as) +setupCCMP(Wifipkt *w, uvlong tsc, uchar nonce[13], uchar auth[32]) { uchar *p; - setupAESstate(as, k->key, k->len, nil); - nonce[0] = ((w->fc[0] & 0x0c) == 0x00) << 4; memmove(&nonce[1], w->a2, Eaddrlen); nonce[7] = tsc >> 40; @@ -1599,11 +1653,10 @@ static void ccmpencrypt(Wkey *k, Wifipkt *w, Block *b, uvlong tsc) { uchar auth[32], nonce[13]; - AESstate as; aesCCMencrypt(2, 8, nonce, auth, - setupCCMP(k, w, tsc, nonce, auth, &as), - b->rp, BLEN(b), &as); + setupCCMP(w, tsc, nonce, auth), + b->rp, BLEN(b), (AESstate*)k->key); b->wp += 8; } @@ -1611,13 +1664,12 @@ static int ccmpdecrypt(Wkey *k, Wifipkt *w, Block *b, uvlong tsc) { uchar auth[32], nonce[13]; - AESstate as; if(BLEN(b) < 8) return -1; b->wp -= 8; return aesCCMdecrypt(2, 8, nonce, auth, - setupCCMP(k, w, tsc, nonce, auth, &as), - b->rp, BLEN(b), &as); + setupCCMP(w, tsc, nonce, auth), + b->rp, BLEN(b), (AESstate*)k->key); } From 0ac260b18a9a41ba944e6dadec5d15c058af23fd Mon Sep 17 00:00:00 2001 From: cinap_lenrek Date: Sat, 27 Aug 2016 20:36:08 +0200 Subject: [PATCH 4/9] wifi: update wifi.h header --- sys/src/9/pc/wifi.h | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/sys/src/9/pc/wifi.h b/sys/src/9/pc/wifi.h index bca2e07e9..2171afd21 100644 --- a/sys/src/9/pc/wifi.h +++ b/sys/src/9/pc/wifi.h @@ -15,10 +15,10 @@ enum { struct Wkey { - int cipher; - int len; - uchar key[32]; - uvlong tsc; + int cipher; + int len; + uvlong tsc; + uchar key[]; }; struct Wnode @@ -30,8 +30,8 @@ struct Wnode int rsnelen; uchar rsne[258]; - Wkey txkey[1]; - Wkey rxkey[5]; + Wkey *txkey[1]; + Wkey *rxkey[5]; int aid; /* association id */ ulong lastsend; @@ -58,6 +58,7 @@ struct Wifi int debug; + RWlock crypt; Queue *iq; ulong watchdog; ulong lastauth; From 7250c438bb124f76aa006dad47b5a3b8f277d1b7 Mon Sep 17 00:00:00 2001 From: cinap_lenrek Date: Sat, 27 Aug 2016 20:37:14 +0200 Subject: [PATCH 5/9] devssl: allocate cipher states in secret memory --- sys/src/9/port/devssl.c | 82 +++++++++++------------------------------ 1 file changed, 22 insertions(+), 60 deletions(-) diff --git a/sys/src/9/port/devssl.c b/sys/src/9/port/devssl.c index 32b207618..ef3cd6fb6 100644 --- a/sys/src/9/port/devssl.c +++ b/sys/src/9/port/devssl.c @@ -373,14 +373,10 @@ sslclose(Chan *c) sslhangup(s); if(s->c) cclose(s->c); - if(s->in.secret) - free(s->in.secret); - if(s->out.secret) - free(s->out.secret); - if(s->in.state) - free(s->in.state); - if(s->out.state) - free(s->out.state); + secfree(s->in.secret); + secfree(s->out.secret); + secfree(s->in.state); + secfree(s->out.state); free(s); } @@ -826,10 +822,8 @@ sslput(Dstate *s, Block * volatile b) static void setsecret(OneWay *w, uchar *secret, int n) { - if(w->secret) - free(w->secret); - - w->secret = smalloc(n); + secfree(w->secret); + w->secret = secalloc(n); memmove(w->secret, secret, n); w->slen = n; } @@ -837,12 +831,8 @@ setsecret(OneWay *w, uchar *secret, int n) static void initDESkey(OneWay *w) { - if(w->state){ - free(w->state); - w->state = 0; - } - - w->state = smalloc(sizeof(DESstate)); + secfree(w->state); + w->state = secalloc(sizeof(DESstate)); if(w->slen >= 16) setupDESstate(w->state, w->secret, w->secret+8); else if(w->slen >= 8) @@ -860,11 +850,6 @@ initDESkey_40(OneWay *w) { uchar key[8]; - if(w->state){ - free(w->state); - w->state = 0; - } - if(w->slen >= 8){ memmove(key, w->secret, 8); key[0] &= 0x0f; @@ -872,25 +857,14 @@ initDESkey_40(OneWay *w) key[4] &= 0x0f; key[6] &= 0x0f; } - - w->state = smalloc(sizeof(DESstate)); - if(w->slen >= 16) - setupDESstate(w->state, key, w->secret+8); - else if(w->slen >= 8) - setupDESstate(w->state, key, 0); - else - error("secret too short"); + initDESkey(w); } static void initRC4key(OneWay *w) { - if(w->state){ - free(w->state); - w->state = 0; - } - - w->state = smalloc(sizeof(RC4state)); + secfree(w->state); + w->state = secalloc(sizeof(RC4state)); setupRC4state(w->state, w->secret, w->slen); } @@ -901,16 +875,9 @@ initRC4key(OneWay *w) static void initRC4key_40(OneWay *w) { - if(w->state){ - free(w->state); - w->state = 0; - } - if(w->slen > 5) w->slen = 5; - - w->state = smalloc(sizeof(RC4state)); - setupRC4state(w->state, w->secret, w->slen); + initRC4key(w); } /* @@ -920,16 +887,9 @@ initRC4key_40(OneWay *w) static void initRC4key_128(OneWay *w) { - if(w->state){ - free(w->state); - w->state = 0; - } - if(w->slen > 16) w->slen = 16; - - w->state = smalloc(sizeof(RC4state)); - setupRC4state(w->state, w->secret, w->slen); + initRC4key(w); } @@ -1177,27 +1137,29 @@ sslwrite(Chan *c, void *a, long n, vlong) break; case Csin: p = cb->f[1]; - m = (strlen(p)*3)/2; - x = smalloc(m); + m = (strlen(p)*3)/2 + 1; + x = secalloc(m); t = dec64(x, m, p, strlen(p)); + memset(p, 0, strlen(p)); if(t <= 0){ - free(x); + secfree(x); error(Ebadarg); } setsecret(&s->in, x, t); - free(x); + secfree(x); break; case Csout: p = cb->f[1]; m = (strlen(p)*3)/2 + 1; - x = smalloc(m); + x = secalloc(m); t = dec64(x, m, p, strlen(p)); + memset(p, 0, strlen(p)); if(t <= 0){ - free(x); + secfree(x); error(Ebadarg); } setsecret(&s->out, x, t); - free(x); + secfree(x); break; } poperror(); From 2967f942ea0a9239ea316dd97b52f9cf2c2bfd6b Mon Sep 17 00:00:00 2001 From: cinap_lenrek Date: Sat, 27 Aug 2016 20:37:31 +0200 Subject: [PATCH 6/9] devtls: allocate cipher states in secret memory --- sys/src/9/port/devtls.c | 38 ++++++++++++++++++-------------------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/sys/src/9/port/devtls.c b/sys/src/9/port/devtls.c index 81f50d3a6..3f864a7fc 100644 --- a/sys/src/9/port/devtls.c +++ b/sys/src/9/port/devtls.c @@ -1471,7 +1471,7 @@ struct Encalg static void initRC4key(Encalg *ea, Secret *s, uchar *p, uchar *) { - s->enckey = smalloc(sizeof(RC4state)); + s->enckey = secalloc(sizeof(RC4state)); s->enc = rc4enc; s->dec = rc4enc; setupRC4state(s->enckey, p, ea->keylen); @@ -1480,7 +1480,7 @@ initRC4key(Encalg *ea, Secret *s, uchar *p, uchar *) static void initDES3key(Encalg *, Secret *s, uchar *p, uchar *iv) { - s->enckey = smalloc(sizeof(DES3state)); + s->enckey = secalloc(sizeof(DES3state)); s->enc = des3enc; s->dec = des3dec; s->block = 8; @@ -1490,7 +1490,7 @@ initDES3key(Encalg *, Secret *s, uchar *p, uchar *iv) static void initAESkey(Encalg *ea, Secret *s, uchar *p, uchar *iv) { - s->enckey = smalloc(sizeof(AESstate)); + s->enckey = secalloc(sizeof(AESstate)); s->enc = aesenc; s->dec = aesdec; s->block = 16; @@ -1500,7 +1500,7 @@ initAESkey(Encalg *ea, Secret *s, uchar *p, uchar *iv) static void initccpolykey(Encalg *ea, Secret *s, uchar *p, uchar *iv) { - s->enckey = smalloc(sizeof(Chachastate)); + s->enckey = secalloc(sizeof(Chachastate)); s->aead_enc = ccpoly_aead_enc; s->aead_dec = ccpoly_aead_dec; s->maclen = Poly1305dlen; @@ -1517,7 +1517,7 @@ initccpolykey(Encalg *ea, Secret *s, uchar *p, uchar *iv) static void initaesgcmkey(Encalg *ea, Secret *s, uchar *p, uchar *iv) { - s->enckey = smalloc(sizeof(AESGCMstate)); + s->enckey = secalloc(sizeof(AESGCMstate)); s->aead_enc = aesgcm_aead_enc; s->aead_dec = aesgcm_aead_dec; s->maclen = 16; @@ -1673,18 +1673,19 @@ tlswrite(Chan *c, void *a, long n, vlong off) ea = parseencalg(cb->f[2]); p = cb->f[4]; - m = (strlen(p)*3)/2; - x = smalloc(m); - tos = smalloc(sizeof(Secret)); - toc = smalloc(sizeof(Secret)); + m = (strlen(p)*3)/2 + 1; + x = secalloc(m); + tos = secalloc(sizeof(Secret)); + toc = secalloc(sizeof(Secret)); if(waserror()){ + secfree(x); freeSec(tos); freeSec(toc); - free(x); nexterror(); } m = dec64(x, m, p, strlen(p)); + memset(p, 0, strlen(p)); if(m < 2 * ha->maclen + 2 * ea->keylen + 2 * ea->ivlen) error("not enough secret data provided"); @@ -1719,7 +1720,7 @@ tlswrite(Chan *c, void *a, long n, vlong off) tos->encalg = ea->name; tos->hashalg = ha->name; - free(x); + secfree(x); poperror(); }else if(strcmp(cb->f[0], "changecipher") == 0){ if(cb->nf != 1) @@ -2048,17 +2049,10 @@ tlsstate(int s) static void freeSec(Secret *s) { - void *k; - if(s == nil) return; - k = s->enckey; - if(k != nil){ - memset(k, 0, msize(k)); - free(k); - } - memset(s, 0, sizeof(*s)); - free(s); + secfree(s->enckey); + secfree(s); } static int @@ -2162,6 +2156,8 @@ ccpoly_aead_setiv(Secret *sec, uchar seq[8]) iv[i+(ChachaIVlen-8)] ^= seq[i]; chacha_setiv(cs, iv); + + memset(iv, 0, sizeof(iv)); } static int @@ -2196,6 +2192,7 @@ aesgcm_aead_enc(Secret *sec, uchar *aad, int aadlen, uchar *reciv, uchar *data, for(i=0; i<8; i++) iv[4+i] ^= aad[i]; memmove(reciv, iv+4, 8); aesgcm_setiv(sec->enckey, iv, 12); + memset(iv, 0, sizeof(iv)); aesgcm_encrypt(data, len, aad, aadlen, data+len, sec->enckey); return len + sec->maclen; } @@ -2211,6 +2208,7 @@ aesgcm_aead_dec(Secret *sec, uchar *aad, int aadlen, uchar *reciv, uchar *data, memmove(iv, sec->mackey, 4); memmove(iv+4, reciv, 8); aesgcm_setiv(sec->enckey, iv, 12); + memset(iv, 0, sizeof(iv)); if(aesgcm_decrypt(data, len, aad, aadlen, data+len, sec->enckey) != 0) return -1; return len; From 7f16c92762af7c602316ce26d482526e67df74cd Mon Sep 17 00:00:00 2001 From: cinap_lenrek Date: Sat, 27 Aug 2016 20:38:33 +0200 Subject: [PATCH 7/9] ip/esp: allocate cipher states in secret memory --- sys/src/9/ip/esp.c | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/sys/src/9/ip/esp.c b/sys/src/9/ip/esp.c index 75c48a1ff..1e93f6f75 100644 --- a/sys/src/9/ip/esp.c +++ b/sys/src/9/ip/esp.c @@ -261,8 +261,8 @@ espclose(Conv *c) ipmove(c->raddr, IPnoaddr); ecb = (Espcb*)c->ptcl; - free(ecb->espstate); - free(ecb->ahstate); + secfree(ecb->espstate); + secfree(ecb->ahstate); memset(ecb, 0, sizeof(Espcb)); } @@ -694,16 +694,16 @@ setalg(Espcb *ecb, char **f, int n, Algorithm *alg) return "non-hex character in key"; } /* collapse hex digits into complete bytes in reverse order in key */ - key = smalloc(nbyte); + key = secalloc(nbyte); for(i = 0; i < nchar && i/2 < nbyte; i++) { c = f[2][nchar-i-1]; if(i&1) c <<= 4; key[i/2] |= c; } - + memset(f[2], 0, nchar); alg->init(ecb, alg->name, key, alg->keylen); - free(key); + secfree(key); return nil; } @@ -791,7 +791,7 @@ shaahinit(Espcb *ecb, char *name, uchar *key, unsigned klen) ecb->ahblklen = 1; ecb->ahlen = BITS2BYTES(96); ecb->auth = shaauth; - ecb->ahstate = smalloc(klen); + ecb->ahstate = secalloc(klen); memmove(ecb->ahstate, key, klen); } @@ -853,8 +853,10 @@ aescbcespinit(Espcb *ecb, char *name, uchar *k, unsigned n) ecb->espblklen = Aesblk; ecb->espivlen = Aesblk; ecb->cipher = aescbccipher; - ecb->espstate = smalloc(sizeof(AESstate)); + ecb->espstate = secalloc(sizeof(AESstate)); setupAESstate(ecb->espstate, key, n /* keybytes */, ivec); + memset(ivec, 0, sizeof(ivec)); + memset(key, 0, sizeof(key)); } static int @@ -911,8 +913,10 @@ aesctrespinit(Espcb *ecb, char *name, uchar *k, unsigned n) ecb->espblklen = Aesblk; ecb->espivlen = Aesblk; ecb->cipher = aesctrcipher; - ecb->espstate = smalloc(sizeof(AESstate)); + ecb->espstate = secalloc(sizeof(AESstate)); setupAESstate(ecb->espstate, key, n /* keybytes */, ivec); + memset(ivec, 0, sizeof(ivec)); + memset(key, 0, sizeof(key)); } @@ -963,7 +967,7 @@ md5ahinit(Espcb *ecb, char *name, uchar *key, unsigned klen) ecb->ahblklen = 1; ecb->ahlen = BITS2BYTES(96); ecb->auth = md5auth; - ecb->ahstate = smalloc(klen); + ecb->ahstate = secalloc(klen); memmove(ecb->ahstate, key, klen); } @@ -1020,8 +1024,10 @@ desespinit(Espcb *ecb, char *name, uchar *k, unsigned n) ecb->espivlen = Desblk; ecb->cipher = descipher; - ecb->espstate = smalloc(sizeof(DESstate)); + ecb->espstate = secalloc(sizeof(DESstate)); setupDESstate(ecb->espstate, key, ivec); + memset(ivec, 0, sizeof(ivec)); + memset(key, 0, sizeof(key)); } static void @@ -1042,8 +1048,10 @@ des3espinit(Espcb *ecb, char *name, uchar *k, unsigned n) ecb->espivlen = Desblk; ecb->cipher = des3cipher; - ecb->espstate = smalloc(sizeof(DES3state)); + ecb->espstate = secalloc(sizeof(DES3state)); setupDES3state(ecb->espstate, key, ivec); + memset(ivec, 0, sizeof(ivec)); + memset(key, 0, sizeof(key)); } From 71ac88392f2033256b29f22bd8afdd7374100e5a Mon Sep 17 00:00:00 2001 From: cinap_lenrek Date: Sat, 27 Aug 2016 20:39:36 +0200 Subject: [PATCH 8/9] devsdp: keep cipher states in secret memory --- sys/src/9/port/devsdp.c | 32 +++++++++++++------------------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/sys/src/9/port/devsdp.c b/sys/src/9/port/devsdp.c index 2be928d66..6443212e4 100644 --- a/sys/src/9/port/devsdp.c +++ b/sys/src/9/port/devsdp.c @@ -1056,10 +1056,8 @@ onewaycleanup(OneWay *ow) { if(ow->controlpkt) freeb(ow->controlpkt); - if(ow->authstate) - free(ow->authstate); - if(ow->cipherstate) - free(ow->cipherstate); + secfree(ow->authstate); + secfree(ow->cipherstate); if(ow->compstate) free(ow->compstate); memset(ow, 0, sizeof(OneWay)); @@ -1920,14 +1918,10 @@ cipherfree(Conv *c) static void authfree(Conv *c) { - if(c->in.authstate) { - free(c->in.authstate); - c->in.authstate = nil; - } - if(c->out.authstate) { - free(c->out.authstate); - c->out.authstate = nil; - } + secfree(c->in.authstate); + secfree(c->out.authstate); + c->in.authstate = nil; + c->out.authstate = nil; c->in.auth = nil; c->in.authlen = 0; c->out.authlen = 0; @@ -2019,7 +2013,7 @@ descipherinit(Conv *c) c->in.cipherblklen = 8; c->in.cipherivlen = 8; c->in.cipher = desdecrypt; - c->in.cipherstate = smalloc(sizeof(DESstate)); + c->in.cipherstate = secalloc(sizeof(DESstate)); setupDESstate(c->in.cipherstate, key, ivec); /* out */ @@ -2030,7 +2024,7 @@ descipherinit(Conv *c) c->out.cipherblklen = 8; c->out.cipherivlen = 8; c->out.cipher = desencrypt; - c->out.cipherstate = smalloc(sizeof(DESstate)); + c->out.cipherstate = secalloc(sizeof(DESstate)); setupDESstate(c->out.cipherstate, key, ivec); } @@ -2129,7 +2123,7 @@ rc4cipherinit(Conv *c) c->in.cipherblklen = 1; c->in.cipherivlen = 4; c->in.cipher = rc4decrypt; - cr = smalloc(sizeof(CipherRc4)); + cr = secalloc(sizeof(CipherRc4)); memset(cr, 0, sizeof(*cr)); setupRC4state(&cr->current, key, n); c->in.cipherstate = cr; @@ -2140,7 +2134,7 @@ rc4cipherinit(Conv *c) c->out.cipherblklen = 1; c->out.cipherivlen = 4; c->out.cipher = rc4encrypt; - cr = smalloc(sizeof(CipherRc4)); + cr = secalloc(sizeof(CipherRc4)); memset(cr, 0, sizeof(*cr)); setupRC4state(&cr->current, key, n); c->out.cipherstate = cr; @@ -2195,7 +2189,7 @@ md5auth(OneWay *ow, uchar *t, int tlen) memset(hash, 0, MD5dlen); seanq_hmac_md5(hash, ow->seqwrap, t, tlen, (uchar*)ow->authstate, 16); - r = memcmp(t+tlen, hash, ow->authlen) == 0; + r = tsmemcmp(t+tlen, hash, ow->authlen) == 0; memmove(t+tlen, hash, ow->authlen); return r; } @@ -2212,14 +2206,14 @@ md5authinit(Conv *c) keylen = 16; /* in */ - c->in.authstate = smalloc(16); + c->in.authstate = secalloc(16); memset(c->in.authstate, 0, 16); setkey(c->in.authstate, keylen, &c->in, "auth"); c->in.authlen = 12; c->in.auth = md5auth; /* out */ - c->out.authstate = smalloc(16); + c->out.authstate = secalloc(16); memset(c->out.authstate, 0, 16); setkey(c->out.authstate, keylen, &c->out, "auth"); c->out.authlen = 12; From 0a5f81a44230cbd562b6d71a0a5be018e24a5ba6 Mon Sep 17 00:00:00 2001 From: cinap_lenrek Date: Sat, 27 Aug 2016 20:42:31 +0200 Subject: [PATCH 9/9] kernel: switch to fast portable chacha based seed-once random number generator --- sys/src/9/pc/devarch.c | 5 ++ sys/src/9/pc/mkfile | 2 +- sys/src/9/pc/pcrandom.c | 152 -------------------------------------- sys/src/9/pc64/mkfile | 2 +- sys/src/9/port/devcons.c | 32 ++++---- sys/src/9/port/portfns.h | 1 + sys/src/9/port/random.c | 156 ++++++++++++++++----------------------- 7 files changed, 83 insertions(+), 267 deletions(-) delete mode 100644 sys/src/9/pc/pcrandom.c diff --git a/sys/src/9/pc/devarch.c b/sys/src/9/pc/devarch.c index f3be061cb..0b4cad252 100644 --- a/sys/src/9/pc/devarch.c +++ b/sys/src/9/pc/devarch.c @@ -872,6 +872,11 @@ cpuidentify(void) fprestore = fpx87restore; } + if(strcmp(m->cpuidid, "GenuineIntel") == 0 && (m->cpuidcx & Rdrnd) != 0) + hwrandbuf = rdrandbuf; + else + hwrandbuf = nil; + cputype = t; return t->family; } diff --git a/sys/src/9/pc/mkfile b/sys/src/9/pc/mkfile index 96ab2c623..c6e683e22 100644 --- a/sys/src/9/pc/mkfile +++ b/sys/src/9/pc/mkfile @@ -32,6 +32,7 @@ PORT=\ proc.$O\ qio.$O\ qlock.$O\ + random.$O\ rdb.$O\ rebootcmd.$O\ segment.$O\ @@ -52,7 +53,6 @@ OBJ=\ memory.$O\ mmu.$O\ trap.$O\ - pcrandom.$O\ $CONF.root.$O\ $CONF.rootc.$O\ $DEVS\ diff --git a/sys/src/9/pc/pcrandom.c b/sys/src/9/pc/pcrandom.c deleted file mode 100644 index 386d7bf8e..000000000 --- a/sys/src/9/pc/pcrandom.c +++ /dev/null @@ -1,152 +0,0 @@ -#include "u.h" -#include "../port/lib.h" -#include "mem.h" -#include "dat.h" -#include "fns.h" -#include "../port/error.h" - -static int haverdrand; - -struct Rb -{ - QLock; - Rendez producer; - Rendez consumer; - ulong randomcount; - uchar buf[128]; - uchar *ep; - uchar *rp; - uchar *wp; - uchar next; - uchar wakeme; - ushort bits; - ulong randn; -} rb; - -static int -rbnotfull(void*) -{ - int i; - - i = rb.rp - rb.wp; - return i != 1 && i != (1 - sizeof(rb.buf)); -} - -static int -rbnotempty(void*) -{ - return rb.wp != rb.rp; -} - -static void -genrandom(void*) -{ - up->basepri = PriNormal; - up->priority = up->basepri; - - while(waserror()) - ; - for(;;){ - if(++rb.randomcount <= 100000) - continue; - if(anyhigher()) - sched(); - if(!rbnotfull(0)) - sleep(&rb.producer, rbnotfull, 0); - } -} - -/* - * produce random bits in a circular buffer - */ -static void -randomclock(void) -{ - if(rb.randomcount == 0 || !rbnotfull(0)) - return; - - rb.bits = (rb.bits<<2) ^ rb.randomcount; - rb.randomcount = 0; - - rb.next++; - if(rb.next != 8/2) - return; - rb.next = 0; - - *rb.wp ^= rb.bits; - if(rb.wp+1 == rb.ep) - rb.wp = rb.buf; - else - rb.wp = rb.wp+1; - - if(rb.wakeme) - wakeup(&rb.consumer); -} - -void -randominit(void) -{ - if(!strcmp(m->cpuidid, "GenuineIntel") - && (m->cpuidcx & Rdrnd)){ - haverdrand = 1; - } - else{ - /* Frequency close but not equal to HZ */ - addclock0link(randomclock, MS2HZ+3); - rb.ep = rb.buf + sizeof(rb.buf); - rb.rp = rb.wp = rb.buf; - kproc("genrandom", genrandom, 0); - } -} - -/* - * consume random bytes from a circular buffer - */ -ulong -randomread(void *xp, ulong n) -{ - uchar *e, *p; - ulong x; - - p = xp; - - if(haverdrand){ - rdrandbuf(p, n); - return n; - } - - if(waserror()){ - qunlock(&rb); - nexterror(); - } - - qlock(&rb); - for(e = p + n; p < e; ){ - if(rb.wp == rb.rp){ - rb.wakeme = 1; - wakeup(&rb.producer); - sleep(&rb.consumer, rbnotempty, 0); - rb.wakeme = 0; - continue; - } - - /* - * beating clocks will be predictable if - * they are synchronized. Use a cheap pseudo- - * random number generator to obscure any cycles. - */ - x = rb.randn*1103515245 ^ *rb.rp; - *p++ = rb.randn = x; - - if(rb.rp+1 == rb.ep) - rb.rp = rb.buf; - else - rb.rp = rb.rp+1; - } - qunlock(&rb); - poperror(); - - wakeup(&rb.producer); - - return n; -} diff --git a/sys/src/9/pc64/mkfile b/sys/src/9/pc64/mkfile index 30b40daf1..16aae0a68 100644 --- a/sys/src/9/pc64/mkfile +++ b/sys/src/9/pc64/mkfile @@ -29,6 +29,7 @@ PORT=\ proc.$O\ qio.$O\ qlock.$O\ + random.$O\ rdb.$O\ rebootcmd.$O\ segment.$O\ @@ -49,7 +50,6 @@ OBJ=\ memory.$O\ mmu.$O\ trap.$O\ - pcrandom.$O\ $CONF.root.$O\ $CONF.rootc.$O\ $DEVS\ diff --git a/sys/src/9/port/devcons.c b/sys/src/9/port/devcons.c index b09df91f2..7f287610f 100644 --- a/sys/src/9/port/devcons.c +++ b/sys/src/9/port/devcons.c @@ -4,8 +4,8 @@ #include "dat.h" #include "fns.h" #include "../port/error.h" -#include "pool.h" +#include #include void (*consdebug)(void) = nil; @@ -21,7 +21,6 @@ int panicking; char *sysname; vlong fasthz; -static void seedrand(void); static int readtime(ulong, char*, int); static int readbintime(char*, int); static int writetime(char*, int); @@ -616,7 +615,8 @@ consread(Chan *c, void *buf, long n, vlong off) "%lud/%lud user\n" "%lud/%lud swap\n" "%llud/%llud/%llud kernel malloc\n" - "%llud/%llud/%llud kernel draw\n", + "%llud/%llud/%llud kernel draw\n" + "%llud/%llud/%llud kernel secret\n", (uvlong)conf.npage*BY2PG, (uvlong)BY2PG, conf.npage-conf.upages, @@ -627,7 +627,10 @@ consread(Chan *c, void *buf, long n, vlong off) (uvlong)mainmem->maxsize, (uvlong)imagmem->curalloc, (uvlong)imagmem->cursize, - (uvlong)imagmem->maxsize); + (uvlong)imagmem->maxsize, + (uvlong)secrmem->curalloc, + (uvlong)secrmem->cursize, + (uvlong)secrmem->maxsize); return readstr((ulong)offset, buf, n, tmp); @@ -845,31 +848,22 @@ Dev consdevtab = { static ulong randn; -static void -seedrand(void) +int +rand(void) { - if(!waserror()){ + if(randn == 0) randomread((void*)&randn, sizeof(randn)); - poperror(); - } + randn = randn*1103515245 + 12345 + MACHP(0)->ticks; + return randn; } int nrand(int n) { - if(randn == 0) - seedrand(); - randn = randn*1103515245 + 12345 + MACHP(0)->ticks; + rand(); return (randn>>16) % n; } -int -rand(void) -{ - nrand(1); - return randn; -} - static uvlong uvorder = 0x0001020304050607ULL; static uchar* diff --git a/sys/src/9/port/portfns.h b/sys/src/9/port/portfns.h index bd0c6f16c..6f84fc691 100644 --- a/sys/src/9/port/portfns.h +++ b/sys/src/9/port/portfns.h @@ -126,6 +126,7 @@ void gotolabel(Label*); char* getconfenv(void); long hostdomainwrite(char*, int); long hostownerwrite(char*, int); +void (*hwrandbuf)(void*, ulong); void hzsched(void); Block* iallocb(int); void iallocsummary(void); diff --git a/sys/src/9/port/random.c b/sys/src/9/port/random.c index f578d68cc..012424aa6 100644 --- a/sys/src/9/port/random.c +++ b/sys/src/9/port/random.c @@ -5,135 +5,103 @@ #include "fns.h" #include "../port/error.h" -struct Rb +#include + +/* machine specific hardware random number generator */ +void (*hwrandbuf)(void*, ulong) = nil; + +static struct { QLock; - Rendez producer; - Rendez consumer; - ulong randomcount; - uchar buf[128]; - uchar *ep; - uchar *rp; - uchar *wp; - uchar next; - uchar wakeme; - ushort bits; - ulong randn; -} rb; + Chachastate; +} *rs; -static int -rbnotfull(void*) +typedef struct Seedbuf Seedbuf; +struct Seedbuf { - int i; + ulong randomcount; + uchar buf[64]; + uchar nbuf; + uchar next; + ushort bits; - i = rb.rp - rb.wp; - return i != 1 && i != (1 - sizeof(rb.buf)); -} + SHA2_512state ds; +}; -static int -rbnotempty(void*) +static void +randomsample(Ureg*, Timer *t) { - return rb.wp != rb.rp; + Seedbuf *s = t->ta; + + if(s->randomcount == 0 || s->nbuf >= sizeof(s->buf)) + return; + s->bits = (s->bits<<2) ^ s->randomcount; + s->randomcount = 0; + if(++s->next < 8/2) + return; + s->next = 0; + s->buf[s->nbuf++] ^= s->bits; } static void -genrandom(void*) +randomseed(void*) { - up->basepri = PriNormal; - up->priority = up->basepri; + Seedbuf *s; - while(waserror()) - ; - for(;;){ - if(++rb.randomcount <= 100000) + s = secalloc(sizeof(Seedbuf)); + + if(hwrandbuf != nil) + (*hwrandbuf)(s->buf, sizeof(s->buf)); + + /* Frequency close but not equal to HZ */ + up->tns = (vlong)(MS2HZ+3)*1000000LL; + up->tmode = Tperiodic; + up->tt = nil; + up->ta = s; + up->tf = randomsample; + timeradd(up); + while(s->nbuf < sizeof(s->buf)){ + if(++s->randomcount <= 100000) continue; if(anyhigher()) sched(); - if(!rbnotfull(0)) - sleep(&rb.producer, rbnotfull, 0); } -} + timerdel(up); -/* - * produce random bits in a circular buffer - */ -static void -randomclock(void) -{ - if(rb.randomcount == 0 || !rbnotfull(0)) - return; + sha2_512(s->buf, sizeof(s->buf), s->buf, &s->ds); + setupChachastate(rs, s->buf, 32, s->buf+32, 12, 20); + qunlock(rs); - rb.bits = (rb.bits<<2) ^ rb.randomcount; - rb.randomcount = 0; + secfree(s); - rb.next++; - if(rb.next != 8/2) - return; - rb.next = 0; - - *rb.wp ^= rb.bits; - if(rb.wp+1 == rb.ep) - rb.wp = rb.buf; - else - rb.wp = rb.wp+1; - - if(rb.wakeme) - wakeup(&rb.consumer); + pexit("", 1); } void randominit(void) { - /* Frequency close but not equal to HZ */ - addclock0link(randomclock, MS2HZ+3); - rb.ep = rb.buf + sizeof(rb.buf); - rb.rp = rb.wp = rb.buf; - kproc("genrandom", genrandom, 0); + rs = secalloc(sizeof(*rs)); + qlock(rs); /* randomseed() unlocks once seeded */ + kproc("randomseed", randomseed, nil); } -/* - * consume random bytes from a circular buffer - */ ulong randomread(void *xp, ulong n) { - uchar *e, *p; - ulong x; + if(n == 0) + return 0; - p = xp; + if(hwrandbuf != nil) + (*hwrandbuf)(xp, n); if(waserror()){ - qunlock(&rb); + qunlock(rs); nexterror(); } - - qlock(&rb); - for(e = p + n; p < e; ){ - if(rb.wp == rb.rp){ - rb.wakeme = 1; - wakeup(&rb.producer); - sleep(&rb.consumer, rbnotempty, 0); - rb.wakeme = 0; - continue; - } - - /* - * beating clocks will be predictable if - * they are synchronized. Use a cheap pseudo- - * random number generator to obscure any cycles. - */ - x = rb.randn*1103515245 ^ *rb.rp; - *p++ = rb.randn = x; - - if(rb.rp+1 == rb.ep) - rb.rp = rb.buf; - else - rb.rp = rb.rp+1; - } - qunlock(&rb); + qlock(rs); + chacha_encrypt((uchar*)xp, n, rs); + qunlock(rs); poperror(); - wakeup(&rb.producer); - return n; }