prng.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410
  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. #include <linux/err.h>
  16. #include <linux/init.h>
  17. #include <linux/module.h>
  18. #include <linux/mm.h>
  19. #include <linux/slab.h>
  20. #include <linux/fs.h>
  21. #include <linux/scatterlist.h>
  22. #include <linux/string.h>
  23. #include <linux/crypto.h>
  24. #include <linux/highmem.h>
  25. #include <linux/moduleparam.h>
  26. #include <linux/jiffies.h>
  27. #include <linux/timex.h>
  28. #include <linux/interrupt.h>
  29. #include <linux/miscdevice.h>
  30. #include "prng.h"
  31. #define TEST_PRNG_ON_START 0
  32. #define DEFAULT_PRNG_KEY "0123456789abcdef1011"
  33. #define DEFAULT_PRNG_KSZ 20
  34. #define DEFAULT_PRNG_IV "defaultv"
  35. #define DEFAULT_PRNG_IVSZ 8
  36. #define DEFAULT_BLK_SZ 16
  37. #define DEFAULT_V_SEED "zaybxcwdveuftgsh"
  38. /*
  39. * Flags for the prng_context flags field
  40. */
  41. #define PRNG_FIXED_SIZE 0x1
  42. #define PRNG_NEED_RESET 0x2
  43. /*
  44. * Note: DT is our counter value
  45. * I is our intermediate value
  46. * V is our seed vector
  47. * See http://csrc.nist.gov/groups/STM/cavp/documents/rng/931rngext.pdf
  48. * for implementation details
  49. */
  50. struct prng_context {
  51. char *prng_key;
  52. char *prng_iv;
  53. spinlock_t prng_lock;
  54. unsigned char rand_data[DEFAULT_BLK_SZ];
  55. unsigned char last_rand_data[DEFAULT_BLK_SZ];
  56. unsigned char DT[DEFAULT_BLK_SZ];
  57. unsigned char I[DEFAULT_BLK_SZ];
  58. unsigned char V[DEFAULT_BLK_SZ];
  59. u32 rand_data_valid;
  60. struct crypto_blkcipher *tfm;
  61. u32 flags;
  62. };
  63. static int dbg;
  64. static void hexdump(char *note, unsigned char *buf, unsigned int len)
  65. {
  66. if (dbg) {
  67. printk(KERN_CRIT "%s", note);
  68. print_hex_dump(KERN_CONT, "", DUMP_PREFIX_OFFSET,
  69. 16, 1,
  70. buf, len, false);
  71. }
  72. }
  73. #define dbgprint(format, args...) do {if(dbg) printk(format, ##args);} while(0)
  74. static void xor_vectors(unsigned char *in1, unsigned char *in2,
  75. unsigned char *out, unsigned int size)
  76. {
  77. int i;
  78. for (i=0;i<size;i++)
  79. out[i] = in1[i] ^ in2[i];
  80. }
  81. /*
  82. * Returns DEFAULT_BLK_SZ bytes of random data per call
  83. * returns 0 if generation succeded, <0 if something went wrong
  84. */
  85. static int _get_more_prng_bytes(struct prng_context *ctx)
  86. {
  87. int i;
  88. struct blkcipher_desc desc;
  89. struct scatterlist sg_in, sg_out;
  90. int ret;
  91. unsigned char tmp[DEFAULT_BLK_SZ];
  92. desc.tfm = ctx->tfm;
  93. desc.flags = 0;
  94. dbgprint(KERN_CRIT "Calling _get_more_prng_bytes for context %p\n",ctx);
  95. hexdump("Input DT: ", ctx->DT, DEFAULT_BLK_SZ);
  96. hexdump("Input I: ", ctx->I, DEFAULT_BLK_SZ);
  97. hexdump("Input V: ", ctx->V, DEFAULT_BLK_SZ);
  98. /*
  99. * This algorithm is a 3 stage state machine
  100. */
  101. for (i=0;i<3;i++) {
  102. desc.tfm = ctx->tfm;
  103. desc.flags = 0;
  104. switch (i) {
  105. case 0:
  106. /*
  107. * Start by encrypting the counter value
  108. * This gives us an intermediate value I
  109. */
  110. memcpy(tmp, ctx->DT, DEFAULT_BLK_SZ);
  111. sg_init_one(&sg_out, &ctx->I[0], DEFAULT_BLK_SZ);
  112. hexdump("tmp stage 0: ", tmp, DEFAULT_BLK_SZ);
  113. break;
  114. case 1:
  115. /*
  116. * Next xor I with our secret vector V
  117. * encrypt that result to obtain our
  118. * pseudo random data which we output
  119. */
  120. xor_vectors(ctx->I, ctx->V, tmp, DEFAULT_BLK_SZ);
  121. sg_init_one(&sg_out, &ctx->rand_data[0], DEFAULT_BLK_SZ);
  122. hexdump("tmp stage 1: ", tmp, DEFAULT_BLK_SZ);
  123. break;
  124. case 2:
  125. /*
  126. * First check that we didn't produce the same random data
  127. * that we did last time around through this
  128. */
  129. if (!memcmp(ctx->rand_data, ctx->last_rand_data, DEFAULT_BLK_SZ)) {
  130. printk(KERN_ERR "ctx %p Failed repetition check!\n",
  131. ctx);
  132. ctx->flags |= PRNG_NEED_RESET;
  133. return -1;
  134. }
  135. memcpy(ctx->last_rand_data, ctx->rand_data, DEFAULT_BLK_SZ);
  136. /*
  137. * Lastly xor the random data with I
  138. * and encrypt that to obtain a new secret vector V
  139. */
  140. xor_vectors(ctx->rand_data, ctx->I, tmp, DEFAULT_BLK_SZ);
  141. sg_init_one(&sg_out, &ctx->V[0], DEFAULT_BLK_SZ);
  142. hexdump("tmp stage 2: ", tmp, DEFAULT_BLK_SZ);
  143. break;
  144. }
  145. /* Initialize our input buffer */
  146. sg_init_one(&sg_in, &tmp[0], DEFAULT_BLK_SZ);
  147. /* do the encryption */
  148. ret = crypto_blkcipher_encrypt(&desc, &sg_out, &sg_in, DEFAULT_BLK_SZ);
  149. /* And check the result */
  150. if (ret) {
  151. dbgprint(KERN_CRIT "Encryption of new block failed for context %p\n",ctx);
  152. ctx->rand_data_valid = DEFAULT_BLK_SZ;
  153. return -1;
  154. }
  155. }
  156. /*
  157. * Now update our DT value
  158. */
  159. for (i=DEFAULT_BLK_SZ-1;i>0;i--) {
  160. ctx->DT[i] = ctx->DT[i-1];
  161. }
  162. ctx->DT[0] += 1;
  163. dbgprint("Returning new block for context %p\n",ctx);
  164. ctx->rand_data_valid = 0;
  165. hexdump("Output DT: ", ctx->DT, DEFAULT_BLK_SZ);
  166. hexdump("Output I: ", ctx->I, DEFAULT_BLK_SZ);
  167. hexdump("Output V: ", ctx->V, DEFAULT_BLK_SZ);
  168. hexdump("New Random Data: ", ctx->rand_data, DEFAULT_BLK_SZ);
  169. return 0;
  170. }
  171. /* Our exported functions */
  172. int get_prng_bytes(char *buf, int nbytes, struct prng_context *ctx)
  173. {
  174. unsigned long flags;
  175. unsigned char *ptr = buf;
  176. unsigned int byte_count = (unsigned int)nbytes;
  177. int err;
  178. if (nbytes < 0)
  179. return -EINVAL;
  180. spin_lock_irqsave(&ctx->prng_lock, flags);
  181. err = -EFAULT;
  182. if (ctx->flags & PRNG_NEED_RESET)
  183. goto done;
  184. /*
  185. * If the FIXED_SIZE flag is on, only return whole blocks of
  186. * pseudo random data
  187. */
  188. err = -EINVAL;
  189. if (ctx->flags & PRNG_FIXED_SIZE) {
  190. if (nbytes < DEFAULT_BLK_SZ)
  191. goto done;
  192. byte_count = DEFAULT_BLK_SZ;
  193. }
  194. err = byte_count;
  195. dbgprint(KERN_CRIT "getting %d random bytes for context %p\n",byte_count, ctx);
  196. remainder:
  197. if (ctx->rand_data_valid == DEFAULT_BLK_SZ) {
  198. if (_get_more_prng_bytes(ctx) < 0) {
  199. memset(buf, 0, nbytes);
  200. err = -EFAULT;
  201. goto done;
  202. }
  203. }
  204. /*
  205. * Copy up to the next whole block size
  206. */
  207. if (byte_count < DEFAULT_BLK_SZ) {
  208. for (;ctx->rand_data_valid < DEFAULT_BLK_SZ; ctx->rand_data_valid++) {
  209. *ptr = ctx->rand_data[ctx->rand_data_valid];
  210. ptr++;
  211. byte_count--;
  212. if (byte_count == 0)
  213. goto done;
  214. }
  215. }
  216. /*
  217. * Now copy whole blocks
  218. */
  219. for(;byte_count >= DEFAULT_BLK_SZ; byte_count -= DEFAULT_BLK_SZ) {
  220. if (_get_more_prng_bytes(ctx) < 0) {
  221. memset(buf, 0, nbytes);
  222. err = -1;
  223. goto done;
  224. }
  225. memcpy(ptr, ctx->rand_data, DEFAULT_BLK_SZ);
  226. ctx->rand_data_valid += DEFAULT_BLK_SZ;
  227. ptr += DEFAULT_BLK_SZ;
  228. }
  229. /*
  230. * Now copy any extra partial data
  231. */
  232. if (byte_count)
  233. goto remainder;
  234. done:
  235. spin_unlock_irqrestore(&ctx->prng_lock, flags);
  236. dbgprint(KERN_CRIT "returning %d from get_prng_bytes in context %p\n",err, ctx);
  237. return err;
  238. }
  239. EXPORT_SYMBOL_GPL(get_prng_bytes);
  240. struct prng_context *alloc_prng_context(void)
  241. {
  242. struct prng_context *ctx=kzalloc(sizeof(struct prng_context), GFP_KERNEL);
  243. spin_lock_init(&ctx->prng_lock);
  244. if (reset_prng_context(ctx, NULL, NULL, NULL, NULL)) {
  245. kfree(ctx);
  246. ctx = NULL;
  247. }
  248. dbgprint(KERN_CRIT "returning context %p\n",ctx);
  249. return ctx;
  250. }
  251. EXPORT_SYMBOL_GPL(alloc_prng_context);
  252. void free_prng_context(struct prng_context *ctx)
  253. {
  254. crypto_free_blkcipher(ctx->tfm);
  255. kfree(ctx);
  256. }
  257. EXPORT_SYMBOL_GPL(free_prng_context);
  258. int reset_prng_context(struct prng_context *ctx,
  259. unsigned char *key, unsigned char *iv,
  260. unsigned char *V, unsigned char *DT)
  261. {
  262. int ret;
  263. int iv_len;
  264. int rc = -EFAULT;
  265. spin_lock(&ctx->prng_lock);
  266. ctx->flags |= PRNG_NEED_RESET;
  267. if (key)
  268. memcpy(ctx->prng_key,key,strlen(ctx->prng_key));
  269. else
  270. ctx->prng_key = DEFAULT_PRNG_KEY;
  271. if (iv)
  272. memcpy(ctx->prng_iv,iv, strlen(ctx->prng_iv));
  273. else
  274. ctx->prng_iv = DEFAULT_PRNG_IV;
  275. if (V)
  276. memcpy(ctx->V,V,DEFAULT_BLK_SZ);
  277. else
  278. memcpy(ctx->V,DEFAULT_V_SEED,DEFAULT_BLK_SZ);
  279. if (DT)
  280. memcpy(ctx->DT, DT, DEFAULT_BLK_SZ);
  281. else
  282. memset(ctx->DT, 0, DEFAULT_BLK_SZ);
  283. memset(ctx->rand_data,0,DEFAULT_BLK_SZ);
  284. memset(ctx->last_rand_data,0,DEFAULT_BLK_SZ);
  285. if (ctx->tfm)
  286. crypto_free_blkcipher(ctx->tfm);
  287. ctx->tfm = crypto_alloc_blkcipher("rfc3686(ctr(aes))",0,0);
  288. if (!ctx->tfm) {
  289. dbgprint(KERN_CRIT "Failed to alloc crypto tfm for context %p\n",ctx->tfm);
  290. goto out;
  291. }
  292. ctx->rand_data_valid = DEFAULT_BLK_SZ;
  293. ret = crypto_blkcipher_setkey(ctx->tfm, ctx->prng_key, strlen(ctx->prng_key));
  294. if (ret) {
  295. dbgprint(KERN_CRIT "PRNG: setkey() failed flags=%x\n",
  296. crypto_blkcipher_get_flags(ctx->tfm));
  297. crypto_free_blkcipher(ctx->tfm);
  298. goto out;
  299. }
  300. iv_len = crypto_blkcipher_ivsize(ctx->tfm);
  301. if (iv_len) {
  302. crypto_blkcipher_set_iv(ctx->tfm, ctx->prng_iv, iv_len);
  303. }
  304. rc = 0;
  305. ctx->flags &= ~PRNG_NEED_RESET;
  306. out:
  307. spin_unlock(&ctx->prng_lock);
  308. return rc;
  309. }
  310. EXPORT_SYMBOL_GPL(reset_prng_context);
  311. /* Module initalization */
  312. static int __init prng_mod_init(void)
  313. {
  314. #ifdef TEST_PRNG_ON_START
  315. int i;
  316. unsigned char tmpbuf[DEFAULT_BLK_SZ];
  317. struct prng_context *ctx = alloc_prng_context();
  318. if (ctx == NULL)
  319. return -EFAULT;
  320. for (i=0;i<16;i++) {
  321. if (get_prng_bytes(tmpbuf, DEFAULT_BLK_SZ, ctx) < 0) {
  322. free_prng_context(ctx);
  323. return -EFAULT;
  324. }
  325. }
  326. free_prng_context(ctx);
  327. #endif
  328. return 0;
  329. }
  330. static void __exit prng_mod_fini(void)
  331. {
  332. return;
  333. }
  334. MODULE_LICENSE("GPL");
  335. MODULE_DESCRIPTION("Software Pseudo Random Number Generator");
  336. MODULE_AUTHOR("Neil Horman <nhorman@tuxdriver.com>");
  337. module_param(dbg, int, 0);
  338. MODULE_PARM_DESC(dbg, "Boolean to enable debugging (0/1 == off/on)");
  339. module_init(prng_mod_init);
  340. module_exit(prng_mod_fini);