prng_fips1861.c
上传用户:lyxiangda
上传日期:2007-01-12
资源大小:3042k
文件大小:16k
源码类别:

CA认证

开发平台:

WINDOWS

  1. /*
  2.  *
  3.  * The contents of this file are subject to the Mozilla Public
  4.  * License Version 1.1 (the "License"); you may not use this file
  5.  * except in compliance with the License. You may obtain a copy of
  6.  * the License at http://www.mozilla.org/MPL/
  7.  * 
  8.  * Software distributed under the License is distributed on an "AS
  9.  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  10.  * implied. See the License for the specific language governing
  11.  * rights and limitations under the License.
  12.  * 
  13.  * The Original Code is the Netscape security libraries.
  14.  * 
  15.  * The Initial Developer of the Original Code is Netscape
  16.  * Communications Corporation.  Portions created by Netscape are 
  17.  * Copyright (C) 1994-2000 Netscape Communications Corporation.  All
  18.  * Rights Reserved.
  19.  * 
  20.  * Contributor(s):
  21.  * 
  22.  * Alternatively, the contents of this file may be used under the
  23.  * terms of the GNU General Public License Version 2 or later (the
  24.  * "GPL"), in which case the provisions of the GPL are applicable 
  25.  * instead of those above.  If you wish to allow use of your 
  26.  * version of this file only under the terms of the GPL and not to
  27.  * allow others to use your version of this file under the MPL,
  28.  * indicate your decision by deleting the provisions above and
  29.  * replace them with the notice and other provisions required by
  30.  * the GPL.  If you do not delete the provisions above, a recipient
  31.  * may use your version of this file under either the MPL or the
  32.  * GPL.
  33.  *
  34.  * $Id: prng_fips1861.c,v 1.7 2000/09/06 23:27:34 mcgreer%netscape.com Exp $
  35.  */
  36. #include "prerr.h"
  37. #include "secerr.h"
  38. #include "prtypes.h"
  39. #include "prinit.h"
  40. #include "blapi.h"
  41. #include "prlock.h"
  42. #include "secitem.h"
  43. #include "sha_fast.h"
  44. /*
  45.  * The minimum amount of seed data required before the generator will
  46.  * provide data.
  47.  * Note that this is a measure of the number of bytes sent to
  48.  * RNG_RandomUpdate, not the actual amount of entropy present in the
  49.  * generator.  Naturally, it is impossible to know (at this level) just
  50.  * how much entropy is present in the provided seed data.  A bare minimum
  51.  * of entropy would be 20 bytes, so by requiring 1K this code is making
  52.  * the tacit assumption that at least 1 byte of pure entropy is provided
  53.  * with every 8 bytes supplied to RNG_RandomUpdate.  The reality of this
  54.  * assumption is left up to the caller.
  55.  */
  56. #define MIN_SEED_COUNT 1024
  57. /*
  58.  * Steps taken from FIPS 186-1 Appendix 3.1
  59.  */
  60. /*
  61.  * According to FIPS 186-1, 160 <= b <= 512
  62.  * For our purposes, we will assume b == 160
  63.  */
  64. #define FIPS_B     160
  65. #define BSIZE      FIPS_B / BITS_PER_BYTE
  66. /*
  67.  * Add two 160-bit numbers represented as arrays of 20 bytes.
  68.  * The numbers are big-endian, MSB first, so addition is done
  69.  * from the end of the buffer to the beginning.
  70.  */
  71. #define ADD_160BIT_PLUS_CARRY(dest, add1, add2, cy) 
  72.     carry = cy; 
  73.     for (i=BSIZE-1; i>=0; --i) { 
  74. carry += add1[i] + add2[i]; 
  75. dest[i] = (PRUint8)carry; 
  76. carry >>= 8; 
  77.     }
  78. #define ADD_160BIT_2(dest, add1, add2) 
  79. ADD_160BIT_PLUS_CARRY(dest, add1, add2, 0)
  80. /*
  81.  * FIPS requires result from Step 3c to be reduced mod q when generating
  82.  * random numbers for DSA.
  83.  * by definition q >= 2^159 + 1, thus xj < 2q
  84.  * thus reducing mod q is simple subtraction when xj > q
  85.  */
  86. #define dsa_reduce_mod_q(xj, q) 
  87.     PORT_Assert(q[0] >= 0x80); 
  88.     if (memcmp(xj,q,BSIZE) > 0) { 
  89. carry = 0; 
  90. for (i=BSIZE-1; i>=0; --i) { 
  91.     carry += (signed int)xj[i] - (signed int)q[i]; 
  92.     xj[i] = (PRUint8)carry; 
  93.     carry >>= 8; 
  94.     }
  95. /*
  96.  * Specialized SHA1-like function.  This function appends zeroes to a 
  97.  * single input block and runs a single instance of the compression function, 
  98.  * as specified in FIPS 186-1 appendix 3.3.
  99.  */
  100. void 
  101. RNG_UpdateAndEnd_FIPS186_1(SHA1Context *ctx, 
  102.                            unsigned char *input, unsigned int inputLen,
  103.                            unsigned char *hashout, unsigned int *pDigestLen, 
  104.                            unsigned int maxDigestLen);
  105. /*
  106.  * Global RNG context
  107.  */ 
  108. struct RNGContextStr {
  109.     PRUint8   XKEY[BSIZE]; /* Seed for next SHA iteration */
  110.     PRUint8   Xj[BSIZE];   /* Output from previous operation */
  111.     PRLock   *lock;        /* Lock to serialize access to global rng */
  112.     PRUint8   avail;       /* # bytes of output available, [0...20] */
  113.     PRUint32  seedCount;   /* number of seed bytes given to generator */
  114.     PRBool    isValid;     /* false if RNG reaches an invalid state */
  115. };
  116. typedef struct RNGContextStr RNGContext;
  117. static RNGContext *globalrng = NULL;
  118. /*
  119.  * Free the global RNG context
  120.  */
  121. static void
  122. freeRNGContext()
  123. {
  124.     PR_DestroyLock(globalrng->lock);
  125.     PORT_ZFree(globalrng, sizeof *globalrng);
  126.     globalrng = NULL;
  127. }
  128. /*
  129.  * Implementation of the algorithm in FIPS 186-1 appendix 3.1, heretofore
  130.  * called alg3_1().  It is assumed a lock for the global rng context has
  131.  * already been acquired.
  132.  * Calling this function with XSEEDj == NULL is equivalent to saying there
  133.  * is no optional user input, which is further equivalent to saying that
  134.  * the optional user input is 0.
  135.  */
  136. static SECStatus
  137. alg_fips186_1_x3_1(RNGContext *rng,
  138.                    const unsigned char *XSEEDj, unsigned char *q)
  139. {
  140.     /* SHA1 context for G(t, XVAL) function */
  141.     SHA1Context sha1cx;
  142.     /* input to hash function */
  143.     PRUint8 XVAL[BSIZE];
  144.     /* store a copy of the output to compare with the previous output */
  145.     PRUint8 x_j[BSIZE];
  146.     /* used by ADD_160BIT macros */
  147.     int i, carry;
  148.     unsigned int len;
  149.     if (!rng->isValid) {
  150. /* RNG has alread entered an invalid state. */
  151. PORT_SetError(SEC_ERROR_INVALID_ARGS);
  152. return SECFailure;
  153.     }
  154.     /* initialize the SHA1 context */
  155.     memset(&sha1cx, 0, sizeof(sha1cx));
  156.     /* 
  157.      * <Step 2> Initialize t, taken care of in SHA-1 (same initial values) 
  158.      */
  159.     SHA1_Begin(&sha1cx);
  160.     /* 
  161.      * <Step 3a> XSEEDj is optional user input
  162.      * 
  163.      * <Step 3b> XVAL = (XKEY + XSEEDj) mod 2^b
  164.      *     :always reduced mod 2^b, since storing as 160-bit value
  165.      */
  166.     if (XSEEDj) {
  167. /* XSEEDj > 0 */
  168. ADD_160BIT_2(XVAL, rng->XKEY, XSEEDj);
  169.     } else {
  170. /* XSEEDj == 0 */
  171. memcpy(XVAL, rng->XKEY, BSIZE);
  172.     }
  173.     /* 
  174.      * <Step 3c> Xj = G(t, XVAL) mod q
  175.      *     :In this code, (mod q) is only understood for DSA ops, 
  176.      *     :not general RNG (what would q be in non-DSA uses?).
  177.      *     :If a q is specified, use it.
  178.      *     :FIPS 186-1 specifies a different padding than the SHA1 180-1
  179.      *     :specification, this function is implemented below.
  180.      */ 
  181.     RNG_UpdateAndEnd_FIPS186_1(&sha1cx, XVAL, BSIZE, x_j, &len, BSIZE);
  182.     if (q != NULL) {
  183. dsa_reduce_mod_q(x_j, q);
  184.     }
  185.     /*     [FIPS 140-1] verify output does not match previous output */
  186.     if (memcmp(x_j, rng->Xj, BSIZE) == 0) {
  187. /* failed FIPS 140-1 continuous RNG condition.  RNG now invalid. */
  188. rng->isValid = PR_FALSE;
  189. return SECFailure;
  190.     }
  191.     /* Xj is the output */
  192.     memcpy(rng->Xj, x_j, BSIZE);
  193.     /* 
  194.      * <Step 3d> XKEY = (1 + XKEY + Xj) mod 2^b
  195.      *     :always reduced mod 2^b, since storing as 160-bit value 
  196.      */
  197.     ADD_160BIT_PLUS_CARRY(rng->XKEY, rng->XKEY, x_j, 1);
  198.     /* Always have a full buffer after executing alg3_1() */
  199.     rng->avail = BSIZE;
  200.     /* housekeeping */
  201.     memset(x_j, 0, BSIZE);
  202.     memset(XVAL, 0, BSIZE);
  203.     return SECSuccess;
  204. }
  205. /* Use NSPR to prevent RNG_RNGInit from being called from separate
  206.  * threads, creating a race condition.
  207.  */
  208. static PRCallOnceType coRNGInit = { 0, 0, 0 };
  209. static PRStatus rng_init(void)
  210. {
  211.     unsigned char bytes[120];
  212.     unsigned int numBytes;
  213.     if (globalrng == NULL) {
  214. /* create a new global RNG context */
  215. globalrng = (RNGContext *)PORT_ZAlloc(sizeof(RNGContext));
  216. if (globalrng == NULL) {
  217.     PORT_SetError(PR_OUT_OF_MEMORY_ERROR);
  218.     return PR_FAILURE;
  219. }
  220. /* create a lock for it */
  221. globalrng->lock = PR_NewLock();
  222. if (globalrng->lock == NULL) {
  223.     PORT_SetError(PR_OUT_OF_MEMORY_ERROR);
  224.     return PR_FAILURE;
  225. }
  226. /* the RNG is in a valid state */
  227. globalrng->isValid = PR_TRUE;
  228. /* Try to get some seed data for the RNG */
  229. numBytes = RNG_GetNoise(bytes, sizeof bytes);
  230. RNG_RandomUpdate(bytes, numBytes);
  231.     }
  232.     return (globalrng != NULL) ? PR_SUCCESS : PR_FAILURE;
  233. }
  234. /*
  235.  * Initialize the global RNG context and give it some seed input taken
  236.  * from the system.  This function is thread-safe and will only allow
  237.  * the global context to be initialized once.  The seed input is likely
  238.  * small, so it is imperative that RNG_RandomUpdate() be called with
  239.  * additional seed data before the generator is used.  A good way to
  240.  * provide the generator with additional entropy is to call
  241.  * RNG_SystemInfoForRNG().  Note that NSS_Init() does exactly that.
  242.  */
  243. SECStatus 
  244. RNG_RNGInit(void)
  245. {
  246.     /* Allow only one call to initialize the context */
  247.     PR_CallOnce(&coRNGInit, rng_init);
  248.     /* Make sure there is a context */
  249.     return (globalrng != NULL) ? PR_SUCCESS : PR_FAILURE;
  250. }
  251. /*
  252. ** Update the global random number generator with more seeding
  253. ** material
  254. */
  255. SECStatus 
  256. prng_RandomUpdate(RNGContext *rng, void *data, size_t bytes, unsigned char *q)
  257. {
  258.     SECStatus rv = SECSuccess;
  259.     unsigned char inputhash[BSIZE];
  260.     /* check for a valid global RNG context */
  261.     PORT_Assert(rng != NULL);
  262.     if (rng == NULL) {
  263. PORT_SetError(SEC_ERROR_INVALID_ARGS);
  264. return SECFailure;
  265.     }
  266.     /* RNG_SystemInfoForRNG() sometimes does this, not really an error */
  267.     if (bytes == 0)
  268. return SECSuccess;
  269.     /* If received 20 bytes of input, use it, else hash the input before 
  270.      * locking.
  271.      */
  272.     if (bytes == BSIZE)
  273. memcpy(inputhash, data, BSIZE);
  274.     else
  275. rv = SHA1_HashBuf(inputhash, data, bytes);
  276.     if (rv != SECSuccess) {
  277. PORT_SetError(SEC_ERROR_INVALID_ARGS);
  278. return SECFailure;
  279.     }
  280.     /* --- LOCKED --- */
  281.     PR_Lock(rng->lock);
  282.     /*
  283.      * Random information is initially supplied by a call to
  284.      * RNG_SystemInfoForRNG().  That function collects entropy from
  285.      * the system and calls RNG_RandomUpdate() to seed the generator.
  286.      * FIPS 186-1 3.1 step 1 specifies that a secret value for the
  287.      * seed-key must be chosen before the generator can begin.  The
  288.      * size of XKEY is b-bytes, so fill it with the first b-bytes
  289.      * sent to RNG_RandomUpdate().
  290.      */
  291.     if (rng->seedCount == 0) {
  292. /* This is the first call to RandomUpdate().  Use a SHA1 hash
  293.  * of the input to set the seed, XKEY.
  294.  *
  295.  * <Step 1> copy seed bytes into context's XKEY
  296.  */
  297. memcpy(rng->XKEY, inputhash, BSIZE);
  298. /* 
  299.  * Now continue with algorithm.  Since the input was used to
  300.  * initialize XKEY, the "optional user input" at this stage
  301.  * will be a pad of zeros, XSEEDj = 0.
  302.  */
  303. rv = alg_fips186_1_x3_1(rng, NULL, q);
  304. /* As per FIPS 140-1 continuous RNG requirement, the first
  305.  * iteration of output is discarded.  So here there is really
  306.  * no output available.  This forces another execution of alg3_1()
  307.  * before any bytes can be extracted from the generator.
  308.  */
  309. rng->avail = 0;
  310.     } else {
  311. /* Execute the algorithm from FIPS 186-1 appendix 3.1 */
  312. rv = alg_fips186_1_x3_1(rng, inputhash, q);
  313.     }
  314.     /* If got this far, have added bytes of seed data. */
  315.     rng->seedCount += bytes;
  316.     PR_Unlock(rng->lock);
  317.     /* --- UNLOCKED --- */
  318.     /* housekeeping */
  319.     memset(inputhash, 0, BSIZE);
  320.     return rv;
  321. }
  322. /*
  323. ** Update the global random number generator with more seeding
  324. ** material.  Not DSA, so no q.
  325. */
  326. SECStatus 
  327. RNG_RandomUpdate(void *data, size_t bytes)
  328. {
  329.     return prng_RandomUpdate(globalrng, data, bytes, NULL);
  330. }
  331. /*
  332. ** Generate some random bytes, using the global random number generator
  333. ** object.
  334. */
  335. SECStatus 
  336. prng_GenerateGlobalRandomBytes(RNGContext *rng,
  337.                                void *dest, size_t len, unsigned char *q)
  338. {
  339.     PRUint8 num;
  340.     SECStatus rv = SECSuccess;
  341.     unsigned char *output = dest;
  342.     /* check for a valid global RNG context */
  343.     PORT_Assert(rng != NULL);
  344.     if (rng == NULL) {
  345. PORT_SetError(SEC_ERROR_INVALID_ARGS);
  346. return SECFailure;
  347.     }
  348.     /* --- LOCKED --- */
  349.     PR_Lock(rng->lock);
  350.     /* Check the amount of seed data in the generator.  If not enough,
  351.      * don't produce any data.
  352.      */
  353.     if (rng->seedCount < MIN_SEED_COUNT) {
  354. PR_Unlock(rng->lock);
  355. /* XXX this should be a new error code */
  356. PORT_SetError(SEC_ERROR_INVALID_ARGS);
  357. return SECFailure;
  358.     }
  359.     /*
  360.      * If there are enough bytes of random data, send back Xj, 
  361.      * else call alg3_1() with 0's to generate more random data.
  362.      */
  363.     while (len > 0) {
  364. if (rng->avail == 0)
  365.     /* All available bytes are used, so generate more. */
  366.     rv = alg_fips186_1_x3_1(rng, NULL, q);
  367. /* number of bytes to obtain on this iteration (max of 20) */
  368. num = PR_MIN(rng->avail, len);
  369. /* if avail < BSIZE, the first avail bytes have already been used. */
  370. memcpy(output, rng->Xj + (BSIZE - rng->avail), num);
  371. rng->avail -= num;
  372. len -= num;
  373. output += num;
  374.     }
  375.     PR_Unlock(rng->lock);
  376.     /* --- UNLOCKED --- */
  377.     return rv;
  378. }
  379. /*
  380. ** Generate some random bytes, using the global random number generator
  381. ** object.  Not DSA, so no q.
  382. */
  383. SECStatus 
  384. RNG_GenerateGlobalRandomBytes(void *dest, size_t len)
  385. {
  386.     return prng_GenerateGlobalRandomBytes(globalrng, dest, len, NULL);
  387. }
  388. void
  389. RNG_RNGShutdown(void)
  390. {
  391.     /* check for a valid global RNG context */
  392.     PORT_Assert(globalrng != NULL);
  393.     if (globalrng == NULL) {
  394. PORT_SetError(SEC_ERROR_INVALID_ARGS);
  395. return;
  396.     }
  397.     /* clear */
  398.     freeRNGContext();
  399.     /* zero the callonce struct to allow a new call to RNG_RNGInit() */
  400.     memset(&coRNGInit, 0, sizeof coRNGInit);
  401. }
  402. /*
  403.  *  SHA: Generate hash value from context
  404.  *       Specialized function for PRNG
  405.  *       The PRNG specified in FIPS 186-1 3.3 uses a function, G,
  406.  *       which has the same initialization and compression functions
  407.  *       as SHA1 180-1, but uses different padding.  FIPS 186-1 3.3 
  408.  *       specifies that the message be padded with 0's until the size
  409.  *       reaches 512 bits.
  410.  */
  411. void 
  412. RNG_UpdateAndEnd_FIPS186_1(SHA1Context *ctx, 
  413.                            unsigned char *input, unsigned int inputLen,
  414.                            unsigned char *hashout, unsigned int *pDigestLen, 
  415.                            unsigned int maxDigestLen)
  416. {
  417.     register PRUint32 A;
  418.     static const unsigned char bulk_pad0[64] = { 0,0,0,0,0,0,0,0,0,0,
  419.                0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  420.                0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0  };
  421.     PORT_Assert(maxDigestLen >= SHA1_LENGTH);
  422.     PORT_Assert(inputLen <= SHA1_INPUT_LEN);
  423.     /*
  424.      *  Add the input
  425.      */
  426.     SHA1_Update(ctx, input, inputLen);
  427.     /*
  428.      *  Pad with zeroes
  429.      *  This will fill the input block and cause the compression function
  430.      *  to be called.
  431.      */
  432.     SHA1_Update(ctx, bulk_pad0, SHA1_INPUT_LEN - inputLen);
  433.     /*
  434.      *  Output hash
  435.      */
  436. #if defined(IS_LITTLE_ENDIAN)
  437.     SHA_BYTESWAP(ctx->H[0]);
  438.     SHA_BYTESWAP(ctx->H[1]);
  439.     SHA_BYTESWAP(ctx->H[2]);
  440.     SHA_BYTESWAP(ctx->H[3]);
  441.     SHA_BYTESWAP(ctx->H[4]);
  442. #endif
  443.     memcpy(hashout, ctx->H, SHA1_LENGTH);
  444.     *pDigestLen = SHA1_LENGTH;
  445.     /*
  446.      *  Re-initialize the context (also zeroizes contents)
  447.      */
  448.     SHA1_Begin(ctx);
  449. }
  450. /*
  451.  * Specialized RNG for DSA
  452.  *
  453.  * As per FIPS 186-1 appendix 3.1, in step 5 the value Xj should
  454.  * be reduced mod q, a 160-bit prime number.   Since this parameter is
  455.  * only meaningful in the context of DSA, the above RNG functions
  456.  * were implemented without it.  They are re-implemented below for use
  457.  * with DSA.
  458.  *
  459.  */
  460. /*
  461. ** Update the global random number generator with more seeding
  462. ** material.  DSA needs a q parameter.
  463. */
  464. SECStatus 
  465. DSA_RandomUpdate(void *data, size_t bytes, unsigned char *q)
  466. {
  467.     return prng_RandomUpdate(globalrng, data, bytes, q);
  468. }
  469. /*
  470. ** Generate some random bytes, using the global random number generator
  471. ** object.  In DSA mode, so there is a q.
  472. */
  473. SECStatus 
  474. DSA_GenerateGlobalRandomBytes(void *dest, size_t len, unsigned char *q)
  475. {
  476.     return prng_GenerateGlobalRandomBytes(globalrng, dest, len, q);
  477. }