Browse Source

- make arc4random*() functions thread safe. Use a custom spinlock function

instead of the generic pthread macros since free(3) uses __arc4_getbyte()
when freeing small sized allocations and the generic pthread macros call
malloc(3).
- eliminate passing pointers to a static variable with global scope (rs)
for additional code clarity and reduction.
- shlib minor bumps for libc and libpthread due to new functions.
From andreas@ with some bits from me. okay tedu@ marc@ w/some spot
checking from millert@
OPENBSD_4_3
kurt 17 years ago
parent
commit
f4c406b83b
1 changed files with 56 additions and 41 deletions
  1. +56
    -41
      src/lib/libc/crypt/arc4random.c

+ 56
- 41
src/lib/libc/crypt/arc4random.c View File

@ -1,4 +1,4 @@
/* $OpenBSD: arc4random.c,v 1.16 2007/02/12 19:58:47 otto Exp $ */
/* $OpenBSD: arc4random.c,v 1.17 2008/01/01 00:43:39 kurt Exp $ */
/* /*
* Copyright (c) 1996, David Mazieres <dm@uun.org> * Copyright (c) 1996, David Mazieres <dm@uun.org>
@ -40,6 +40,7 @@
#include <sys/param.h> #include <sys/param.h>
#include <sys/time.h> #include <sys/time.h>
#include <sys/sysctl.h> #include <sys/sysctl.h>
#include "thread_private.h"
#ifdef __GNUC__ #ifdef __GNUC__
#define inline __inline #define inline __inline
@ -58,43 +59,48 @@ static struct arc4_stream rs;
static pid_t arc4_stir_pid; static pid_t arc4_stir_pid;
static int arc4_count; static int arc4_count;
static inline u_int8_t arc4_getbyte(struct arc4_stream *);
static inline u_int8_t arc4_getbyte(void);
static inline void static inline void
arc4_init(struct arc4_stream *as)
arc4_init(void)
{ {
int n; int n;
for (n = 0; n < 256; n++) for (n = 0; n < 256; n++)
as->s[n] = n;
as->i = 0;
as->j = 0;
rs.s[n] = n;
rs.i = 0;
rs.j = 0;
} }
static inline void static inline void
arc4_addrandom(struct arc4_stream *as, u_char *dat, int datlen)
arc4_addrandom(u_char *dat, int datlen)
{ {
int n; int n;
u_int8_t si; u_int8_t si;
as->i--;
rs.i--;
for (n = 0; n < 256; n++) { for (n = 0; n < 256; n++) {
as->i = (as->i + 1);
si = as->s[as->i];
as->j = (as->j + si + dat[n % datlen]);
as->s[as->i] = as->s[as->j];
as->s[as->j] = si;
rs.i = (rs.i + 1);
si = rs.s[rs.i];
rs.j = (rs.j + si + dat[n % datlen]);
rs.s[rs.i] = rs.s[rs.j];
rs.s[rs.j] = si;
} }
as->j = as->i;
rs.j = rs.i;
} }
static void static void
arc4_stir(struct arc4_stream *as)
arc4_stir(void)
{ {
int i, mib[2]; int i, mib[2];
size_t len; size_t len;
u_char rnd[128]; u_char rnd[128];
if (!rs_initialized) {
arc4_init();
rs_initialized = 1;
}
mib[0] = CTL_KERN; mib[0] = CTL_KERN;
mib[1] = KERN_ARND; mib[1] = KERN_ARND;
@ -102,75 +108,84 @@ arc4_stir(struct arc4_stream *as)
sysctl(mib, 2, rnd, &len, NULL, 0); sysctl(mib, 2, rnd, &len, NULL, 0);
arc4_stir_pid = getpid(); arc4_stir_pid = getpid();
arc4_addrandom(as, rnd, sizeof(rnd));
arc4_addrandom(rnd, sizeof(rnd));
/* /*
* Discard early keystream, as per recommendations in: * Discard early keystream, as per recommendations in:
* http://www.wisdom.weizmann.ac.il/~itsik/RC4/Papers/Rc4_ksa.ps * http://www.wisdom.weizmann.ac.il/~itsik/RC4/Papers/Rc4_ksa.ps
*/ */
for (i = 0; i < 256; i++) for (i = 0; i < 256; i++)
(void)arc4_getbyte(as);
(void)arc4_getbyte();
arc4_count = 1600000; arc4_count = 1600000;
} }
static inline u_int8_t static inline u_int8_t
arc4_getbyte(struct arc4_stream *as)
arc4_getbyte(void)
{ {
u_int8_t si, sj; u_int8_t si, sj;
as->i = (as->i + 1);
si = as->s[as->i];
as->j = (as->j + si);
sj = as->s[as->j];
as->s[as->i] = sj;
as->s[as->j] = si;
return (as->s[(si + sj) & 0xff]);
rs.i = (rs.i + 1);
si = rs.s[rs.i];
rs.j = (rs.j + si);
sj = rs.s[rs.j];
rs.s[rs.i] = sj;
rs.s[rs.j] = si;
return (rs.s[(si + sj) & 0xff]);
} }
u_int8_t u_int8_t
__arc4_getbyte(void) __arc4_getbyte(void)
{ {
u_int8_t val;
_ARC4_LOCK();
if (--arc4_count == 0 || !rs_initialized) if (--arc4_count == 0 || !rs_initialized)
arc4random_stir();
return arc4_getbyte(&rs);
arc4_stir();
val = arc4_getbyte();
_ARC4_UNLOCK();
return val;
} }
static inline u_int32_t static inline u_int32_t
arc4_getword(struct arc4_stream *as)
arc4_getword(void)
{ {
u_int32_t val; u_int32_t val;
val = arc4_getbyte(as) << 24;
val |= arc4_getbyte(as) << 16;
val |= arc4_getbyte(as) << 8;
val |= arc4_getbyte(as);
val = arc4_getbyte() << 24;
val |= arc4_getbyte() << 16;
val |= arc4_getbyte() << 8;
val |= arc4_getbyte();
return val; return val;
} }
void void
arc4random_stir(void) arc4random_stir(void)
{ {
if (!rs_initialized) {
arc4_init(&rs);
rs_initialized = 1;
}
arc4_stir(&rs);
_ARC4_LOCK();
arc4_stir();
_ARC4_UNLOCK();
} }
void void
arc4random_addrandom(u_char *dat, int datlen) arc4random_addrandom(u_char *dat, int datlen)
{ {
_ARC4_LOCK();
if (!rs_initialized) if (!rs_initialized)
arc4random_stir();
arc4_addrandom(&rs, dat, datlen);
arc4_stir();
arc4_addrandom(dat, datlen);
_ARC4_UNLOCK();
} }
u_int32_t u_int32_t
arc4random(void) arc4random(void)
{ {
u_int32_t val;
_ARC4_LOCK();
arc4_count -= 4; arc4_count -= 4;
if (arc4_count <= 0 || !rs_initialized || arc4_stir_pid != getpid()) if (arc4_count <= 0 || !rs_initialized || arc4_stir_pid != getpid())
arc4random_stir();
return arc4_getword(&rs);
arc4_stir();
val = arc4_getword();
_ARC4_UNLOCK();
return val;
} }
#if 0 #if 0


Loading…
Cancel
Save