SECStatus DH_GenParam(int primeLen, DHParams **params) { PLArenaPool *arena; DHParams *dhparams; unsigned char *pb = NULL; unsigned char *ab = NULL; unsigned long counter = 0; mp_int p, q, a, h, psub1, test; mp_err err = MP_OKAY; SECStatus rv = SECSuccess; if (!params || primeLen < 0) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } arena = PORT_NewArena(NSS_FREEBL_DEFAULT_CHUNKSIZE); if (!arena) { PORT_SetError(SEC_ERROR_NO_MEMORY); return SECFailure; } dhparams = (DHParams *)PORT_ArenaZAlloc(arena, sizeof(DHParams)); if (!dhparams) { PORT_SetError(SEC_ERROR_NO_MEMORY); PORT_FreeArena(arena, PR_TRUE); return SECFailure; } dhparams->arena = arena; MP_DIGITS(&p) = 0; MP_DIGITS(&q) = 0; MP_DIGITS(&a) = 0; MP_DIGITS(&h) = 0; MP_DIGITS(&psub1) = 0; MP_DIGITS(&test) = 0; CHECK_MPI_OK( mp_init(&p) ); CHECK_MPI_OK( mp_init(&q) ); CHECK_MPI_OK( mp_init(&a) ); CHECK_MPI_OK( mp_init(&h) ); CHECK_MPI_OK( mp_init(&psub1) ); CHECK_MPI_OK( mp_init(&test) ); /* generate prime with MPI, uses Miller-Rabin to generate strong prime. */ pb = PORT_Alloc(primeLen); CHECK_SEC_OK( RNG_GenerateGlobalRandomBytes(pb, primeLen) ); pb[0] |= 0x80; /* set high-order bit */ pb[primeLen-1] |= 0x01; /* set low-order bit */ CHECK_MPI_OK( mp_read_unsigned_octets(&p, pb, primeLen) ); CHECK_MPI_OK( mpp_make_prime(&p, primeLen * 8, PR_TRUE, &counter) ); /* construct Sophie-Germain prime q = (p-1)/2. */ CHECK_MPI_OK( mp_sub_d(&p, 1, &psub1) ); CHECK_MPI_OK( mp_div_2(&psub1, &q) ); /* construct a generator from the prime. */ ab = PORT_Alloc(primeLen); /* generate a candidate number a in p's field */ CHECK_SEC_OK( RNG_GenerateGlobalRandomBytes(ab, primeLen) ); CHECK_MPI_OK( mp_read_unsigned_octets(&a, ab, primeLen) ); /* force a < p (note that quot(a/p) <= 1) */ if ( mp_cmp(&a, &p) > 0 ) CHECK_MPI_OK( mp_sub(&a, &p, &a) ); do { /* check that a is in the range [2..p-1] */ if ( mp_cmp_d(&a, 2) < 0 || mp_cmp(&a, &psub1) >= 0) { /* a is outside of the allowed range. Set a=3 and keep going. */ mp_set(&a, 3); } /* if a**q mod p != 1 then a is a generator */ CHECK_MPI_OK( mp_exptmod(&a, &q, &p, &test) ); if ( mp_cmp_d(&test, 1) != 0 ) break; /* increment the candidate and try again. */ CHECK_MPI_OK( mp_add_d(&a, 1, &a) ); } while (PR_TRUE); MPINT_TO_SECITEM(&p, &dhparams->prime, arena); MPINT_TO_SECITEM(&a, &dhparams->base, arena); *params = dhparams; cleanup: mp_clear(&p); mp_clear(&q); mp_clear(&a); mp_clear(&h); mp_clear(&psub1); mp_clear(&test); if (pb) PORT_ZFree(pb, primeLen); if (ab) PORT_ZFree(ab, primeLen); if (err) { MP_TO_SEC_ERROR(err); rv = SECFailure; } if (rv) PORT_FreeArena(arena, PR_TRUE); return rv; }
SECStatus DH_NewKey(DHParams *params, DHPrivateKey **privKey) { PLArenaPool *arena; DHPrivateKey *key; mp_int g, xa, p, Ya; mp_err err = MP_OKAY; SECStatus rv = SECSuccess; if (!params || !privKey) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } arena = PORT_NewArena(NSS_FREEBL_DEFAULT_CHUNKSIZE); if (!arena) { PORT_SetError(SEC_ERROR_NO_MEMORY); return SECFailure; } key = (DHPrivateKey *)PORT_ArenaZAlloc(arena, sizeof(DHPrivateKey)); if (!key) { PORT_SetError(SEC_ERROR_NO_MEMORY); PORT_FreeArena(arena, PR_TRUE); return SECFailure; } key->arena = arena; MP_DIGITS(&g) = 0; MP_DIGITS(&xa) = 0; MP_DIGITS(&p) = 0; MP_DIGITS(&Ya) = 0; CHECK_MPI_OK( mp_init(&g) ); CHECK_MPI_OK( mp_init(&xa) ); CHECK_MPI_OK( mp_init(&p) ); CHECK_MPI_OK( mp_init(&Ya) ); /* Set private key's p */ CHECK_SEC_OK( SECITEM_CopyItem(arena, &key->prime, ¶ms->prime) ); SECITEM_TO_MPINT(key->prime, &p); /* Set private key's g */ CHECK_SEC_OK( SECITEM_CopyItem(arena, &key->base, ¶ms->base) ); SECITEM_TO_MPINT(key->base, &g); /* Generate private key xa */ SECITEM_AllocItem(arena, &key->privateValue, dh_GetSecretKeyLen(params->prime.len)); CHECK_SEC_OK(RNG_GenerateGlobalRandomBytes(key->privateValue.data, key->privateValue.len)); SECITEM_TO_MPINT( key->privateValue, &xa ); /* xa < p */ CHECK_MPI_OK( mp_mod(&xa, &p, &xa) ); /* Compute public key Ya = g ** xa mod p */ CHECK_MPI_OK( mp_exptmod(&g, &xa, &p, &Ya) ); MPINT_TO_SECITEM(&Ya, &key->publicValue, key->arena); *privKey = key; cleanup: mp_clear(&g); mp_clear(&xa); mp_clear(&p); mp_clear(&Ya); if (err) { MP_TO_SEC_ERROR(err); rv = SECFailure; } if (rv) { *privKey = NULL; PORT_FreeArena(arena, PR_TRUE); } return rv; }
static SECStatus rsa_build_from_primes(mp_int *p, mp_int *q, mp_int *e, PRBool needPublicExponent, mp_int *d, PRBool needPrivateExponent, RSAPrivateKey *key, unsigned int keySizeInBits) { mp_int n, phi; mp_int psub1, qsub1, tmp; mp_err err = MP_OKAY; SECStatus rv = SECSuccess; MP_DIGITS(&n) = 0; MP_DIGITS(&phi) = 0; MP_DIGITS(&psub1) = 0; MP_DIGITS(&qsub1) = 0; MP_DIGITS(&tmp) = 0; CHECK_MPI_OK( mp_init(&n) ); CHECK_MPI_OK( mp_init(&phi) ); CHECK_MPI_OK( mp_init(&psub1) ); CHECK_MPI_OK( mp_init(&qsub1) ); CHECK_MPI_OK( mp_init(&tmp) ); /* 1. Compute n = p*q */ CHECK_MPI_OK( mp_mul(p, q, &n) ); /* verify that the modulus has the desired number of bits */ if ((unsigned)mpl_significant_bits(&n) != keySizeInBits) { PORT_SetError(SEC_ERROR_NEED_RANDOM); rv = SECFailure; goto cleanup; } /* at least one exponent must be given */ PORT_Assert(!(needPublicExponent && needPrivateExponent)); /* 2. Compute phi = (p-1)*(q-1) */ CHECK_MPI_OK( mp_sub_d(p, 1, &psub1) ); CHECK_MPI_OK( mp_sub_d(q, 1, &qsub1) ); if (needPublicExponent || needPrivateExponent) { CHECK_MPI_OK( mp_mul(&psub1, &qsub1, &phi) ); /* 3. Compute d = e**-1 mod(phi) */ /* or e = d**-1 mod(phi) as necessary */ if (needPublicExponent) { err = mp_invmod(d, &phi, e); } else { err = mp_invmod(e, &phi, d); } } else { err = MP_OKAY; } /* Verify that phi(n) and e have no common divisors */ if (err != MP_OKAY) { if (err == MP_UNDEF) { PORT_SetError(SEC_ERROR_NEED_RANDOM); err = MP_OKAY; /* to keep PORT_SetError from being called again */ rv = SECFailure; } goto cleanup; } /* 4. Compute exponent1 = d mod (p-1) */ CHECK_MPI_OK( mp_mod(d, &psub1, &tmp) ); MPINT_TO_SECITEM(&tmp, &key->exponent1, key->arena); /* 5. Compute exponent2 = d mod (q-1) */ CHECK_MPI_OK( mp_mod(d, &qsub1, &tmp) ); MPINT_TO_SECITEM(&tmp, &key->exponent2, key->arena); /* 6. Compute coefficient = q**-1 mod p */ CHECK_MPI_OK( mp_invmod(q, p, &tmp) ); MPINT_TO_SECITEM(&tmp, &key->coefficient, key->arena); /* copy our calculated results, overwrite what is there */ key->modulus.data = NULL; MPINT_TO_SECITEM(&n, &key->modulus, key->arena); key->privateExponent.data = NULL; MPINT_TO_SECITEM(d, &key->privateExponent, key->arena); key->publicExponent.data = NULL; MPINT_TO_SECITEM(e, &key->publicExponent, key->arena); key->prime1.data = NULL; MPINT_TO_SECITEM(p, &key->prime1, key->arena); key->prime2.data = NULL; MPINT_TO_SECITEM(q, &key->prime2, key->arena); cleanup: mp_clear(&n); mp_clear(&phi); mp_clear(&psub1); mp_clear(&qsub1); mp_clear(&tmp); if (err) { MP_TO_SEC_ERROR(err); rv = SECFailure; } return rv; }
static SECStatus dsa_NewKeyExtended(const PQGParams *params, const SECItem * seed, DSAPrivateKey **privKey) { mp_int p, g; mp_int x, y; mp_err err; PRArenaPool *arena; DSAPrivateKey *key; /* Check args. */ if (!params || !privKey || !seed || !seed->data) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } /* Initialize an arena for the DSA key. */ arena = PORT_NewArena(NSS_FREEBL_DSA_DEFAULT_CHUNKSIZE); if (!arena) { PORT_SetError(SEC_ERROR_NO_MEMORY); return SECFailure; } key = (DSAPrivateKey *)PORT_ArenaZAlloc(arena, sizeof(DSAPrivateKey)); if (!key) { PORT_SetError(SEC_ERROR_NO_MEMORY); PORT_FreeArena(arena, PR_TRUE); return SECFailure; } key->params.arena = arena; /* Initialize MPI integers. */ MP_DIGITS(&p) = 0; MP_DIGITS(&g) = 0; MP_DIGITS(&x) = 0; MP_DIGITS(&y) = 0; CHECK_MPI_OK( mp_init(&p) ); CHECK_MPI_OK( mp_init(&g) ); CHECK_MPI_OK( mp_init(&x) ); CHECK_MPI_OK( mp_init(&y) ); /* Copy over the PQG params */ CHECK_MPI_OK( SECITEM_CopyItem(arena, &key->params.prime, ¶ms->prime) ); CHECK_MPI_OK( SECITEM_CopyItem(arena, &key->params.subPrime, ¶ms->subPrime) ); CHECK_MPI_OK( SECITEM_CopyItem(arena, &key->params.base, ¶ms->base) ); /* Convert stored p, g, and received x into MPI integers. */ SECITEM_TO_MPINT(params->prime, &p); SECITEM_TO_MPINT(params->base, &g); OCTETS_TO_MPINT(seed->data, &x, seed->len); /* Store x in private key */ SECITEM_AllocItem(arena, &key->privateValue, seed->len); PORT_Memcpy(key->privateValue.data, seed->data, seed->len); /* Compute public key y = g**x mod p */ CHECK_MPI_OK( mp_exptmod(&g, &x, &p, &y) ); /* Store y in public key */ MPINT_TO_SECITEM(&y, &key->publicValue, arena); *privKey = key; key = NULL; cleanup: mp_clear(&p); mp_clear(&g); mp_clear(&x); mp_clear(&y); if (key) PORT_FreeArena(key->params.arena, PR_TRUE); if (err) { translate_mpi_error(err); return SECFailure; } return SECSuccess; }
/* ** Generate and return a new RSA public and private key. ** Both keys are encoded in a single RSAPrivateKey structure. ** "cx" is the random number generator context ** "keySizeInBits" is the size of the key to be generated, in bits. ** 512, 1024, etc. ** "publicExponent" when not NULL is a pointer to some data that ** represents the public exponent to use. The data is a byte ** encoded integer, in "big endian" order. */ RSAPrivateKey * RSA_NewKey(int keySizeInBits, SECItem *publicExponent) { unsigned int primeLen; mp_int p, q, e; int kiter; mp_err err = MP_OKAY; SECStatus rv = SECSuccess; int prerr = 0; RSAPrivateKey *key = NULL; PRArenaPool *arena = NULL; /* Require key size to be a multiple of 16 bits. */ if (!publicExponent || keySizeInBits % 16 != 0 || BAD_RSA_KEY_SIZE(keySizeInBits/8, publicExponent->len)) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return NULL; } /* 1. Allocate arena & key */ arena = PORT_NewArena(NSS_FREEBL_DEFAULT_CHUNKSIZE); if (!arena) { PORT_SetError(SEC_ERROR_NO_MEMORY); return NULL; } key = (RSAPrivateKey *)PORT_ArenaZAlloc(arena, sizeof(RSAPrivateKey)); if (!key) { PORT_SetError(SEC_ERROR_NO_MEMORY); PORT_FreeArena(arena, PR_TRUE); return NULL; } key->arena = arena; /* length of primes p and q (in bytes) */ primeLen = keySizeInBits / (2 * BITS_PER_BYTE); MP_DIGITS(&p) = 0; MP_DIGITS(&q) = 0; MP_DIGITS(&e) = 0; CHECK_MPI_OK( mp_init(&p) ); CHECK_MPI_OK( mp_init(&q) ); CHECK_MPI_OK( mp_init(&e) ); /* 2. Set the version number (PKCS1 v1.5 says it should be zero) */ SECITEM_AllocItem(arena, &key->version, 1); key->version.data[0] = 0; /* 3. Set the public exponent */ SECITEM_CopyItem(arena, &key->publicExponent, publicExponent); SECITEM_TO_MPINT(*publicExponent, &e); kiter = 0; do { prerr = 0; PORT_SetError(0); CHECK_SEC_OK( generate_prime(&p, primeLen) ); CHECK_SEC_OK( generate_prime(&q, primeLen) ); /* Assure q < p */ if (mp_cmp(&p, &q) < 0) mp_exch(&p, &q); /* Attempt to use these primes to generate a key */ rv = rsa_keygen_from_primes(&p, &q, &e, key, keySizeInBits); if (rv == SECSuccess) break; /* generated two good primes */ prerr = PORT_GetError(); kiter++; /* loop until have primes */ } while (prerr == SEC_ERROR_NEED_RANDOM && kiter < MAX_KEY_GEN_ATTEMPTS); if (prerr) goto cleanup; MPINT_TO_SECITEM(&p, &key->prime1, arena); MPINT_TO_SECITEM(&q, &key->prime2, arena); cleanup: mp_clear(&p); mp_clear(&q); mp_clear(&e); if (err) { MP_TO_SEC_ERROR(err); rv = SECFailure; } if (rv && arena) { PORT_FreeArena(arena, PR_TRUE); key = NULL; } return key; }
static SECStatus rsa_keygen_from_primes(mp_int *p, mp_int *q, mp_int *e, RSAPrivateKey *key, unsigned int keySizeInBits) { mp_int n, d, phi; mp_int psub1, qsub1, tmp; mp_err err = MP_OKAY; SECStatus rv = SECSuccess; MP_DIGITS(&n) = 0; MP_DIGITS(&d) = 0; MP_DIGITS(&phi) = 0; MP_DIGITS(&psub1) = 0; MP_DIGITS(&qsub1) = 0; MP_DIGITS(&tmp) = 0; CHECK_MPI_OK( mp_init(&n) ); CHECK_MPI_OK( mp_init(&d) ); CHECK_MPI_OK( mp_init(&phi) ); CHECK_MPI_OK( mp_init(&psub1) ); CHECK_MPI_OK( mp_init(&qsub1) ); CHECK_MPI_OK( mp_init(&tmp) ); /* 1. Compute n = p*q */ CHECK_MPI_OK( mp_mul(p, q, &n) ); /* verify that the modulus has the desired number of bits */ if ((unsigned)mpl_significant_bits(&n) != keySizeInBits) { PORT_SetError(SEC_ERROR_NEED_RANDOM); rv = SECFailure; goto cleanup; } /* 2. Compute phi = (p-1)*(q-1) */ CHECK_MPI_OK( mp_sub_d(p, 1, &psub1) ); CHECK_MPI_OK( mp_sub_d(q, 1, &qsub1) ); CHECK_MPI_OK( mp_mul(&psub1, &qsub1, &phi) ); /* 3. Compute d = e**-1 mod(phi) */ err = mp_invmod(e, &phi, &d); /* Verify that phi(n) and e have no common divisors */ if (err != MP_OKAY) { if (err == MP_UNDEF) { PORT_SetError(SEC_ERROR_NEED_RANDOM); err = MP_OKAY; /* to keep PORT_SetError from being called again */ rv = SECFailure; } goto cleanup; } MPINT_TO_SECITEM(&n, &key->modulus, key->arena); MPINT_TO_SECITEM(&d, &key->privateExponent, key->arena); /* 4. Compute exponent1 = d mod (p-1) */ CHECK_MPI_OK( mp_mod(&d, &psub1, &tmp) ); MPINT_TO_SECITEM(&tmp, &key->exponent1, key->arena); /* 5. Compute exponent2 = d mod (q-1) */ CHECK_MPI_OK( mp_mod(&d, &qsub1, &tmp) ); MPINT_TO_SECITEM(&tmp, &key->exponent2, key->arena); /* 6. Compute coefficient = q**-1 mod p */ CHECK_MPI_OK( mp_invmod(q, p, &tmp) ); MPINT_TO_SECITEM(&tmp, &key->coefficient, key->arena); cleanup: mp_clear(&n); mp_clear(&d); mp_clear(&phi); mp_clear(&psub1); mp_clear(&qsub1); mp_clear(&tmp); if (err) { MP_TO_SEC_ERROR(err); rv = SECFailure; } return rv; }