aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeil Horman <nhorman@tuxdriver.com>2008-07-07 10:41:31 -0400
committerHerbert Xu <herbert@gondor.apana.org.au>2008-07-10 08:35:18 -0400
commitb8454eebe380677789735fd6bad368af2e6b2d1e (patch)
treed1deffadf86c3292e51bde06bf8d2a00c20da697
parent166247f46a9c866e6f7f7d2212be875fb82212a1 (diff)
crypto: prng - Deterministic CPRNG
This patch adds a cryptographic pseudo-random number generator based on CTR(AES-128). It is meant to be used in cases where a deterministic CPRNG is required. One of the first applications will be as an input in the IPsec IV generation process. Signed-off-by: Neil Horman <nhorman@tuxdriver.com> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
-rw-r--r--crypto/Kconfig9
-rw-r--r--crypto/Makefile2
-rw-r--r--crypto/prng.c410
-rw-r--r--crypto/prng.h27
4 files changed, 447 insertions, 1 deletions
diff --git a/crypto/Kconfig b/crypto/Kconfig
index 795e31c8aec2..43b7473ff19b 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -666,6 +666,15 @@ config CRYPTO_LZO
666 help 666 help
667 This is the LZO algorithm. 667 This is the LZO algorithm.
668 668
669comment "Random Number Generation"
670
671config CRYPTO_PRNG
672 tristate "Pseudo Random Number Generation for Cryptographic modules"
673 help
674 This option enables the generic pseudo random number generator
675 for cryptographic modules. Uses the Algorithm specified in
676 ANSI X9.31 A.2.4
677
669source "drivers/crypto/Kconfig" 678source "drivers/crypto/Kconfig"
670 679
671endif # if CRYPTO 680endif # if CRYPTO
diff --git a/crypto/Makefile b/crypto/Makefile
index d4f3ed857df0..ef61b3b64660 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -69,7 +69,7 @@ obj-$(CONFIG_CRYPTO_MICHAEL_MIC) += michael_mic.o
69obj-$(CONFIG_CRYPTO_CRC32C) += crc32c.o 69obj-$(CONFIG_CRYPTO_CRC32C) += crc32c.o
70obj-$(CONFIG_CRYPTO_AUTHENC) += authenc.o 70obj-$(CONFIG_CRYPTO_AUTHENC) += authenc.o
71obj-$(CONFIG_CRYPTO_LZO) += lzo.o 71obj-$(CONFIG_CRYPTO_LZO) += lzo.o
72 72obj-$(CONFIG_CRYPTO_PRNG) += prng.o
73obj-$(CONFIG_CRYPTO_TEST) += tcrypt.o 73obj-$(CONFIG_CRYPTO_TEST) += tcrypt.o
74 74
75# 75#
diff --git a/crypto/prng.c b/crypto/prng.c
new file mode 100644
index 000000000000..24e4f3282c56
--- /dev/null
+++ b/crypto/prng.c
@@ -0,0 +1,410 @@
1/*
2 * PRNG: Pseudo Random Number Generator
3 * Based on NIST Recommended PRNG From ANSI X9.31 Appendix A.2.4 using
4 * AES 128 cipher in RFC3686 ctr mode
5 *
6 * (C) Neil Horman <nhorman@tuxdriver.com>
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * any later version.
12 *
13 *
14 */
15
16#include <linux/err.h>
17#include <linux/init.h>
18#include <linux/module.h>
19#include <linux/mm.h>
20#include <linux/slab.h>
21#include <linux/fs.h>
22#include <linux/scatterlist.h>
23#include <linux/string.h>
24#include <linux/crypto.h>
25#include <linux/highmem.h>
26#include <linux/moduleparam.h>
27#include <linux/jiffies.h>
28#include <linux/timex.h>
29#include <linux/interrupt.h>
30#include <linux/miscdevice.h>
31#include "prng.h"
32
33#define TEST_PRNG_ON_START 0
34
35#define DEFAULT_PRNG_KEY "0123456789abcdef1011"
36#define DEFAULT_PRNG_KSZ 20
37#define DEFAULT_PRNG_IV "defaultv"
38#define DEFAULT_PRNG_IVSZ 8
39#define DEFAULT_BLK_SZ 16
40#define DEFAULT_V_SEED "zaybxcwdveuftgsh"
41
42/*
43 * Flags for the prng_context flags field
44 */
45
46#define PRNG_FIXED_SIZE 0x1
47#define PRNG_NEED_RESET 0x2
48
49/*
50 * Note: DT is our counter value
51 * I is our intermediate value
52 * V is our seed vector
53 * See http://csrc.nist.gov/groups/STM/cavp/documents/rng/931rngext.pdf
54 * for implementation details
55 */
56
57
58struct prng_context {
59 char *prng_key;
60 char *prng_iv;
61 spinlock_t prng_lock;
62 unsigned char rand_data[DEFAULT_BLK_SZ];
63 unsigned char last_rand_data[DEFAULT_BLK_SZ];
64 unsigned char DT[DEFAULT_BLK_SZ];
65 unsigned char I[DEFAULT_BLK_SZ];
66 unsigned char V[DEFAULT_BLK_SZ];
67 u32 rand_data_valid;
68 struct crypto_blkcipher *tfm;
69 u32 flags;
70};
71
72static int dbg;
73
74static void hexdump(char *note, unsigned char *buf, unsigned int len)
75{
76 if (dbg) {
77 printk(KERN_CRIT "%s", note);
78 print_hex_dump(KERN_CONT, "", DUMP_PREFIX_OFFSET,
79 16, 1,
80 buf, len, false);
81 }
82}
83
84#define dbgprint(format, args...) do {if(dbg) printk(format, ##args);} while(0)
85
86static void xor_vectors(unsigned char *in1, unsigned char *in2,
87 unsigned char *out, unsigned int size)
88{
89 int i;
90
91 for (i=0;i<size;i++)
92 out[i] = in1[i] ^ in2[i];
93
94}
95/*
96 * Returns DEFAULT_BLK_SZ bytes of random data per call
97 * returns 0 if generation succeded, <0 if something went wrong
98 */
99static int _get_more_prng_bytes(struct prng_context *ctx)
100{
101 int i;
102 struct blkcipher_desc desc;
103 struct scatterlist sg_in, sg_out;
104 int ret;
105 unsigned char tmp[DEFAULT_BLK_SZ];
106
107 desc.tfm = ctx->tfm;
108 desc.flags = 0;
109
110
111 dbgprint(KERN_CRIT "Calling _get_more_prng_bytes for context %p\n",ctx);
112
113 hexdump("Input DT: ", ctx->DT, DEFAULT_BLK_SZ);
114 hexdump("Input I: ", ctx->I, DEFAULT_BLK_SZ);
115 hexdump("Input V: ", ctx->V, DEFAULT_BLK_SZ);
116
117 /*
118 * This algorithm is a 3 stage state machine
119 */
120 for (i=0;i<3;i++) {
121
122 desc.tfm = ctx->tfm;
123 desc.flags = 0;
124 switch (i) {
125 case 0:
126 /*
127 * Start by encrypting the counter value
128 * This gives us an intermediate value I
129 */
130 memcpy(tmp, ctx->DT, DEFAULT_BLK_SZ);
131 sg_init_one(&sg_out, &ctx->I[0], DEFAULT_BLK_SZ);
132 hexdump("tmp stage 0: ", tmp, DEFAULT_BLK_SZ);
133 break;
134 case 1:
135
136 /*
137 * Next xor I with our secret vector V
138 * encrypt that result to obtain our
139 * pseudo random data which we output
140 */
141 xor_vectors(ctx->I, ctx->V, tmp, DEFAULT_BLK_SZ);
142 sg_init_one(&sg_out, &ctx->rand_data[0], DEFAULT_BLK_SZ);
143 hexdump("tmp stage 1: ", tmp, DEFAULT_BLK_SZ);
144 break;
145 case 2:
146 /*
147 * First check that we didn't produce the same random data
148 * that we did last time around through this
149 */
150 if (!memcmp(ctx->rand_data, ctx->last_rand_data, DEFAULT_BLK_SZ)) {
151 printk(KERN_ERR "ctx %p Failed repetition check!\n",
152 ctx);
153 ctx->flags |= PRNG_NEED_RESET;
154 return -1;
155 }
156 memcpy(ctx->last_rand_data, ctx->rand_data, DEFAULT_BLK_SZ);
157
158 /*
159 * Lastly xor the random data with I
160 * and encrypt that to obtain a new secret vector V
161 */
162 xor_vectors(ctx->rand_data, ctx->I, tmp, DEFAULT_BLK_SZ);
163 sg_init_one(&sg_out, &ctx->V[0], DEFAULT_BLK_SZ);
164 hexdump("tmp stage 2: ", tmp, DEFAULT_BLK_SZ);
165 break;
166 }
167
168 /* Initialize our input buffer */
169 sg_init_one(&sg_in, &tmp[0], DEFAULT_BLK_SZ);
170
171 /* do the encryption */
172 ret = crypto_blkcipher_encrypt(&desc, &sg_out, &sg_in, DEFAULT_BLK_SZ);
173
174 /* And check the result */
175 if (ret) {
176 dbgprint(KERN_CRIT "Encryption of new block failed for context %p\n",ctx);
177 ctx->rand_data_valid = DEFAULT_BLK_SZ;
178 return -1;
179 }
180
181 }
182
183 /*
184 * Now update our DT value
185 */
186 for (i=DEFAULT_BLK_SZ-1;i>0;i--) {
187 ctx->DT[i] = ctx->DT[i-1];
188 }
189 ctx->DT[0] += 1;
190
191 dbgprint("Returning new block for context %p\n",ctx);
192 ctx->rand_data_valid = 0;
193
194 hexdump("Output DT: ", ctx->DT, DEFAULT_BLK_SZ);
195 hexdump("Output I: ", ctx->I, DEFAULT_BLK_SZ);
196 hexdump("Output V: ", ctx->V, DEFAULT_BLK_SZ);
197 hexdump("New Random Data: ", ctx->rand_data, DEFAULT_BLK_SZ);
198
199 return 0;
200}
201
202/* Our exported functions */
203int get_prng_bytes(char *buf, int nbytes, struct prng_context *ctx)
204{
205 unsigned long flags;
206 unsigned char *ptr = buf;
207 unsigned int byte_count = (unsigned int)nbytes;
208 int err;
209
210
211 if (nbytes < 0)
212 return -EINVAL;
213
214 spin_lock_irqsave(&ctx->prng_lock, flags);
215
216 err = -EFAULT;
217 if (ctx->flags & PRNG_NEED_RESET)
218 goto done;
219
220 /*
221 * If the FIXED_SIZE flag is on, only return whole blocks of
222 * pseudo random data
223 */
224 err = -EINVAL;
225 if (ctx->flags & PRNG_FIXED_SIZE) {
226 if (nbytes < DEFAULT_BLK_SZ)
227 goto done;
228 byte_count = DEFAULT_BLK_SZ;
229 }
230
231 err = byte_count;
232
233 dbgprint(KERN_CRIT "getting %d random bytes for context %p\n",byte_count, ctx);
234
235
236remainder:
237 if (ctx->rand_data_valid == DEFAULT_BLK_SZ) {
238 if (_get_more_prng_bytes(ctx) < 0) {
239 memset(buf, 0, nbytes);
240 err = -EFAULT;
241 goto done;
242 }
243 }
244
245 /*
246 * Copy up to the next whole block size
247 */
248 if (byte_count < DEFAULT_BLK_SZ) {
249 for (;ctx->rand_data_valid < DEFAULT_BLK_SZ; ctx->rand_data_valid++) {
250 *ptr = ctx->rand_data[ctx->rand_data_valid];
251 ptr++;
252 byte_count--;
253 if (byte_count == 0)
254 goto done;
255 }
256 }
257
258 /*
259 * Now copy whole blocks
260 */
261 for(;byte_count >= DEFAULT_BLK_SZ; byte_count -= DEFAULT_BLK_SZ) {
262 if (_get_more_prng_bytes(ctx) < 0) {
263 memset(buf, 0, nbytes);
264 err = -1;
265 goto done;
266 }
267 memcpy(ptr, ctx->rand_data, DEFAULT_BLK_SZ);
268 ctx->rand_data_valid += DEFAULT_BLK_SZ;
269 ptr += DEFAULT_BLK_SZ;
270 }
271
272 /*
273 * Now copy any extra partial data
274 */
275 if (byte_count)
276 goto remainder;
277
278done:
279 spin_unlock_irqrestore(&ctx->prng_lock, flags);
280 dbgprint(KERN_CRIT "returning %d from get_prng_bytes in context %p\n",err, ctx);
281 return err;
282}
283EXPORT_SYMBOL_GPL(get_prng_bytes);
284
285struct prng_context *alloc_prng_context(void)
286{
287 struct prng_context *ctx=kzalloc(sizeof(struct prng_context), GFP_KERNEL);
288
289 spin_lock_init(&ctx->prng_lock);
290
291 if (reset_prng_context(ctx, NULL, NULL, NULL, NULL)) {
292 kfree(ctx);
293 ctx = NULL;
294 }
295
296 dbgprint(KERN_CRIT "returning context %p\n",ctx);
297 return ctx;
298}
299
300EXPORT_SYMBOL_GPL(alloc_prng_context);
301
302void free_prng_context(struct prng_context *ctx)
303{
304 crypto_free_blkcipher(ctx->tfm);
305 kfree(ctx);
306}
307EXPORT_SYMBOL_GPL(free_prng_context);
308
309int reset_prng_context(struct prng_context *ctx,
310 unsigned char *key, unsigned char *iv,
311 unsigned char *V, unsigned char *DT)
312{
313 int ret;
314 int iv_len;
315 int rc = -EFAULT;
316
317 spin_lock(&ctx->prng_lock);
318 ctx->flags |= PRNG_NEED_RESET;
319
320 if (key)
321 memcpy(ctx->prng_key,key,strlen(ctx->prng_key));
322 else
323 ctx->prng_key = DEFAULT_PRNG_KEY;
324
325 if (iv)
326 memcpy(ctx->prng_iv,iv, strlen(ctx->prng_iv));
327 else
328 ctx->prng_iv = DEFAULT_PRNG_IV;
329
330 if (V)
331 memcpy(ctx->V,V,DEFAULT_BLK_SZ);
332 else
333 memcpy(ctx->V,DEFAULT_V_SEED,DEFAULT_BLK_SZ);
334
335 if (DT)
336 memcpy(ctx->DT, DT, DEFAULT_BLK_SZ);
337 else
338 memset(ctx->DT, 0, DEFAULT_BLK_SZ);
339
340 memset(ctx->rand_data,0,DEFAULT_BLK_SZ);
341 memset(ctx->last_rand_data,0,DEFAULT_BLK_SZ);
342
343 if (ctx->tfm)
344 crypto_free_blkcipher(ctx->tfm);
345
346 ctx->tfm = crypto_alloc_blkcipher("rfc3686(ctr(aes))",0,0);
347 if (!ctx->tfm) {
348 dbgprint(KERN_CRIT "Failed to alloc crypto tfm for context %p\n",ctx->tfm);
349 goto out;
350 }
351
352 ctx->rand_data_valid = DEFAULT_BLK_SZ;
353
354 ret = crypto_blkcipher_setkey(ctx->tfm, ctx->prng_key, strlen(ctx->prng_key));
355 if (ret) {
356 dbgprint(KERN_CRIT "PRNG: setkey() failed flags=%x\n",
357 crypto_blkcipher_get_flags(ctx->tfm));
358 crypto_free_blkcipher(ctx->tfm);
359 goto out;
360 }
361
362 iv_len = crypto_blkcipher_ivsize(ctx->tfm);
363 if (iv_len) {
364 crypto_blkcipher_set_iv(ctx->tfm, ctx->prng_iv, iv_len);
365 }
366 rc = 0;
367 ctx->flags &= ~PRNG_NEED_RESET;
368out:
369 spin_unlock(&ctx->prng_lock);
370
371 return rc;
372
373}
374EXPORT_SYMBOL_GPL(reset_prng_context);
375
376/* Module initalization */
377static int __init prng_mod_init(void)
378{
379
380#ifdef TEST_PRNG_ON_START
381 int i;
382 unsigned char tmpbuf[DEFAULT_BLK_SZ];
383
384 struct prng_context *ctx = alloc_prng_context();
385 if (ctx == NULL)
386 return -EFAULT;
387 for (i=0;i<16;i++) {
388 if (get_prng_bytes(tmpbuf, DEFAULT_BLK_SZ, ctx) < 0) {
389 free_prng_context(ctx);
390 return -EFAULT;
391 }
392 }
393 free_prng_context(ctx);
394#endif
395
396 return 0;
397}
398
399static void __exit prng_mod_fini(void)
400{
401 return;
402}
403
404MODULE_LICENSE("GPL");
405MODULE_DESCRIPTION("Software Pseudo Random Number Generator");
406MODULE_AUTHOR("Neil Horman <nhorman@tuxdriver.com>");
407module_param(dbg, int, 0);
408MODULE_PARM_DESC(dbg, "Boolean to enable debugging (0/1 == off/on)");
409module_init(prng_mod_init);
410module_exit(prng_mod_fini);
diff --git a/crypto/prng.h b/crypto/prng.h
new file mode 100644
index 000000000000..1ac9be5009b7
--- /dev/null
+++ b/crypto/prng.h
@@ -0,0 +1,27 @@
1/*
2 * PRNG: Pseudo Random Number Generator
3 *
4 * (C) Neil Horman <nhorman@tuxdriver.com>
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * any later version.
10 *
11 *
12 */
13
14#ifndef _PRNG_H_
15#define _PRNG_H_
16struct prng_context;
17
18int get_prng_bytes(char *buf, int nbytes, struct prng_context *ctx);
19struct prng_context *alloc_prng_context(void);
20int reset_prng_context(struct prng_context *ctx,
21 unsigned char *key, unsigned char *iv,
22 unsigned char *V,
23 unsigned char *DT);
24void free_prng_context(struct prng_context *ctx);
25
26#endif
27