diff options
author | Neil Horman <nhorman@tuxdriver.com> | 2008-08-14 08:15:52 -0400 |
---|---|---|
committer | Herbert Xu <herbert@gondor.apana.org.au> | 2008-08-29 01:50:04 -0400 |
commit | 17f0f4a47df9aea9ee26c939f8057c35e0be1847 (patch) | |
tree | d6c7ff6c93573227a49c9e8fe06c53d97950e4e6 /crypto | |
parent | ccb778e1841ce04b4c10b39f0dd2558ab2c6dcd4 (diff) |
crypto: rng - RNG interface and implementation
This patch adds a random number generator interface as well as a
cryptographic pseudo-random number generator based on AES. 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>
Diffstat (limited to 'crypto')
-rw-r--r-- | crypto/Kconfig | 16 | ||||
-rw-r--r-- | crypto/Makefile | 4 | ||||
-rw-r--r-- | crypto/ansi_cprng.c | 417 | ||||
-rw-r--r-- | crypto/krng.c | 66 | ||||
-rw-r--r-- | crypto/rng.c | 126 |
5 files changed, 628 insertions, 1 deletions
diff --git a/crypto/Kconfig b/crypto/Kconfig index a784c2dce57e..2274293e71e1 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig | |||
@@ -46,6 +46,10 @@ config CRYPTO_HASH | |||
46 | tristate | 46 | tristate |
47 | select CRYPTO_ALGAPI | 47 | select CRYPTO_ALGAPI |
48 | 48 | ||
49 | config CRYPTO_RNG | ||
50 | tristate | ||
51 | select CRYPTO_ALGAPI | ||
52 | |||
49 | config CRYPTO_MANAGER | 53 | config CRYPTO_MANAGER |
50 | tristate "Cryptographic algorithm manager" | 54 | tristate "Cryptographic algorithm manager" |
51 | select CRYPTO_AEAD | 55 | select CRYPTO_AEAD |
@@ -689,6 +693,18 @@ config CRYPTO_LZO | |||
689 | help | 693 | help |
690 | This is the LZO algorithm. | 694 | This is the LZO algorithm. |
691 | 695 | ||
696 | comment "Random Number Generation" | ||
697 | |||
698 | config CRYPTO_ANSI_CPRNG | ||
699 | tristate "Pseudo Random Number Generation for Cryptographic modules" | ||
700 | select CRYPTO_AES | ||
701 | select CRYPTO_RNG | ||
702 | select CRYPTO_FIPS | ||
703 | help | ||
704 | This option enables the generic pseudo random number generator | ||
705 | for cryptographic modules. Uses the Algorithm specified in | ||
706 | ANSI X9.31 A.2.4 | ||
707 | |||
692 | source "drivers/crypto/Kconfig" | 708 | source "drivers/crypto/Kconfig" |
693 | 709 | ||
694 | endif # if CRYPTO | 710 | endif # if CRYPTO |
diff --git a/crypto/Makefile b/crypto/Makefile index 8a27b834ea76..5862b807334e 100644 --- a/crypto/Makefile +++ b/crypto/Makefile | |||
@@ -73,7 +73,9 @@ obj-$(CONFIG_CRYPTO_MICHAEL_MIC) += michael_mic.o | |||
73 | obj-$(CONFIG_CRYPTO_CRC32C) += crc32c.o | 73 | obj-$(CONFIG_CRYPTO_CRC32C) += crc32c.o |
74 | obj-$(CONFIG_CRYPTO_AUTHENC) += authenc.o | 74 | obj-$(CONFIG_CRYPTO_AUTHENC) += authenc.o |
75 | obj-$(CONFIG_CRYPTO_LZO) += lzo.o | 75 | obj-$(CONFIG_CRYPTO_LZO) += lzo.o |
76 | 76 | obj-$(CONFIG_CRYPTO_RNG) += rng.o | |
77 | obj-$(CONFIG_CRYPTO_RNG) += krng.o | ||
78 | obj-$(CONFIG_CRYPTO_ANSI_CPRNG) += ansi_cprng.o | ||
77 | obj-$(CONFIG_CRYPTO_TEST) += tcrypt.o | 79 | obj-$(CONFIG_CRYPTO_TEST) += tcrypt.o |
78 | 80 | ||
79 | # | 81 | # |
diff --git a/crypto/ansi_cprng.c b/crypto/ansi_cprng.c new file mode 100644 index 000000000000..72db0fd763cc --- /dev/null +++ b/crypto/ansi_cprng.c | |||
@@ -0,0 +1,417 @@ | |||
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 | ||
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 <crypto/internal/rng.h> | ||
17 | #include <linux/err.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/moduleparam.h> | ||
21 | #include <linux/string.h> | ||
22 | |||
23 | #include "internal.h" | ||
24 | |||
25 | #define DEFAULT_PRNG_KEY "0123456789abcdef" | ||
26 | #define DEFAULT_PRNG_KSZ 16 | ||
27 | #define DEFAULT_BLK_SZ 16 | ||
28 | #define DEFAULT_V_SEED "zaybxcwdveuftgsh" | ||
29 | |||
30 | /* | ||
31 | * Flags for the prng_context flags field | ||
32 | */ | ||
33 | |||
34 | #define PRNG_FIXED_SIZE 0x1 | ||
35 | #define PRNG_NEED_RESET 0x2 | ||
36 | |||
37 | /* | ||
38 | * Note: DT is our counter value | ||
39 | * I is our intermediate value | ||
40 | * V is our seed vector | ||
41 | * See http://csrc.nist.gov/groups/STM/cavp/documents/rng/931rngext.pdf | ||
42 | * for implementation details | ||
43 | */ | ||
44 | |||
45 | |||
46 | struct prng_context { | ||
47 | spinlock_t prng_lock; | ||
48 | unsigned char rand_data[DEFAULT_BLK_SZ]; | ||
49 | unsigned char last_rand_data[DEFAULT_BLK_SZ]; | ||
50 | unsigned char DT[DEFAULT_BLK_SZ]; | ||
51 | unsigned char I[DEFAULT_BLK_SZ]; | ||
52 | unsigned char V[DEFAULT_BLK_SZ]; | ||
53 | u32 rand_data_valid; | ||
54 | struct crypto_cipher *tfm; | ||
55 | u32 flags; | ||
56 | }; | ||
57 | |||
58 | static int dbg; | ||
59 | |||
60 | static void hexdump(char *note, unsigned char *buf, unsigned int len) | ||
61 | { | ||
62 | if (dbg) { | ||
63 | printk(KERN_CRIT "%s", note); | ||
64 | print_hex_dump(KERN_CONT, "", DUMP_PREFIX_OFFSET, | ||
65 | 16, 1, | ||
66 | buf, len, false); | ||
67 | } | ||
68 | } | ||
69 | |||
70 | #define dbgprint(format, args...) do {\ | ||
71 | if (dbg)\ | ||
72 | printk(format, ##args);\ | ||
73 | } while (0) | ||
74 | |||
75 | static void xor_vectors(unsigned char *in1, unsigned char *in2, | ||
76 | unsigned char *out, unsigned int size) | ||
77 | { | ||
78 | int i; | ||
79 | |||
80 | for (i = 0; i < size; i++) | ||
81 | out[i] = in1[i] ^ in2[i]; | ||
82 | |||
83 | } | ||
84 | /* | ||
85 | * Returns DEFAULT_BLK_SZ bytes of random data per call | ||
86 | * returns 0 if generation succeded, <0 if something went wrong | ||
87 | */ | ||
88 | static int _get_more_prng_bytes(struct prng_context *ctx) | ||
89 | { | ||
90 | int i; | ||
91 | unsigned char tmp[DEFAULT_BLK_SZ]; | ||
92 | unsigned char *output = NULL; | ||
93 | |||
94 | |||
95 | dbgprint(KERN_CRIT "Calling _get_more_prng_bytes for context %p\n", | ||
96 | ctx); | ||
97 | |||
98 | hexdump("Input DT: ", ctx->DT, DEFAULT_BLK_SZ); | ||
99 | hexdump("Input I: ", ctx->I, DEFAULT_BLK_SZ); | ||
100 | hexdump("Input V: ", ctx->V, DEFAULT_BLK_SZ); | ||
101 | |||
102 | /* | ||
103 | * This algorithm is a 3 stage state machine | ||
104 | */ | ||
105 | for (i = 0; i < 3; i++) { | ||
106 | |||
107 | switch (i) { | ||
108 | case 0: | ||
109 | /* | ||
110 | * Start by encrypting the counter value | ||
111 | * This gives us an intermediate value I | ||
112 | */ | ||
113 | memcpy(tmp, ctx->DT, DEFAULT_BLK_SZ); | ||
114 | output = ctx->I; | ||
115 | hexdump("tmp stage 0: ", tmp, DEFAULT_BLK_SZ); | ||
116 | break; | ||
117 | case 1: | ||
118 | |||
119 | /* | ||
120 | * Next xor I with our secret vector V | ||
121 | * encrypt that result to obtain our | ||
122 | * pseudo random data which we output | ||
123 | */ | ||
124 | xor_vectors(ctx->I, ctx->V, tmp, DEFAULT_BLK_SZ); | ||
125 | hexdump("tmp stage 1: ", tmp, DEFAULT_BLK_SZ); | ||
126 | output = ctx->rand_data; | ||
127 | break; | ||
128 | case 2: | ||
129 | /* | ||
130 | * First check that we didn't produce the same | ||
131 | * random data that we did last time around through this | ||
132 | */ | ||
133 | if (!memcmp(ctx->rand_data, ctx->last_rand_data, | ||
134 | DEFAULT_BLK_SZ)) { | ||
135 | printk(KERN_ERR | ||
136 | "ctx %p Failed repetition check!\n", | ||
137 | ctx); | ||
138 | ctx->flags |= PRNG_NEED_RESET; | ||
139 | return -EINVAL; | ||
140 | } | ||
141 | memcpy(ctx->last_rand_data, ctx->rand_data, | ||
142 | DEFAULT_BLK_SZ); | ||
143 | |||
144 | /* | ||
145 | * Lastly xor the random data with I | ||
146 | * and encrypt that to obtain a new secret vector V | ||
147 | */ | ||
148 | xor_vectors(ctx->rand_data, ctx->I, tmp, | ||
149 | DEFAULT_BLK_SZ); | ||
150 | output = ctx->V; | ||
151 | hexdump("tmp stage 2: ", tmp, DEFAULT_BLK_SZ); | ||
152 | break; | ||
153 | } | ||
154 | |||
155 | |||
156 | /* do the encryption */ | ||
157 | crypto_cipher_encrypt_one(ctx->tfm, output, tmp); | ||
158 | |||
159 | } | ||
160 | |||
161 | /* | ||
162 | * Now update our DT value | ||
163 | */ | ||
164 | for (i = 0; i < DEFAULT_BLK_SZ; i++) { | ||
165 | ctx->DT[i] += 1; | ||
166 | if (ctx->DT[i] != 0) | ||
167 | break; | ||
168 | } | ||
169 | |||
170 | dbgprint("Returning new block for context %p\n", ctx); | ||
171 | ctx->rand_data_valid = 0; | ||
172 | |||
173 | hexdump("Output DT: ", ctx->DT, DEFAULT_BLK_SZ); | ||
174 | hexdump("Output I: ", ctx->I, DEFAULT_BLK_SZ); | ||
175 | hexdump("Output V: ", ctx->V, DEFAULT_BLK_SZ); | ||
176 | hexdump("New Random Data: ", ctx->rand_data, DEFAULT_BLK_SZ); | ||
177 | |||
178 | return 0; | ||
179 | } | ||
180 | |||
181 | /* Our exported functions */ | ||
182 | static int get_prng_bytes(char *buf, size_t nbytes, struct prng_context *ctx) | ||
183 | { | ||
184 | unsigned long flags; | ||
185 | unsigned char *ptr = buf; | ||
186 | unsigned int byte_count = (unsigned int)nbytes; | ||
187 | int err; | ||
188 | |||
189 | |||
190 | if (nbytes < 0) | ||
191 | return -EINVAL; | ||
192 | |||
193 | spin_lock_irqsave(&ctx->prng_lock, flags); | ||
194 | |||
195 | err = -EINVAL; | ||
196 | if (ctx->flags & PRNG_NEED_RESET) | ||
197 | goto done; | ||
198 | |||
199 | /* | ||
200 | * If the FIXED_SIZE flag is on, only return whole blocks of | ||
201 | * pseudo random data | ||
202 | */ | ||
203 | err = -EINVAL; | ||
204 | if (ctx->flags & PRNG_FIXED_SIZE) { | ||
205 | if (nbytes < DEFAULT_BLK_SZ) | ||
206 | goto done; | ||
207 | byte_count = DEFAULT_BLK_SZ; | ||
208 | } | ||
209 | |||
210 | err = byte_count; | ||
211 | |||
212 | dbgprint(KERN_CRIT "getting %d random bytes for context %p\n", | ||
213 | byte_count, ctx); | ||
214 | |||
215 | |||
216 | remainder: | ||
217 | if (ctx->rand_data_valid == DEFAULT_BLK_SZ) { | ||
218 | if (_get_more_prng_bytes(ctx) < 0) { | ||
219 | memset(buf, 0, nbytes); | ||
220 | err = -EINVAL; | ||
221 | goto done; | ||
222 | } | ||
223 | } | ||
224 | |||
225 | /* | ||
226 | * Copy up to the next whole block size | ||
227 | */ | ||
228 | if (byte_count < DEFAULT_BLK_SZ) { | ||
229 | for (; ctx->rand_data_valid < DEFAULT_BLK_SZ; | ||
230 | ctx->rand_data_valid++) { | ||
231 | *ptr = ctx->rand_data[ctx->rand_data_valid]; | ||
232 | ptr++; | ||
233 | byte_count--; | ||
234 | if (byte_count == 0) | ||
235 | goto done; | ||
236 | } | ||
237 | } | ||
238 | |||
239 | /* | ||
240 | * Now copy whole blocks | ||
241 | */ | ||
242 | for (; byte_count >= DEFAULT_BLK_SZ; byte_count -= DEFAULT_BLK_SZ) { | ||
243 | if (_get_more_prng_bytes(ctx) < 0) { | ||
244 | memset(buf, 0, nbytes); | ||
245 | err = -EINVAL; | ||
246 | goto done; | ||
247 | } | ||
248 | memcpy(ptr, ctx->rand_data, DEFAULT_BLK_SZ); | ||
249 | ctx->rand_data_valid += DEFAULT_BLK_SZ; | ||
250 | ptr += DEFAULT_BLK_SZ; | ||
251 | } | ||
252 | |||
253 | /* | ||
254 | * Now copy any extra partial data | ||
255 | */ | ||
256 | if (byte_count) | ||
257 | goto remainder; | ||
258 | |||
259 | done: | ||
260 | spin_unlock_irqrestore(&ctx->prng_lock, flags); | ||
261 | dbgprint(KERN_CRIT "returning %d from get_prng_bytes in context %p\n", | ||
262 | err, ctx); | ||
263 | return err; | ||
264 | } | ||
265 | |||
266 | static void free_prng_context(struct prng_context *ctx) | ||
267 | { | ||
268 | crypto_free_cipher(ctx->tfm); | ||
269 | } | ||
270 | |||
271 | static int reset_prng_context(struct prng_context *ctx, | ||
272 | unsigned char *key, size_t klen, | ||
273 | unsigned char *V, unsigned char *DT) | ||
274 | { | ||
275 | int ret; | ||
276 | int rc = -EINVAL; | ||
277 | unsigned char *prng_key; | ||
278 | |||
279 | spin_lock(&ctx->prng_lock); | ||
280 | ctx->flags |= PRNG_NEED_RESET; | ||
281 | |||
282 | prng_key = (key != NULL) ? key : (unsigned char *)DEFAULT_PRNG_KEY; | ||
283 | |||
284 | if (!key) | ||
285 | klen = DEFAULT_PRNG_KSZ; | ||
286 | |||
287 | if (V) | ||
288 | memcpy(ctx->V, V, DEFAULT_BLK_SZ); | ||
289 | else | ||
290 | memcpy(ctx->V, DEFAULT_V_SEED, DEFAULT_BLK_SZ); | ||
291 | |||
292 | if (DT) | ||
293 | memcpy(ctx->DT, DT, DEFAULT_BLK_SZ); | ||
294 | else | ||
295 | memset(ctx->DT, 0, DEFAULT_BLK_SZ); | ||
296 | |||
297 | memset(ctx->rand_data, 0, DEFAULT_BLK_SZ); | ||
298 | memset(ctx->last_rand_data, 0, DEFAULT_BLK_SZ); | ||
299 | |||
300 | if (ctx->tfm) | ||
301 | crypto_free_cipher(ctx->tfm); | ||
302 | |||
303 | ctx->tfm = crypto_alloc_cipher("aes", 0, 0); | ||
304 | if (IS_ERR(ctx->tfm)) { | ||
305 | dbgprint(KERN_CRIT "Failed to alloc tfm for context %p\n", | ||
306 | ctx); | ||
307 | ctx->tfm = NULL; | ||
308 | goto out; | ||
309 | } | ||
310 | |||
311 | ctx->rand_data_valid = DEFAULT_BLK_SZ; | ||
312 | |||
313 | ret = crypto_cipher_setkey(ctx->tfm, prng_key, klen); | ||
314 | if (ret) { | ||
315 | dbgprint(KERN_CRIT "PRNG: setkey() failed flags=%x\n", | ||
316 | crypto_cipher_get_flags(ctx->tfm)); | ||
317 | crypto_free_cipher(ctx->tfm); | ||
318 | goto out; | ||
319 | } | ||
320 | |||
321 | rc = 0; | ||
322 | ctx->flags &= ~PRNG_NEED_RESET; | ||
323 | out: | ||
324 | spin_unlock(&ctx->prng_lock); | ||
325 | |||
326 | return rc; | ||
327 | |||
328 | } | ||
329 | |||
330 | static int cprng_init(struct crypto_tfm *tfm) | ||
331 | { | ||
332 | struct prng_context *ctx = crypto_tfm_ctx(tfm); | ||
333 | |||
334 | spin_lock_init(&ctx->prng_lock); | ||
335 | |||
336 | return reset_prng_context(ctx, NULL, DEFAULT_PRNG_KSZ, NULL, NULL); | ||
337 | } | ||
338 | |||
339 | static void cprng_exit(struct crypto_tfm *tfm) | ||
340 | { | ||
341 | free_prng_context(crypto_tfm_ctx(tfm)); | ||
342 | } | ||
343 | |||
344 | static int cprng_get_random(struct crypto_rng *tfm, u8 *rdata, | ||
345 | unsigned int dlen) | ||
346 | { | ||
347 | struct prng_context *prng = crypto_rng_ctx(tfm); | ||
348 | |||
349 | return get_prng_bytes(rdata, dlen, prng); | ||
350 | } | ||
351 | |||
352 | static int cprng_reset(struct crypto_rng *tfm, u8 *seed, unsigned int slen) | ||
353 | { | ||
354 | struct prng_context *prng = crypto_rng_ctx(tfm); | ||
355 | u8 *key = seed + DEFAULT_PRNG_KSZ; | ||
356 | |||
357 | if (slen < DEFAULT_PRNG_KSZ + DEFAULT_BLK_SZ) | ||
358 | return -EINVAL; | ||
359 | |||
360 | reset_prng_context(prng, key, DEFAULT_PRNG_KSZ, seed, NULL); | ||
361 | |||
362 | if (prng->flags & PRNG_NEED_RESET) | ||
363 | return -EINVAL; | ||
364 | return 0; | ||
365 | } | ||
366 | |||
367 | static struct crypto_alg rng_alg = { | ||
368 | .cra_name = "stdrng", | ||
369 | .cra_driver_name = "ansi_cprng", | ||
370 | .cra_priority = 100, | ||
371 | .cra_flags = CRYPTO_ALG_TYPE_RNG, | ||
372 | .cra_ctxsize = sizeof(struct prng_context), | ||
373 | .cra_type = &crypto_rng_type, | ||
374 | .cra_module = THIS_MODULE, | ||
375 | .cra_list = LIST_HEAD_INIT(rng_alg.cra_list), | ||
376 | .cra_init = cprng_init, | ||
377 | .cra_exit = cprng_exit, | ||
378 | .cra_u = { | ||
379 | .rng = { | ||
380 | .rng_make_random = cprng_get_random, | ||
381 | .rng_reset = cprng_reset, | ||
382 | .seedsize = DEFAULT_PRNG_KSZ + DEFAULT_BLK_SZ, | ||
383 | } | ||
384 | } | ||
385 | }; | ||
386 | |||
387 | |||
388 | /* Module initalization */ | ||
389 | static int __init prng_mod_init(void) | ||
390 | { | ||
391 | int ret = 0; | ||
392 | |||
393 | if (fips_enabled) | ||
394 | rng_alg.cra_priority += 200; | ||
395 | |||
396 | ret = crypto_register_alg(&rng_alg); | ||
397 | |||
398 | if (ret) | ||
399 | goto out; | ||
400 | out: | ||
401 | return 0; | ||
402 | } | ||
403 | |||
404 | static void __exit prng_mod_fini(void) | ||
405 | { | ||
406 | crypto_unregister_alg(&rng_alg); | ||
407 | return; | ||
408 | } | ||
409 | |||
410 | MODULE_LICENSE("GPL"); | ||
411 | MODULE_DESCRIPTION("Software Pseudo Random Number Generator"); | ||
412 | MODULE_AUTHOR("Neil Horman <nhorman@tuxdriver.com>"); | ||
413 | module_param(dbg, int, 0); | ||
414 | MODULE_PARM_DESC(dbg, "Boolean to enable debugging (0/1 == off/on)"); | ||
415 | module_init(prng_mod_init); | ||
416 | module_exit(prng_mod_fini); | ||
417 | MODULE_ALIAS("stdrng"); | ||
diff --git a/crypto/krng.c b/crypto/krng.c new file mode 100644 index 000000000000..4328bb3430ed --- /dev/null +++ b/crypto/krng.c | |||
@@ -0,0 +1,66 @@ | |||
1 | /* | ||
2 | * RNG implementation using standard kernel RNG. | ||
3 | * | ||
4 | * Copyright (c) 2008 Herbert Xu <herbert@gondor.apana.org.au> | ||
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 | #include <crypto/internal/rng.h> | ||
14 | #include <linux/err.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/random.h> | ||
18 | |||
19 | static int krng_get_random(struct crypto_rng *tfm, u8 *rdata, unsigned int dlen) | ||
20 | { | ||
21 | get_random_bytes(rdata, dlen); | ||
22 | return 0; | ||
23 | } | ||
24 | |||
25 | static int krng_reset(struct crypto_rng *tfm, u8 *seed, unsigned int slen) | ||
26 | { | ||
27 | return 0; | ||
28 | } | ||
29 | |||
30 | static struct crypto_alg krng_alg = { | ||
31 | .cra_name = "stdrng", | ||
32 | .cra_driver_name = "krng", | ||
33 | .cra_priority = 200, | ||
34 | .cra_flags = CRYPTO_ALG_TYPE_RNG, | ||
35 | .cra_ctxsize = 0, | ||
36 | .cra_type = &crypto_rng_type, | ||
37 | .cra_module = THIS_MODULE, | ||
38 | .cra_list = LIST_HEAD_INIT(krng_alg.cra_list), | ||
39 | .cra_u = { | ||
40 | .rng = { | ||
41 | .rng_make_random = krng_get_random, | ||
42 | .rng_reset = krng_reset, | ||
43 | .seedsize = 0, | ||
44 | } | ||
45 | } | ||
46 | }; | ||
47 | |||
48 | |||
49 | /* Module initalization */ | ||
50 | static int __init krng_mod_init(void) | ||
51 | { | ||
52 | return crypto_register_alg(&krng_alg); | ||
53 | } | ||
54 | |||
55 | static void __exit krng_mod_fini(void) | ||
56 | { | ||
57 | crypto_unregister_alg(&krng_alg); | ||
58 | return; | ||
59 | } | ||
60 | |||
61 | module_init(krng_mod_init); | ||
62 | module_exit(krng_mod_fini); | ||
63 | |||
64 | MODULE_LICENSE("GPL"); | ||
65 | MODULE_DESCRIPTION("Kernel Random Number Generator"); | ||
66 | MODULE_ALIAS("stdrng"); | ||
diff --git a/crypto/rng.c b/crypto/rng.c new file mode 100644 index 000000000000..6e94bc735578 --- /dev/null +++ b/crypto/rng.c | |||
@@ -0,0 +1,126 @@ | |||
1 | /* | ||
2 | * Cryptographic API. | ||
3 | * | ||
4 | * RNG operations. | ||
5 | * | ||
6 | * Copyright (c) 2008 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 Free | ||
10 | * Software Foundation; either version 2 of the License, or (at your option) | ||
11 | * any later version. | ||
12 | * | ||
13 | */ | ||
14 | |||
15 | #include <asm/atomic.h> | ||
16 | #include <crypto/internal/rng.h> | ||
17 | #include <linux/err.h> | ||
18 | #include <linux/module.h> | ||
19 | #include <linux/mutex.h> | ||
20 | #include <linux/random.h> | ||
21 | #include <linux/seq_file.h> | ||
22 | #include <linux/string.h> | ||
23 | |||
24 | static DEFINE_MUTEX(crypto_default_rng_lock); | ||
25 | struct crypto_rng *crypto_default_rng; | ||
26 | EXPORT_SYMBOL_GPL(crypto_default_rng); | ||
27 | static int crypto_default_rng_refcnt; | ||
28 | |||
29 | static int rngapi_reset(struct crypto_rng *tfm, u8 *seed, unsigned int slen) | ||
30 | { | ||
31 | u8 *buf = NULL; | ||
32 | int err; | ||
33 | |||
34 | if (!seed && slen) { | ||
35 | buf = kmalloc(slen, GFP_KERNEL); | ||
36 | if (!buf) | ||
37 | return -ENOMEM; | ||
38 | |||
39 | get_random_bytes(buf, slen); | ||
40 | seed = buf; | ||
41 | } | ||
42 | |||
43 | err = crypto_rng_alg(tfm)->rng_reset(tfm, seed, slen); | ||
44 | |||
45 | kfree(buf); | ||
46 | return err; | ||
47 | } | ||
48 | |||
49 | static int crypto_init_rng_ops(struct crypto_tfm *tfm, u32 type, u32 mask) | ||
50 | { | ||
51 | struct rng_alg *alg = &tfm->__crt_alg->cra_rng; | ||
52 | struct rng_tfm *ops = &tfm->crt_rng; | ||
53 | |||
54 | ops->rng_gen_random = alg->rng_make_random; | ||
55 | ops->rng_reset = rngapi_reset; | ||
56 | |||
57 | return 0; | ||
58 | } | ||
59 | |||
60 | static void crypto_rng_show(struct seq_file *m, struct crypto_alg *alg) | ||
61 | __attribute__ ((unused)); | ||
62 | static void crypto_rng_show(struct seq_file *m, struct crypto_alg *alg) | ||
63 | { | ||
64 | seq_printf(m, "type : rng\n"); | ||
65 | seq_printf(m, "seedsize : %u\n", alg->cra_rng.seedsize); | ||
66 | } | ||
67 | |||
68 | static unsigned int crypto_rng_ctxsize(struct crypto_alg *alg, u32 type, | ||
69 | u32 mask) | ||
70 | { | ||
71 | return alg->cra_ctxsize; | ||
72 | } | ||
73 | |||
74 | const struct crypto_type crypto_rng_type = { | ||
75 | .ctxsize = crypto_rng_ctxsize, | ||
76 | .init = crypto_init_rng_ops, | ||
77 | #ifdef CONFIG_PROC_FS | ||
78 | .show = crypto_rng_show, | ||
79 | #endif | ||
80 | }; | ||
81 | EXPORT_SYMBOL_GPL(crypto_rng_type); | ||
82 | |||
83 | int crypto_get_default_rng(void) | ||
84 | { | ||
85 | struct crypto_rng *rng; | ||
86 | int err; | ||
87 | |||
88 | mutex_lock(&crypto_default_rng_lock); | ||
89 | if (!crypto_default_rng) { | ||
90 | rng = crypto_alloc_rng("stdrng", 0, 0); | ||
91 | err = PTR_ERR(rng); | ||
92 | if (IS_ERR(rng)) | ||
93 | goto unlock; | ||
94 | |||
95 | err = crypto_rng_reset(rng, NULL, crypto_rng_seedsize(rng)); | ||
96 | if (err) { | ||
97 | crypto_free_rng(rng); | ||
98 | goto unlock; | ||
99 | } | ||
100 | |||
101 | crypto_default_rng = rng; | ||
102 | } | ||
103 | |||
104 | crypto_default_rng_refcnt++; | ||
105 | err = 0; | ||
106 | |||
107 | unlock: | ||
108 | mutex_unlock(&crypto_default_rng_lock); | ||
109 | |||
110 | return err; | ||
111 | } | ||
112 | EXPORT_SYMBOL_GPL(crypto_get_default_rng); | ||
113 | |||
114 | void crypto_put_default_rng(void) | ||
115 | { | ||
116 | mutex_lock(&crypto_default_rng_lock); | ||
117 | if (!--crypto_default_rng_refcnt) { | ||
118 | crypto_free_rng(crypto_default_rng); | ||
119 | crypto_default_rng = NULL; | ||
120 | } | ||
121 | mutex_unlock(&crypto_default_rng_lock); | ||
122 | } | ||
123 | EXPORT_SYMBOL_GPL(crypto_put_default_rng); | ||
124 | |||
125 | MODULE_LICENSE("GPL"); | ||
126 | MODULE_DESCRIPTION("Random Number Genertor"); | ||