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, ¶ms->prime, params->arena); MPINT_TO_SECITEM(&Q, ¶ms->subPrime, params->arena); MPINT_TO_SECITEM(&G, ¶ms->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 + -
显示快捷键?