Back to index

lightning-sunbird  0.9+nobinonly
prng_fips1861.c
Go to the documentation of this file.
00001 /*
00002  *
00003  * ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is the Netscape security libraries.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Netscape Communications Corporation.
00020  * Portions created by the Initial Developer are Copyright (C) 1994-2000
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either the GNU General Public License Version 2 or later (the "GPL"), or
00027  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 /* $Id: prng_fips1861.c,v 1.22.2.4 2006/10/13 17:02:58 wtchang%redhat.com Exp $ */
00039 
00040 #include "prerr.h"
00041 #include "secerr.h"
00042 
00043 #include "prtypes.h"
00044 #include "prinit.h"
00045 #include "blapi.h"
00046 #include "nssilock.h"
00047 #include "secitem.h"
00048 #include "sha_fast.h"
00049 #include "sha256.h"
00050 #include "secrng.h"  /* for RNG_GetNoise() */
00051 #include "secmpi.h"
00052 
00053 /*
00054  * The minimum amount of seed data required before the generator will
00055  * provide data.
00056  * Note that this is a measure of the number of bytes sent to
00057  * RNG_RandomUpdate, not the actual amount of entropy present in the
00058  * generator.  Naturally, it is impossible to know (at this level) just
00059  * how much entropy is present in the provided seed data.  A bare minimum
00060  * of entropy would be 20 bytes, so by requiring 1K this code is making
00061  * the tacit assumption that at least 1 byte of pure entropy is provided
00062  * with every 8 bytes supplied to RNG_RandomUpdate.  The reality of this
00063  * assumption is left up to the caller.
00064  */
00065 #define MIN_SEED_COUNT 1024
00066 
00067 /*
00068  * Steps taken from Algorithm 1 of FIPS 186-2 Change Notice 1
00069  */
00070 
00071 /*
00072  * According to FIPS 186-2, 160 <= b <= 512.
00073  * For our purposes, we will assume b == 160,
00074  * 256, or 512 (the output size of SHA-1,
00075  * SHA-256, or SHA-512).
00076  */
00077 #define FIPS_B     256
00078 #define BSIZE      (FIPS_B / PR_BITS_PER_BYTE)
00079 #if BSIZE != SHA256_LENGTH
00080 #error "this file requires that BSIZE and SHA256_LENGTH be equal"
00081 #endif
00082 
00083 /* Output size of the G function */
00084 #define FIPS_G     160
00085 #define GSIZE      (FIPS_G / PR_BITS_PER_BYTE)
00086 
00087 /*
00088  * Add two b-bit numbers represented as arrays of BSIZE bytes.
00089  * The numbers are big-endian, MSB first, so addition is done
00090  * from the end of the buffer to the beginning.
00091  */
00092 #define ADD_B_BIT_PLUS_CARRY(dest, add1, add2, cy) \
00093     carry = cy; \
00094     for (k=BSIZE-1; k>=0; --k) { \
00095        carry += add1[k] + add2[k]; \
00096        dest[k] = (PRUint8)carry; \
00097        carry >>= 8; \
00098     }
00099 
00100 #define ADD_B_BIT_2(dest, add1, add2) \
00101        ADD_B_BIT_PLUS_CARRY(dest, add1, add2, 0)
00102 
00103 
00104 /*
00105  * FIPS requires result from Step 3.3 to be reduced mod q when generating
00106  * random numbers for DSA.
00107  *
00108  * Input: w, 2*GSIZE bytes
00109  *        q, DSA_SUBPRIME_LEN bytes
00110  * Output: xj, DSA_SUBPRIME_LEN bytes
00111  */
00112 SECStatus
00113 FIPS186Change_ReduceModQForDSA(const unsigned char *w,
00114                                const unsigned char *q,
00115                                unsigned char *xj)
00116 {
00117     mp_int W, Q, Xj;
00118     mp_err err;
00119     SECStatus rv = SECSuccess;
00120 
00121     /* Initialize MPI integers. */
00122     MP_DIGITS(&W) = 0;
00123     MP_DIGITS(&Q) = 0;
00124     MP_DIGITS(&Xj) = 0;
00125     CHECK_MPI_OK( mp_init(&W) );
00126     CHECK_MPI_OK( mp_init(&Q) );
00127     CHECK_MPI_OK( mp_init(&Xj) );
00128     /*
00129      * Convert input arguments into MPI integers.
00130      */
00131     CHECK_MPI_OK( mp_read_unsigned_octets(&W, w, 2*GSIZE) );
00132     CHECK_MPI_OK( mp_read_unsigned_octets(&Q, q, DSA_SUBPRIME_LEN) );
00133     /*
00134      * Algorithm 1 of FIPS 186-2 Change Notice 1, Step 3.3
00135      *
00136      * xj = (w0 || w1) mod q
00137      */
00138     CHECK_MPI_OK( mp_mod(&W, &Q, &Xj) );
00139     CHECK_MPI_OK( mp_to_fixlen_octets(&Xj, xj, DSA_SUBPRIME_LEN) );
00140 cleanup:
00141     mp_clear(&W);
00142     mp_clear(&Q);
00143     mp_clear(&Xj);
00144     if (err) {
00145        MP_TO_SEC_ERROR(err);
00146        rv = SECFailure;
00147     }
00148     return rv;
00149 }
00150 
00151 /*
00152  * Specialized SHA1-like function.  This function appends zeroes to a 
00153  * single input block and runs a single instance of the compression function, 
00154  * as specified in FIPS 186-2 appendix 3.3.
00155  */
00156 static void 
00157 RNG_UpdateAndEnd_FIPS186_2(SHA1Context *ctx, 
00158                            unsigned char *input, unsigned int inputLen,
00159                            unsigned char *hashout, unsigned int *pDigestLen, 
00160                            unsigned int maxDigestLen);
00161 
00162 /*
00163  * Global RNG context
00164  */ 
00165 struct RNGContextStr {
00166     PRUint8   XKEY[BSIZE]; /* Seed for next SHA iteration */
00167     PRUint8   Xj[2*GSIZE]; /* Output from previous operation. */
00168     PZLock   *lock;        /* Lock to serialize access to global rng */
00169     PRUint8   avail;       /* # bytes of output available, [0...2*GSIZE] */
00170     PRUint32  seedCount;   /* number of seed bytes given to generator */
00171     PRBool    isValid;     /* false if RNG reaches an invalid state */
00172 };
00173 typedef struct RNGContextStr RNGContext;
00174 static RNGContext *globalrng = NULL;
00175 static RNGContext theGlobalRng;
00176 
00177 /*
00178  * Clean up the global RNG context
00179  */
00180 static void
00181 freeRNGContext()
00182 {
00183     unsigned char inputhash[BSIZE];
00184     SECStatus rv;
00185 
00186     /* destroy context lock */
00187     PZ_DestroyLock(globalrng->lock);
00188 
00189     /* zero global RNG context except for XKEY to preserve entropy */
00190     rv = SHA256_HashBuf(inputhash, globalrng->XKEY, BSIZE);
00191     PORT_Assert(SECSuccess == rv);
00192     memset(globalrng, 0, sizeof(*globalrng));
00193     memcpy(globalrng->XKEY, inputhash, BSIZE);
00194 
00195     globalrng = NULL;
00196 }
00197 
00198 /*
00199  * The core of Algorithm 1 of FIPS 186-2 Change Notice 1,
00200  * separated from alg_fips186_2_cn_1 as a standalone function
00201  * for FIPS algorithm testing.
00202  *
00203  * Parameters:
00204  *   XKEY [input/output]: the state of the RNG (seed-key)
00205  *   XSEEDj [input]: optional user input (seed)
00206  *   x_j [output]: output of the RNG
00207  *
00208  * Return value:
00209  * This function usually returns SECSuccess.  The only reason
00210  * this function returns SECFailure is that XSEEDj equals
00211  * XKEY, including the intermediate XKEY value between the two
00212  * iterations.  (This test is actually a FIPS 140-2 requirement
00213  * and not required for FIPS algorithm testing, but it is too
00214  * hard to separate from this function.)  If this function fails,
00215  * XKEY is not updated, but some data may have been written to
00216  * x_j, which should be ignored.
00217  */
00218 SECStatus
00219 FIPS186Change_GenerateX(unsigned char *XKEY, const unsigned char *XSEEDj,
00220                         unsigned char *x_j)
00221 {
00222     /* SHA1 context for G(t, XVAL) function */
00223     SHA1Context sha1cx;
00224     /* XKEY for iteration 1 */
00225     PRUint8 XKEY_1[BSIZE];
00226     const PRUint8 *XKEY_old;
00227     PRUint8 *XKEY_new;
00228     /* input to hash function */
00229     PRUint8 XVAL[BSIZE];
00230     /* used by ADD_B_BIT macros */
00231     int k, carry;
00232     /* store the output of G(t, XVAL) in the rightmost GSIZE bytes */
00233     PRUint8 w_i[BSIZE];
00234     int i;
00235     unsigned int len;
00236     SECStatus rv = SECSuccess;
00237 
00238 #if GSIZE < BSIZE
00239     /* zero the leftmost bytes so we can pass it to ADD_B_BIT_PLUS_CARRY */
00240     memset(w_i, 0, BSIZE - GSIZE);
00241 #endif
00242     /* 
00243      * <Step 2> Initialize t, taken care of in SHA-1 (same initial values)
00244      *
00245      * <Step 3.1> XSEEDj is optional user input
00246      */ 
00247     for (i = 0; i < 2; i++) {
00248        /* only update XKEY when both iterations have been completed */
00249        if (i == 0) {
00250            /* for iteration 0 */
00251            XKEY_old = XKEY;
00252            XKEY_new = XKEY_1;
00253        } else {
00254            /* for iteration 1 */
00255            XKEY_old = XKEY_1;
00256            XKEY_new = XKEY;
00257        }
00258        /* 
00259         * <Step 3.2a> XVAL = (XKEY + XSEEDj) mod 2^b
00260         *     :always reduced mod 2^b, since storing as b-bit value
00261         */
00262        if (XSEEDj) {
00263            /* XSEEDj > 0 */
00264            if (memcmp(XKEY_old, XSEEDj, BSIZE) == 0) {
00265               /* Should we add the error code SEC_ERROR_BAD_RNG_SEED? */
00266               PORT_SetError(SEC_ERROR_INVALID_ARGS);
00267               rv = SECFailure;
00268               goto done;
00269            }
00270            ADD_B_BIT_2(XVAL, XKEY_old, XSEEDj);
00271        } else {
00272            /* XSEEDj == 0 */
00273            memcpy(XVAL, XKEY_old, BSIZE);
00274        }
00275        /* 
00276         * <Step 3.2b> Wi = G(t, XVAL)
00277         *     :FIPS 186-2 specifies a different padding than the SHA1 180-1
00278         *     :specification, this function is implemented in
00279         *     :RNG_UpdateAndEnd_FIPS186_2 below.
00280         */ 
00281        SHA1_Begin(&sha1cx);
00282        RNG_UpdateAndEnd_FIPS186_2(&sha1cx, XVAL, BSIZE,
00283                                &w_i[BSIZE - GSIZE], &len, GSIZE);
00284        /* 
00285         * <Step 3.2c> XKEY = (1 + XKEY + Wi) mod 2^b
00286         *     :always reduced mod 2^b, since storing as 160-bit value 
00287         */
00288        ADD_B_BIT_PLUS_CARRY(XKEY_new, XKEY_old, w_i, 1);
00289        /*
00290         * <Step 3.3> Xj = (W0 || W1)
00291         */
00292        memcpy(&x_j[i*GSIZE], &w_i[BSIZE - GSIZE], GSIZE);
00293     }
00294 
00295 done:
00296     /* housekeeping */
00297     memset(&w_i[BSIZE - GSIZE], 0, GSIZE);
00298     memset(XVAL, 0, BSIZE);
00299     memset(XKEY_1, 0, BSIZE);
00300     return rv;
00301 }
00302 
00303 /*
00304  * Implementation of Algorithm 1 of FIPS 186-2 Change Notice 1,
00305  * hereinafter called alg_cn_1().  It is assumed a lock for the global
00306  * rng context has already been acquired.
00307  * Calling this function with XSEEDj == NULL is equivalent to saying there
00308  * is no optional user input, which is further equivalent to saying that
00309  * the optional user input is 0.
00310  */
00311 static SECStatus
00312 alg_fips186_2_cn_1(RNGContext *rng, const unsigned char *XSEEDj)
00313 {
00314     /* store a copy of the output to compare with the previous output */
00315     PRUint8 x_j[2*GSIZE];
00316     SECStatus rv;
00317 
00318     if (!rng->isValid) {
00319        /* RNG has alread entered an invalid state. */
00320        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
00321        return SECFailure;
00322     }
00323     rv = FIPS186Change_GenerateX(rng->XKEY, XSEEDj, x_j);
00324     if (rv != SECSuccess) {
00325        goto done;
00326     }
00327     /*     [FIPS 140-2] verify output does not match previous output */
00328     if (memcmp(x_j, rng->Xj, 2*GSIZE) == 0) {
00329        /* failed FIPS 140-2 continuous RNG test.  RNG now invalid. */
00330        rng->isValid = PR_FALSE;
00331        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
00332        rv = SECFailure;
00333        goto done;
00334     }
00335     /* Xj is the output */
00336     memcpy(rng->Xj, x_j, 2*GSIZE);
00337     /* Always have a full buffer after executing alg_cn_1() */
00338     rng->avail = 2*GSIZE;
00339 
00340 done:
00341     /* housekeeping */
00342     memset(x_j, 0, 2*GSIZE);
00343     return rv;
00344 }
00345 
00346 /* Use NSPR to prevent RNG_RNGInit from being called from separate
00347  * threads, creating a race condition.
00348  */
00349 static const PRCallOnceType pristineCallOnce;
00350 static PRCallOnceType coRNGInit;
00351 static PRStatus rng_init(void)
00352 {
00353     unsigned char bytes[SYSTEM_RNG_SEED_COUNT];
00354     unsigned int numBytes;
00355     if (globalrng == NULL) {
00356        /* create a new global RNG context */
00357        globalrng = &theGlobalRng;
00358         PORT_Assert(NULL == globalrng->lock);
00359        /* create a lock for it */
00360        globalrng->lock = PZ_NewLock(nssILockOther);
00361        if (globalrng->lock == NULL) {
00362            globalrng = NULL;
00363            PORT_SetError(PR_OUT_OF_MEMORY_ERROR);
00364            return PR_FAILURE;
00365        }
00366        /* the RNG is in a valid state */
00367        globalrng->isValid = PR_TRUE;
00368        /* Try to get some seed data for the RNG */
00369        numBytes = RNG_SystemRNG(bytes, sizeof bytes);
00370        PORT_Assert(numBytes == 0 || numBytes == sizeof bytes);
00371        if (numBytes != 0) {
00372            RNG_RandomUpdate(bytes, numBytes);
00373            memset(bytes, 0, numBytes);
00374        } else if (PORT_GetError() != PR_NOT_IMPLEMENTED_ERROR) {
00375            PZ_DestroyLock(globalrng->lock);
00376            globalrng->lock = NULL;
00377            globalrng->isValid = PR_FALSE;
00378            globalrng = NULL;
00379            return PR_FAILURE;
00380        }
00381        numBytes = RNG_GetNoise(bytes, sizeof bytes);
00382        RNG_RandomUpdate(bytes, numBytes);
00383     }
00384     return PR_SUCCESS;
00385 }
00386 
00387 /*
00388  * Initialize the global RNG context and give it some seed input taken
00389  * from the system.  This function is thread-safe and will only allow
00390  * the global context to be initialized once.  The seed input is likely
00391  * small, so it is imperative that RNG_RandomUpdate() be called with
00392  * additional seed data before the generator is used.  A good way to
00393  * provide the generator with additional entropy is to call
00394  * RNG_SystemInfoForRNG().  Note that NSS_Init() does exactly that.
00395  */
00396 SECStatus 
00397 RNG_RNGInit(void)
00398 {
00399     /* Allow only one call to initialize the context */
00400     PR_CallOnce(&coRNGInit, rng_init);
00401     /* Make sure there is a context */
00402     return (globalrng != NULL) ? PR_SUCCESS : PR_FAILURE;
00403 }
00404 
00405 /*
00406 ** Update the global random number generator with more seeding
00407 ** material
00408 */
00409 static SECStatus 
00410 prng_RandomUpdate(RNGContext *rng, const void *data, size_t bytes)
00411 {
00412     SECStatus rv = SECSuccess;
00413     /* check for a valid global RNG context */
00414     PORT_Assert(rng != NULL);
00415     if (rng == NULL) {
00416        PORT_SetError(SEC_ERROR_INVALID_ARGS);
00417        return SECFailure;
00418     }
00419     /* RNG_SystemInfoForRNG() sometimes does this, not really an error */
00420     if (bytes == 0)
00421        return SECSuccess;
00422     /* --- LOCKED --- */
00423     PZ_Lock(rng->lock);
00424     /*
00425      * Random information is initially supplied by a call to
00426      * RNG_SystemInfoForRNG().  That function collects entropy from
00427      * the system and calls RNG_RandomUpdate() to seed the generator.
00428      * Algorithm 1 of FIPS 186-2 Change Notice 1, step 1 specifies that
00429      * a secret value for the seed-key must be chosen before the
00430      * generator can begin.  The size of XKEY is b bits, so fill it
00431      * with the b-bit hash of the input to the first RNG_RandomUpdate()
00432      * call.
00433      */
00434     if (rng->seedCount == 0) {
00435        /* This is the first call to RandomUpdate().  Use a hash
00436         * of the input to set the seed-key, XKEY.
00437         *
00438         * <Step 1> copy hash of seed bytes into context's XKEY
00439         */
00440        SHA256_HashBuf(rng->XKEY, data, bytes);
00441        /* Now continue with algorithm. */
00442        rv = alg_fips186_2_cn_1(rng, NULL);
00443        /* As per FIPS 140-2 continuous RNG test requirement, the first
00444         * iteration of output is discarded.  So here there is really
00445         * no output available.  This forces another execution of alg_cn_1()
00446         * before any bytes can be extracted from the generator.
00447         */
00448        rng->avail = 0;
00449     } else if (bytes == BSIZE && memcmp(rng->XKEY, data, BSIZE) == 0) {
00450        /* Should we add the error code SEC_ERROR_BAD_RNG_SEED? */
00451        PORT_SetError(SEC_ERROR_INVALID_ARGS);
00452        rv = SECFailure;
00453     } else {
00454        /*
00455         * FIPS 186-2 does not specify how to reseed the RNG.  We retrofit
00456         * our RNG with a reseed function from NIST SP 800-90.
00457         *
00458         * Use a hash of the seed-key and the input to reseed the RNG.
00459         */
00460        SHA256Context ctx;
00461        SHA256_Begin(&ctx);
00462        SHA256_Update(&ctx, rng->XKEY, BSIZE);
00463        SHA256_Update(&ctx, data, bytes);
00464        SHA256_End(&ctx, rng->XKEY, NULL, BSIZE);
00465     }
00466     /* If got this far, have added bytes of seed data. */
00467     if (rv == SECSuccess)
00468        rng->seedCount += bytes;
00469     PZ_Unlock(rng->lock);
00470     /* --- UNLOCKED --- */
00471     return rv;
00472 }
00473 
00474 /*
00475 ** Update the global random number generator with more seeding
00476 ** material.
00477 */
00478 SECStatus 
00479 RNG_RandomUpdate(const void *data, size_t bytes)
00480 {
00481     return prng_RandomUpdate(globalrng, data, bytes);
00482 }
00483 
00484 /*
00485 ** Generate some random bytes, using the global random number generator
00486 ** object.
00487 */
00488 static SECStatus 
00489 prng_GenerateGlobalRandomBytes(RNGContext *rng,
00490                                void *dest, size_t len)
00491 {
00492     PRUint8 num;
00493     SECStatus rv = SECSuccess;
00494     unsigned char *output = dest;
00495     /* check for a valid global RNG context */
00496     PORT_Assert(rng != NULL);
00497     if (rng == NULL) {
00498        PORT_SetError(SEC_ERROR_INVALID_ARGS);
00499        return SECFailure;
00500     }
00501     /* --- LOCKED --- */
00502     PZ_Lock(rng->lock);
00503     /* Check the amount of seed data in the generator.  If not enough,
00504      * don't produce any data.
00505      */
00506     if (rng->seedCount < MIN_SEED_COUNT) {
00507        PZ_Unlock(rng->lock);
00508        PORT_SetError(SEC_ERROR_NEED_RANDOM);
00509        return SECFailure;
00510     }
00511     /*
00512      * If there are enough bytes of random data, send back Xj, 
00513      * else call alg_cn_1() with 0's to generate more random data.
00514      */
00515     while (len > 0 && rv == SECSuccess) {
00516        if (rng->avail == 0) {
00517            /* All available bytes are used, so generate more. */
00518            rv = alg_fips186_2_cn_1(rng, NULL);
00519        }
00520        /* number of bytes to obtain on this iteration (max of 40) */
00521        num = PR_MIN(rng->avail, len);
00522        /*
00523         * if avail < 2*GSIZE, the first 2*GSIZE - avail bytes have
00524         * already been used.
00525         */
00526        if (num) {
00527            memcpy(output, rng->Xj + (2*GSIZE - rng->avail), num);
00528            rng->avail -= num;
00529            len -= num;
00530            output += num;
00531        }
00532     }
00533     PZ_Unlock(rng->lock);
00534     /* --- UNLOCKED --- */
00535     return rv;
00536 }
00537 
00538 /*
00539 ** Generate some random bytes, using the global random number generator
00540 ** object.
00541 */
00542 SECStatus 
00543 RNG_GenerateGlobalRandomBytes(void *dest, size_t len)
00544 {
00545     return prng_GenerateGlobalRandomBytes(globalrng, dest, len);
00546 }
00547 
00548 void
00549 RNG_RNGShutdown(void)
00550 {
00551     /* check for a valid global RNG context */
00552     PORT_Assert(globalrng != NULL);
00553     if (globalrng == NULL) {
00554        /* Should set a "not initialized" error code. */
00555        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
00556        return;
00557     }
00558     /* clear */
00559     freeRNGContext();
00560     /* reset the callonce struct to allow a new call to RNG_RNGInit() */
00561     coRNGInit = pristineCallOnce;
00562 }
00563 
00564 /*
00565  *  SHA: Generate hash value from context
00566  *       Specialized function for PRNG
00567  *       The PRNG specified in FIPS 186-2 3.3 uses a function, G,
00568  *       which has the same initialization and compression functions
00569  *       as SHA1 180-1, but uses different padding.  FIPS 186-2 3.3 
00570  *       specifies that the message be padded with 0's until the size
00571  *       reaches 512 bits.
00572  */
00573 static void 
00574 RNG_UpdateAndEnd_FIPS186_2(SHA1Context *ctx, 
00575                            unsigned char *input, unsigned int inputLen,
00576                            unsigned char *hashout, unsigned int *pDigestLen, 
00577                            unsigned int maxDigestLen)
00578 {
00579 #if defined(SHA_NEED_TMP_VARIABLE)
00580     register PRUint32 tmp;
00581 #endif
00582     static const unsigned char bulk_pad0[64] = { 0,0,0,0,0,0,0,0,0,0,
00583                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,
00584                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  };
00585 
00586     PORT_Assert(maxDigestLen >= SHA1_LENGTH);
00587     PORT_Assert(inputLen <= SHA1_INPUT_LEN);
00588 
00589     /*
00590      *  Add the input
00591      */
00592     SHA1_Update(ctx, input, inputLen);
00593     /*
00594      *  Pad with zeroes
00595      *  This will fill the input block and cause the compression function
00596      *  to be called.
00597      */
00598     SHA1_Update(ctx, bulk_pad0, SHA1_INPUT_LEN - inputLen);
00599 
00600     /*
00601      *  Output hash
00602      */
00603     SHA_STORE_RESULT;
00604     *pDigestLen = SHA1_LENGTH;
00605 }
00606 
00607 /*
00608  * Specialized RNG for DSA
00609  *
00610  * As per Algorithm 1 of FIPS 186-2 Change Notice 1, in step 3.3 the value
00611  * Xj should be reduced mod q, a 160-bit prime number.  Since this parameter
00612  * is only meaningful in the context of DSA, the above RNG functions
00613  * were implemented without it.  They are re-implemented below for use
00614  * with DSA.
00615  *
00616  */
00617 
00618 /*
00619 ** Generate some random bytes, using the global random number generator
00620 ** object.  In DSA mode, so there is a q.
00621 */
00622 SECStatus 
00623 DSA_GenerateGlobalRandomBytes(void *dest, size_t len, const unsigned char *q)
00624 {
00625     SECStatus rv;
00626     unsigned char w[2*GSIZE];
00627 
00628     PORT_Assert(q && len == DSA_SUBPRIME_LEN);
00629     if (len != DSA_SUBPRIME_LEN) {
00630        PORT_SetError(SEC_ERROR_OUTPUT_LEN);
00631        return SECFailure;
00632     }
00633     if (*q == 0) {
00634         ++q;
00635     }
00636     rv = prng_GenerateGlobalRandomBytes(globalrng, w, 2*GSIZE);
00637     if (rv != SECSuccess) {
00638        return rv;
00639     }
00640     FIPS186Change_ReduceModQForDSA(w, q, (unsigned char *)dest);
00641     return rv;
00642 }