summaryrefslogtreecommitdiff
path: root/src/lib/libc/crypt
diff options
context:
space:
mode:
authormarkus <>2013-10-01 18:34:57 +0000
committermarkus <>2013-10-01 18:34:57 +0000
commit9a356934a3a8aebc5822ec33f95340401a618b02 (patch)
treec9d1e389fa36eda850bab2211063e000d8567112 /src/lib/libc/crypt
parent362b96a0554ddbc24305e3d4835efe41c2d73b81 (diff)
downloadopenbsd-9a356934a3a8aebc5822ec33f95340401a618b02.tar.gz
openbsd-9a356934a3a8aebc5822ec33f95340401a618b02.tar.bz2
openbsd-9a356934a3a8aebc5822ec33f95340401a618b02.zip
replace rc4 with ChaCha20; inspired by Nick Mathewson's work on libottery;
feedback and ok djm@
Diffstat (limited to 'src/lib/libc/crypt')
-rw-r--r--src/lib/libc/crypt/arc4random.c204
-rw-r--r--src/lib/libc/crypt/chacha_private.h220
2 files changed, 326 insertions, 98 deletions
diff --git a/src/lib/libc/crypt/arc4random.c b/src/lib/libc/crypt/arc4random.c
index f00f5ee9f1..356e231815 100644
--- a/src/lib/libc/crypt/arc4random.c
+++ b/src/lib/libc/crypt/arc4random.c
@@ -1,8 +1,9 @@
1/* $OpenBSD: arc4random.c,v 1.24 2013/06/11 16:59:50 deraadt Exp $ */ 1/* $OpenBSD: arc4random.c,v 1.25 2013/10/01 18:34:57 markus Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 1996, David Mazieres <dm@uun.org> 4 * Copyright (c) 1996, David Mazieres <dm@uun.org>
5 * Copyright (c) 2008, Damien Miller <djm@openbsd.org> 5 * Copyright (c) 2008, Damien Miller <djm@openbsd.org>
6 * Copyright (c) 2013, Markus Friedl <markus@openbsd.org>
6 * 7 *
7 * Permission to use, copy, modify, and distribute this software for any 8 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above 9 * purpose with or without fee is hereby granted, provided that the above
@@ -18,20 +19,13 @@
18 */ 19 */
19 20
20/* 21/*
21 * Arc4 random number generator for OpenBSD. 22 * ChaCha based random number generator for OpenBSD.
22 *
23 * This code is derived from section 17.1 of Applied Cryptography,
24 * second edition, which describes a stream cipher allegedly
25 * compatible with RSA Labs "RC4" cipher (the actual description of
26 * which is a trade secret). The same algorithm is used as a stream
27 * cipher called "arcfour" in Tatu Ylonen's ssh package.
28 *
29 * RC4 is a registered trademark of RSA Laboratories.
30 */ 23 */
31 24
32#include <fcntl.h> 25#include <fcntl.h>
33#include <limits.h> 26#include <limits.h>
34#include <stdlib.h> 27#include <stdlib.h>
28#include <string.h>
35#include <unistd.h> 29#include <unistd.h>
36#include <sys/types.h> 30#include <sys/types.h>
37#include <sys/param.h> 31#include <sys/param.h>
@@ -39,64 +33,43 @@
39#include <sys/sysctl.h> 33#include <sys/sysctl.h>
40#include "thread_private.h" 34#include "thread_private.h"
41 35
36#define KEYSTREAM_ONLY
37#include "chacha_private.h"
38
42#ifdef __GNUC__ 39#ifdef __GNUC__
43#define inline __inline 40#define inline __inline
44#else /* !__GNUC__ */ 41#else /* !__GNUC__ */
45#define inline 42#define inline
46#endif /* !__GNUC__ */ 43#endif /* !__GNUC__ */
47 44
48struct arc4_stream { 45#define KEYSZ 32
49 u_int8_t i; 46#define IVSZ 8
50 u_int8_t j; 47#define BLOCKSZ 64
51 u_int8_t s[256]; 48#define RSBUFSZ (16*BLOCKSZ)
52};
53
54static int rs_initialized; 49static int rs_initialized;
55static struct arc4_stream rs; 50static pid_t rs_stir_pid;
56static pid_t arc4_stir_pid; 51static chacha_ctx rs; /* chacha context for random keystream */
57static int arc4_count; 52static u_char rs_buf[RSBUFSZ]; /* keystream blocks */
58 53static size_t rs_have; /* valid bytes at end of rs_buf */
59static inline u_int8_t arc4_getbyte(void); 54static size_t rs_count; /* bytes till reseed */
60 55
61static inline void 56static inline void _rs_rekey(u_char *dat, size_t datlen);
62arc4_init(void)
63{
64 int n;
65
66 for (n = 0; n < 256; n++)
67 rs.s[n] = n;
68 rs.i = 0;
69 rs.j = 0;
70}
71 57
72static inline void 58static inline void
73arc4_addrandom(u_char *dat, int datlen) 59_rs_init(u_char *buf, size_t n)
74{ 60{
75 int n; 61 if (n < KEYSZ + IVSZ)
76 u_int8_t si; 62 return;
77 63 chacha_keysetup(&rs, buf, KEYSZ * 8, 0);
78 rs.i--; 64 chacha_ivsetup(&rs, buf + KEYSZ);
79 for (n = 0; n < 256; n++) {
80 rs.i = (rs.i + 1);
81 si = rs.s[rs.i];
82 rs.j = (rs.j + si + dat[n % datlen]);
83 rs.s[rs.i] = rs.s[rs.j];
84 rs.s[rs.j] = si;
85 }
86 rs.j = rs.i;
87} 65}
88 66
89static void 67static void
90arc4_stir(void) 68_rs_stir(void)
91{ 69{
92 int i, mib[2]; 70 int mib[2];
93 size_t len; 71 size_t len;
94 u_char rnd[128]; 72 u_char rnd[KEYSZ + IVSZ];
95
96 if (!rs_initialized) {
97 arc4_init();
98 rs_initialized = 1;
99 }
100 73
101 mib[0] = CTL_KERN; 74 mib[0] = CTL_KERN;
102 mib[1] = KERN_ARND; 75 mib[1] = KERN_ARND;
@@ -104,68 +77,109 @@ arc4_stir(void)
104 len = sizeof(rnd); 77 len = sizeof(rnd);
105 sysctl(mib, 2, rnd, &len, NULL, 0); 78 sysctl(mib, 2, rnd, &len, NULL, 0);
106 79
107 arc4_addrandom(rnd, sizeof(rnd)); 80 if (!rs_initialized) {
81 rs_initialized = 1;
82 _rs_init(rnd, sizeof(rnd));
83 } else
84 _rs_rekey(rnd, sizeof(rnd));
85 memset(rnd, 0, sizeof(rnd));
108 86
109 /* 87 /* invalidate rs_buf */
110 * Discard early keystream, as per recommendations in: 88 rs_have = 0;
111 * http://www.wisdom.weizmann.ac.il/~itsik/RC4/Papers/Rc4_ksa.ps 89 memset(rs_buf, 0, RSBUFSZ);
112 */ 90
113 for (i = 0; i < 256; i++) 91 rs_count = 1600000;
114 (void)arc4_getbyte();
115 arc4_count = 1600000;
116} 92}
117 93
118static void 94static inline void
119arc4_stir_if_needed(void) 95_rs_stir_if_needed(size_t len)
120{ 96{
121 pid_t pid = getpid(); 97 pid_t pid = getpid();
122 98
123 if (arc4_count <= 0 || !rs_initialized || arc4_stir_pid != pid) { 99 if (rs_count <= len || !rs_initialized || rs_stir_pid != pid) {
124 arc4_stir_pid = pid; 100 rs_stir_pid = pid;
125 arc4_stir(); 101 _rs_stir();
102 } else
103 rs_count -= len;
104}
105
106static inline void
107_rs_rekey(u_char *dat, size_t datlen)
108{
109#ifndef KEYSTREAM_ONLY
110 memset(rs_buf, 0,RSBUFSZ);
111#endif
112 /* fill rs_buf with the keystream */
113 chacha_encrypt_bytes(&rs, rs_buf, rs_buf, RSBUFSZ);
114 /* mix in optional user provided data */
115 if (dat) {
116 size_t i, m;
117
118 m = MIN(datlen, KEYSZ + IVSZ);
119 for (i = 0; i < m; i++)
120 rs_buf[i] ^= dat[i];
126 } 121 }
122 /* immediately reinit for backtracking resistance */
123 _rs_init(rs_buf, KEYSZ + IVSZ);
124 memset(rs_buf, 0, KEYSZ + IVSZ);
125 rs_have = RSBUFSZ - KEYSZ - IVSZ;
127} 126}
128 127
129static inline u_int8_t 128static inline void
130arc4_getbyte(void) 129_rs_random_buf(void *_buf, size_t n)
131{ 130{
132 u_int8_t si, sj; 131 u_char *buf = (u_char *)_buf;
133 132 size_t m;
134 rs.i = (rs.i + 1); 133
135 si = rs.s[rs.i]; 134 _rs_stir_if_needed(n);
136 rs.j = (rs.j + si); 135 while (n > 0) {
137 sj = rs.s[rs.j]; 136 if (rs_have > 0) {
138 rs.s[rs.i] = sj; 137 m = MIN(n, rs_have);
139 rs.s[rs.j] = si; 138 memcpy(buf, rs_buf + RSBUFSZ - rs_have, m);
140 return (rs.s[(si + sj) & 0xff]); 139 memset(rs_buf + RSBUFSZ - rs_have, 0, m);
140 buf += m;
141 n -= m;
142 rs_have -= m;
143 }
144 if (rs_have == 0)
145 _rs_rekey(NULL, 0);
146 }
141} 147}
142 148
143static inline u_int32_t 149static inline void
144arc4_getword(void) 150_rs_random_u32(u_int32_t *val)
145{ 151{
146 u_int32_t val; 152 _rs_stir_if_needed(sizeof(*val));
147 val = arc4_getbyte() << 24; 153 if (rs_have < sizeof(*val))
148 val |= arc4_getbyte() << 16; 154 _rs_rekey(NULL, 0);
149 val |= arc4_getbyte() << 8; 155 memcpy(val, rs_buf + RSBUFSZ - rs_have, sizeof(*val));
150 val |= arc4_getbyte(); 156 memset(rs_buf + RSBUFSZ - rs_have, 0, sizeof(*val));
151 return val; 157 rs_have -= sizeof(*val);
158 return;
152} 159}
153 160
154void 161void
155arc4random_stir(void) 162arc4random_stir(void)
156{ 163{
157 _ARC4_LOCK(); 164 _ARC4_LOCK();
158 arc4_stir(); 165 _rs_stir();
159 _ARC4_UNLOCK(); 166 _ARC4_UNLOCK();
160} 167}
161 168
162void 169void
163arc4random_addrandom(u_char *dat, int datlen) 170arc4random_addrandom(u_char *dat, int datlen)
164{ 171{
172 int m;
173
165 _ARC4_LOCK(); 174 _ARC4_LOCK();
166 if (!rs_initialized) 175 if (!rs_initialized)
167 arc4_stir(); 176 _rs_stir();
168 arc4_addrandom(dat, datlen); 177 while (datlen > 0) {
178 m = MIN(datlen, KEYSZ + IVSZ);
179 _rs_rekey(dat, m);
180 dat += m;
181 datlen -= m;
182 }
169 _ARC4_UNLOCK(); 183 _ARC4_UNLOCK();
170} 184}
171 185
@@ -173,25 +187,18 @@ u_int32_t
173arc4random(void) 187arc4random(void)
174{ 188{
175 u_int32_t val; 189 u_int32_t val;
190
176 _ARC4_LOCK(); 191 _ARC4_LOCK();
177 arc4_count -= 4; 192 _rs_random_u32(&val);
178 arc4_stir_if_needed();
179 val = arc4_getword();
180 _ARC4_UNLOCK(); 193 _ARC4_UNLOCK();
181 return val; 194 return val;
182} 195}
183 196
184void 197void
185arc4random_buf(void *_buf, size_t n) 198arc4random_buf(void *buf, size_t n)
186{ 199{
187 u_char *buf = (u_char *)_buf;
188 _ARC4_LOCK(); 200 _ARC4_LOCK();
189 arc4_stir_if_needed(); 201 _rs_random_buf(buf, n);
190 while (n--) {
191 if (--arc4_count <= 0)
192 arc4_stir();
193 buf[n] = arc4_getbyte();
194 }
195 _ARC4_UNLOCK(); 202 _ARC4_UNLOCK();
196} 203}
197 204
@@ -249,5 +256,6 @@ main(int argc, char **argv)
249 v /= iter; 256 v /= iter;
250 257
251 printf("%qd cycles\n", v); 258 printf("%qd cycles\n", v);
259 exit(0);
252} 260}
253#endif 261#endif
diff --git a/src/lib/libc/crypt/chacha_private.h b/src/lib/libc/crypt/chacha_private.h
new file mode 100644
index 0000000000..fa085fb6ae
--- /dev/null
+++ b/src/lib/libc/crypt/chacha_private.h
@@ -0,0 +1,220 @@
1/*
2chacha-merged.c version 20080118
3D. J. Bernstein
4Public domain.
5*/
6
7typedef unsigned char u8;
8typedef unsigned int u32;
9
10typedef struct
11{
12 u32 input[16]; /* could be compressed */
13} chacha_ctx;
14
15#define U8C(v) (v##U)
16#define U32C(v) (v##U)
17
18#define U8V(v) ((u8)(v) & U8C(0xFF))
19#define U32V(v) ((u32)(v) & U32C(0xFFFFFFFF))
20
21#define ROTL32(v, n) \
22 (U32V((v) << (n)) | ((v) >> (32 - (n))))
23
24#define U8TO32_LITTLE(p) \
25 (((u32)((p)[0]) ) | \
26 ((u32)((p)[1]) << 8) | \
27 ((u32)((p)[2]) << 16) | \
28 ((u32)((p)[3]) << 24))
29
30#define U32TO8_LITTLE(p, v) \
31 do { \
32 (p)[0] = U8V((v) ); \
33 (p)[1] = U8V((v) >> 8); \
34 (p)[2] = U8V((v) >> 16); \
35 (p)[3] = U8V((v) >> 24); \
36 } while (0)
37
38#define ROTATE(v,c) (ROTL32(v,c))
39#define XOR(v,w) ((v) ^ (w))
40#define PLUS(v,w) (U32V((v) + (w)))
41#define PLUSONE(v) (PLUS((v),1))
42
43#define QUARTERROUND(a,b,c,d) \
44 a = PLUS(a,b); d = ROTATE(XOR(d,a),16); \
45 c = PLUS(c,d); b = ROTATE(XOR(b,c),12); \
46 a = PLUS(a,b); d = ROTATE(XOR(d,a), 8); \
47 c = PLUS(c,d); b = ROTATE(XOR(b,c), 7);
48
49static const char sigma[16] = "expand 32-byte k";
50static const char tau[16] = "expand 16-byte k";
51
52static void
53chacha_keysetup(chacha_ctx *x,const u8 *k,u32 kbits,u32 ivbits)
54{
55 const char *constants;
56
57 x->input[4] = U8TO32_LITTLE(k + 0);
58 x->input[5] = U8TO32_LITTLE(k + 4);
59 x->input[6] = U8TO32_LITTLE(k + 8);
60 x->input[7] = U8TO32_LITTLE(k + 12);
61 if (kbits == 256) { /* recommended */
62 k += 16;
63 constants = sigma;
64 } else { /* kbits == 128 */
65 constants = tau;
66 }
67 x->input[8] = U8TO32_LITTLE(k + 0);
68 x->input[9] = U8TO32_LITTLE(k + 4);
69 x->input[10] = U8TO32_LITTLE(k + 8);
70 x->input[11] = U8TO32_LITTLE(k + 12);
71 x->input[0] = U8TO32_LITTLE(constants + 0);
72 x->input[1] = U8TO32_LITTLE(constants + 4);
73 x->input[2] = U8TO32_LITTLE(constants + 8);
74 x->input[3] = U8TO32_LITTLE(constants + 12);
75}
76
77static void
78chacha_ivsetup(chacha_ctx *x,const u8 *iv)
79{
80 x->input[12] = 0;
81 x->input[13] = 0;
82 x->input[14] = U8TO32_LITTLE(iv + 0);
83 x->input[15] = U8TO32_LITTLE(iv + 4);
84}
85
86static void
87chacha_encrypt_bytes(chacha_ctx *x,const u8 *m,u8 *c,u32 bytes)
88{
89 u32 x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15;
90 u32 j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;
91 u8 *ctarget;
92 u8 tmp[64];
93 int i;
94
95 if (!bytes) return;
96
97 j0 = x->input[0];
98 j1 = x->input[1];
99 j2 = x->input[2];
100 j3 = x->input[3];
101 j4 = x->input[4];
102 j5 = x->input[5];
103 j6 = x->input[6];
104 j7 = x->input[7];
105 j8 = x->input[8];
106 j9 = x->input[9];
107 j10 = x->input[10];
108 j11 = x->input[11];
109 j12 = x->input[12];
110 j13 = x->input[13];
111 j14 = x->input[14];
112 j15 = x->input[15];
113
114 for (;;) {
115 if (bytes < 64) {
116 for (i = 0;i < bytes;++i) tmp[i] = m[i];
117 m = tmp;
118 ctarget = c;
119 c = tmp;
120 }
121 x0 = j0;
122 x1 = j1;
123 x2 = j2;
124 x3 = j3;
125 x4 = j4;
126 x5 = j5;
127 x6 = j6;
128 x7 = j7;
129 x8 = j8;
130 x9 = j9;
131 x10 = j10;
132 x11 = j11;
133 x12 = j12;
134 x13 = j13;
135 x14 = j14;
136 x15 = j15;
137 for (i = 20;i > 0;i -= 2) {
138 QUARTERROUND( x0, x4, x8,x12)
139 QUARTERROUND( x1, x5, x9,x13)
140 QUARTERROUND( x2, x6,x10,x14)
141 QUARTERROUND( x3, x7,x11,x15)
142 QUARTERROUND( x0, x5,x10,x15)
143 QUARTERROUND( x1, x6,x11,x12)
144 QUARTERROUND( x2, x7, x8,x13)
145 QUARTERROUND( x3, x4, x9,x14)
146 }
147 x0 = PLUS(x0,j0);
148 x1 = PLUS(x1,j1);
149 x2 = PLUS(x2,j2);
150 x3 = PLUS(x3,j3);
151 x4 = PLUS(x4,j4);
152 x5 = PLUS(x5,j5);
153 x6 = PLUS(x6,j6);
154 x7 = PLUS(x7,j7);
155 x8 = PLUS(x8,j8);
156 x9 = PLUS(x9,j9);
157 x10 = PLUS(x10,j10);
158 x11 = PLUS(x11,j11);
159 x12 = PLUS(x12,j12);
160 x13 = PLUS(x13,j13);
161 x14 = PLUS(x14,j14);
162 x15 = PLUS(x15,j15);
163
164#ifndef KEYSTREAM_ONLY
165 x0 = XOR(x0,U8TO32_LITTLE(m + 0));
166 x1 = XOR(x1,U8TO32_LITTLE(m + 4));
167 x2 = XOR(x2,U8TO32_LITTLE(m + 8));
168 x3 = XOR(x3,U8TO32_LITTLE(m + 12));
169 x4 = XOR(x4,U8TO32_LITTLE(m + 16));
170 x5 = XOR(x5,U8TO32_LITTLE(m + 20));
171 x6 = XOR(x6,U8TO32_LITTLE(m + 24));
172 x7 = XOR(x7,U8TO32_LITTLE(m + 28));
173 x8 = XOR(x8,U8TO32_LITTLE(m + 32));
174 x9 = XOR(x9,U8TO32_LITTLE(m + 36));
175 x10 = XOR(x10,U8TO32_LITTLE(m + 40));
176 x11 = XOR(x11,U8TO32_LITTLE(m + 44));
177 x12 = XOR(x12,U8TO32_LITTLE(m + 48));
178 x13 = XOR(x13,U8TO32_LITTLE(m + 52));
179 x14 = XOR(x14,U8TO32_LITTLE(m + 56));
180 x15 = XOR(x15,U8TO32_LITTLE(m + 60));
181#endif
182
183 j12 = PLUSONE(j12);
184 if (!j12) {
185 j13 = PLUSONE(j13);
186 /* stopping at 2^70 bytes per nonce is user's responsibility */
187 }
188
189 U32TO8_LITTLE(c + 0,x0);
190 U32TO8_LITTLE(c + 4,x1);
191 U32TO8_LITTLE(c + 8,x2);
192 U32TO8_LITTLE(c + 12,x3);
193 U32TO8_LITTLE(c + 16,x4);
194 U32TO8_LITTLE(c + 20,x5);
195 U32TO8_LITTLE(c + 24,x6);
196 U32TO8_LITTLE(c + 28,x7);
197 U32TO8_LITTLE(c + 32,x8);
198 U32TO8_LITTLE(c + 36,x9);
199 U32TO8_LITTLE(c + 40,x10);
200 U32TO8_LITTLE(c + 44,x11);
201 U32TO8_LITTLE(c + 48,x12);
202 U32TO8_LITTLE(c + 52,x13);
203 U32TO8_LITTLE(c + 56,x14);
204 U32TO8_LITTLE(c + 60,x15);
205
206 if (bytes <= 64) {
207 if (bytes < 64) {
208 for (i = 0;i < bytes;++i) ctarget[i] = c[i];
209 }
210 x->input[12] = j12;
211 x->input[13] = j13;
212 return;
213 }
214 bytes -= 64;
215 c += 64;
216#ifndef KEYSTREAM_ONLY
217 m += 64;
218#endif
219 }
220}