pqg.c

来自「支持SSL v2/v3, TLS, PKCS #5, PKCS #7, PKCS」· C语言 代码 · 共 666 行 · 第 1/2 页

C
666
字号
    /* Compute G, according to the equation  G = (H ** ((P-1)/Q)) mod P */    CHECK_MPI_OK( mp_div(&pm1, Q, &exp, NULL) );  /* exp = (P-1)/Q      */    CHECK_MPI_OK( mp_exptmod(H, &exp, P, G) );    /* G = H ** exp mod P */    /* Check for G == 0 or G == 1, return error if so. */    if (mp_cmp_d(G, 1) <= 0) {	rv = SECFailure;	goto cleanup;    }    *passed = PR_TRUE;cleanup:    mp_clear(&exp);    mp_clear(&pm1);    if (err) {	MP_TO_SEC_ERROR(err);	rv = SECFailure;    }    return rv;}SECStatusPQG_ParamGen(unsigned int j, PQGParams **pParams, PQGVerify **pVfy){    unsigned int L;            /* Length of P in bits.  Per FIPS 186. */    unsigned int seedBytes;    if (j > 8 || !pParams || !pVfy) {	PORT_SetError(SEC_ERROR_INVALID_ARGS);        return SECFailure;    }    L = 512 + (j * 64);         /* bits in P */    seedBytes = L/8;    return PQG_ParamGenSeedLen(j, seedBytes, pParams, pVfy);}/* This code uses labels and gotos, so that it can follow the numbered** steps in the algorithms from FIPS 186 appendix 2.2 very closely,** and so that the correctness of this code can be easily verified.** So, please forgive the ugly c code.**/SECStatusPQG_ParamGenSeedLen(unsigned int j, unsigned int seedBytes,                    PQGParams **pParams, PQGVerify **pVfy){    unsigned int  L;        /* Length of P in bits.  Per FIPS 186. */    unsigned int  n;        /* Per FIPS 186, appendix 2.2. */    unsigned int  b;        /* Per FIPS 186, appendix 2.2. */    unsigned int  g;        /* Per FIPS 186, appendix 2.2. */    unsigned int  counter;  /* Per FIPS 186, appendix 2.2. */    unsigned int  offset;   /* Per FIPS 186, appendix 2.2. */    SECItem      *seed;     /* Per FIPS 186, appendix 2.2. */    PRArenaPool  *arena  = NULL;    PQGParams    *params = NULL;    PQGVerify    *verify = NULL;    PRBool passed;    SECItem hit = { 0, 0, 0 };    mp_int P, Q, G, H, l;    mp_err    err = MP_OKAY;    SECStatus rv  = SECFailure;    int iterations = 0;    if (j > 8 || !pParams || !pVfy) {	PORT_SetError(SEC_ERROR_INVALID_ARGS);	return SECFailure;    }    /* Initialize an arena for the params. */    arena = PORT_NewArena(NSS_FREEBL_DEFAULT_CHUNKSIZE);    if (!arena) {	PORT_SetError(SEC_ERROR_NO_MEMORY);	return SECFailure;    }    params = (PQGParams *)PORT_ArenaZAlloc(arena, sizeof(PQGParams));    if (!params) {	PORT_SetError(SEC_ERROR_NO_MEMORY);	PORT_FreeArena(arena, PR_TRUE);	return SECFailure;    }    params->arena = arena;    /* Initialize an arena for the verify. */    arena = PORT_NewArena(NSS_FREEBL_DEFAULT_CHUNKSIZE);    if (!arena) {	PORT_SetError(SEC_ERROR_NO_MEMORY);	return SECFailure;    }    verify = (PQGVerify *)PORT_ArenaZAlloc(arena, sizeof(PQGVerify));    if (!verify) {	PORT_SetError(SEC_ERROR_NO_MEMORY);	PORT_FreeArena(arena, PR_TRUE);	PORT_FreeArena(params->arena, PR_TRUE);	return SECFailure;    }    verify->arena = arena;    seed = &verify->seed;    arena = NULL;    /* Initialize bignums */    MP_DIGITS(&P) = 0;    MP_DIGITS(&Q) = 0;    MP_DIGITS(&G) = 0;    MP_DIGITS(&H) = 0;    MP_DIGITS(&l) = 0;    CHECK_MPI_OK( mp_init(&P) );    CHECK_MPI_OK( mp_init(&Q) );    CHECK_MPI_OK( mp_init(&G) );    CHECK_MPI_OK( mp_init(&H) );    CHECK_MPI_OK( mp_init(&l) );    /* Compute lengths. */    L = 512 + (j * 64);               /* bits in P */    n = (L - 1) / BITS_IN_Q;          /* BITS_IN_Q is 160 */      b = (L - 1) % BITS_IN_Q;    g = seedBytes * BITS_PER_BYTE;    /* bits in seed, NOT G of PQG. */step_1:    /* ******************************************************************    ** Step 1.    ** "Choose an abitrary sequence of at least 160 bits and call it SEED.    **  Let g be the length of SEED in bits."    */    if (++iterations > MAX_ITERATIONS) {        /* give up after a while */        PORT_SetError(SEC_ERROR_NEED_RANDOM);        goto cleanup;    }    seed->len = seedBytes;    CHECK_SEC_OK( getPQseed(seed) );    /* ******************************************************************    ** Step 2.    ** "Compute U = SHA[SEED] XOR SHA[(SEED+1) mod 2**g]."    **    ** Step 3.    ** "Form Q from U by setting the most signficant bit (the 2**159 bit)     **  and the least signficant bit to 1.  In terms of boolean operations,    **  Q = U OR 2**159 OR 1.  Note that 2**159 < Q < 2**160."    */    CHECK_SEC_OK( makeQfromSeed(g, seed, &Q) );    /* ******************************************************************    ** Step 4.    ** "Use a robust primality testing algorithm to test whether q is prime."    **    ** Appendix 2.1 states that a Rabin test with at least 50 iterations    ** "will give an acceptable probability of error."    */    /*CHECK_SEC_OK( prm_RabinTest(&Q, &passed) );*/    err = mpp_pprime(&Q, 40);    passed = (err == MP_YES) ? SECSuccess : SECFailure;    /* ******************************************************************    ** Step 5. "If q is not prime, goto step 1."    */    if (passed != SECSuccess)        goto step_1;    /* ******************************************************************    ** Step 6. "Let counter = 0 and offset = 2."    */    counter = 0;    offset  = 2;step_7:    /* ******************************************************************    ** Step 7.    ** "for k = 0 ... n let    **          V_k = SHA[(SEED + offset + k) mod 2**g]."    **    ** Step 8.    ** "Let W be the sum of  (V_k * 2**(k*160)) for k = 0 ... n    **  and let X = W + 2**(L-1).    **  Note that 0 <= W < 2**(L-1) and hence 2**(L-1) <= X < 2**L."    **    ** Step 9.    ** "Let c = X mod 2q  and set p = X - (c - 1).    **  Note that p is congruent to 1 mod 2q."    */    CHECK_SEC_OK( makePfromQandSeed(L, offset, g, seed, &Q, &P) );    /*************************************************************    ** Step 10.    ** "if p < 2**(L-1), then goto step 13."    */    CHECK_MPI_OK( mpl_set_bit(&l, (mp_size)(L-1), 1) ); /* l = 2**(L-1) */    if (mp_cmp(&P, &l) < 0)        goto step_13;    /************************************************************    ** Step 11.    ** "Perform a robust primality test on p."    */    /*CHECK_SEC_OK( prm_RabinTest(&P, &passed) );*/    err = mpp_pprime(&P, 40);    passed = (err == MP_YES) ? SECSuccess : SECFailure;    /* ******************************************************************    ** Step 12. "If p passes the test performed in step 11, go to step 15."    */    if (passed == SECSuccess)        goto step_15;step_13:    /* ******************************************************************    ** Step 13.  "Let counter = counter + 1 and offset = offset + n + 1."    */    counter++;    offset += n + 1;    /* ******************************************************************    ** Step 14.  "If counter >= 4096 goto step 1, otherwise go to step 7."    */    if (counter >= 4096)        goto step_1;    goto step_7;step_15:    /* ******************************************************************    ** Step 15.      ** "Save the value of SEED and the value of counter for use    **  in certifying the proper generation of p and q."    */    /* Generate h. */    SECITEM_AllocItem(NULL, &hit, seedBytes); /* h is no longer than p */    if (!hit.data) goto cleanup;    do {	/* loop generate h until 1<h<p-1 and (h**[(p-1)/q])mod p > 1 */	CHECK_SEC_OK( generate_h_candidate(&hit, &H) );        CHECK_SEC_OK( makeGfromH(&P, &Q, &H, &G, &passed) );    } while (passed != PR_TRUE);    /* All generation is done.  Now, save the PQG params.  */    MPINT_TO_SECITEM(&P, &params->prime,    params->arena);    MPINT_TO_SECITEM(&Q, &params->subPrime, params->arena);    MPINT_TO_SECITEM(&G, &params->base,     params->arena);    MPINT_TO_SECITEM(&H, &verify->h,        verify->arena);    verify->counter = counter;    *pParams = params;    *pVfy = verify;cleanup:    mp_clear(&P);    mp_clear(&Q);    mp_clear(&G);    mp_clear(&H);    mp_clear(&l);    if (err) {	MP_TO_SEC_ERROR(err);	rv = SECFailure;    }    if (rv) {	PORT_FreeArena(params->arena, PR_TRUE);	PORT_FreeArena(verify->arena, PR_TRUE);    }    return rv;}SECStatus   PQG_VerifyParams(const PQGParams *params,                  const PQGVerify *vfy, SECStatus *result){    SECStatus rv = SECSuccess;    int passed;    unsigned int g, n, L, offset;    mp_int P, Q, G, P_, Q_, G_, r, h;    mp_err err = MP_OKAY;    int j;#define CHECKPARAM(cond)      \    if (!(cond)) {            \	*result = SECFailure; \	goto cleanup;         \    }    if (!params || !vfy || !result) {	PORT_SetError(SEC_ERROR_INVALID_ARGS);	return SECFailure;    }    MP_DIGITS(&P) = 0;    MP_DIGITS(&Q) = 0;    MP_DIGITS(&G) = 0;    MP_DIGITS(&P_) = 0;    MP_DIGITS(&Q_) = 0;    MP_DIGITS(&G_) = 0;    MP_DIGITS(&r) = 0;    MP_DIGITS(&h) = 0;    CHECK_MPI_OK( mp_init(&P) );    CHECK_MPI_OK( mp_init(&Q) );    CHECK_MPI_OK( mp_init(&G) );    CHECK_MPI_OK( mp_init(&P_) );    CHECK_MPI_OK( mp_init(&Q_) );    CHECK_MPI_OK( mp_init(&G_) );    CHECK_MPI_OK( mp_init(&r) );    CHECK_MPI_OK( mp_init(&h) );    *result = SECSuccess;    SECITEM_TO_MPINT(params->prime,    &P);    SECITEM_TO_MPINT(params->subPrime, &Q);    SECITEM_TO_MPINT(params->base,     &G);    /* 1.  Q is 160 bits long. */    CHECKPARAM( mpl_significant_bits(&Q) == 160 );    /* 2.  P is one of the 9 valid lengths. */    L = mpl_significant_bits(&P);    j = PQG_PBITS_TO_INDEX(L);    CHECKPARAM( j >= 0 && j <= 8 );    /* 3.  G < P */    CHECKPARAM( mp_cmp(&G, &P) < 0 );    /* 4.  P % Q == 1 */    CHECK_MPI_OK( mp_mod(&P, &Q, &r) );    CHECKPARAM( mp_cmp_d(&r, 1) == 0 );    /* 5.  Q is prime */    CHECKPARAM( mpp_pprime(&Q, NUMITER) == MP_YES );    /* 6.  P is prime */    CHECKPARAM( mpp_pprime(&P, NUMITER) == MP_YES );    /* Steps 7-12 are done only if the optional PQGVerify is supplied. */    if (!vfy) goto cleanup;    /* 7.  counter < 4096 */    CHECKPARAM( vfy->counter < 4096 );    /* 8.  g >= 160 and g < 2048   (g is length of seed in bits) */    g = vfy->seed.len * 8;    CHECKPARAM( g >= 160 && g < 2048 );    /* 9.  Q generated from SEED matches Q in PQGParams. */    CHECK_SEC_OK( makeQfromSeed(g, &vfy->seed, &Q_) );    CHECKPARAM( mp_cmp(&Q, &Q_) == 0 );    /* 10. P generated from (L, counter, g, SEED, Q) matches P in PQGParams. */    n = (L - 1) / BITS_IN_Q;    offset = vfy->counter * (n + 1) + 2;    CHECK_SEC_OK( makePfromQandSeed(L, offset, g, &vfy->seed, &Q, &P_) );    CHECKPARAM( mp_cmp(&P, &P_) == 0 );    /* Next two are optional: if h == 0 ignore */    if (vfy->h.len == 0) goto cleanup;    /* 11. 1 < h < P-1 */    SECITEM_TO_MPINT(vfy->h, &h);    CHECK_MPI_OK( mpl_set_bit(&P, 0, 0) ); /* P is prime, p-1 == zero 1st bit */    CHECKPARAM( mp_cmp_d(&h, 1) > 0 && mp_cmp(&h, &P) );    CHECK_MPI_OK( mpl_set_bit(&P, 0, 1) ); /* set it back */    /* 12. G generated from h matches G in PQGParams. */    CHECK_SEC_OK( makeGfromH(&P, &Q, &h, &G_, &passed) );    CHECKPARAM( passed && mp_cmp(&G, &G_) == 0 );cleanup:    mp_clear(&P);    mp_clear(&Q);    mp_clear(&G);    mp_clear(&P_);    mp_clear(&Q_);    mp_clear(&G_);    mp_clear(&r);    mp_clear(&h);    if (err) {	MP_TO_SEC_ERROR(err);	rv = SECFailure;    }    return rv;}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?