/*----------------------------------------------------------------------------*/ static zrtp_status_t zrtp_dh_init(void *s) { struct BigNum* p = NULL; struct BigNum* p_1 = NULL; uint8_t* p_data = NULL; unsigned int p_data_length = 0; zrtp_pk_scheme_t *self = (zrtp_pk_scheme_t *) s; switch (self->base.id) { case ZRTP_PKTYPE_DH2048: p = &self->base.zrtp->P_2048; p_1 = &self->base.zrtp->P_2048_1; p_data = self->base.zrtp->P_2048_data; p_data_length = sizeof(self->base.zrtp->P_2048_data); break; case ZRTP_PKTYPE_DH3072: p = &self->base.zrtp->P_3072; p_1 = &self->base.zrtp->P_3072_1; p_data = self->base.zrtp->P_3072_data; p_data_length = sizeof(self->base.zrtp->P_3072_data); break; default: return zrtp_status_bad_param; } bnBegin(p); bnInsertBigBytes(p, (const unsigned char *)p_data, 0, p_data_length); bnBegin(p_1); bnCopy(p_1, p); bnSub(p_1, &self->base.zrtp->one); return zrtp_status_ok; }
int rsa_ENCRYPTPRIVATE(RSA_CTX *ctx,unsigned char *data,unsigned long int *datLen){ int t; struct BigNum enc,m; /* encrypt (sign) data with private key */ /* datLen must be == to bitsize/8 */ if(*datLen!=ctx->bits/8) return BADDATALEN; bnBegin(&enc); bnBegin(&m); t=bnInsertLittleBytes(&m,(void*)data,0,ctx->bits/8); if(t<0){ bnEnd(&enc); bnEnd(&m); return BADTHINGS; } t=bnExpMod(&enc,&m,&ctx->d,&ctx->n); if(t<0){ bnEnd(&enc); bnEnd(&m); return BADMOD; } bnExtractLittleBytes(&enc,(void*)data,0,ctx->bits/8); bnEnd(&enc); bnEnd(&m); return OK; }
int rsa_ENCRYPTPUBLIC(RSA_CTX *ctx,unsigned char *data,unsigned long int *datLen){ int t; struct BigNum enc,m; /* encrypt data using public key */ /* datLen must be == to bitsize/8 */ if(*datLen!=ctx->bits/8) return BADDATALEN; bnBegin(&enc); bnBegin(&m); t=bnInsertLittleBytes(&m,(void*)data,0,ctx->bits/8); if(t<0){ bnEnd(&enc); bnEnd(&m); return BADTHINGS; } t=bnExpMod(&enc,&m,&ctx->e,&ctx->n); if(t<0){ bnEnd(&enc); bnEnd(&m); return BADTHINGS; } bnExtractLittleBytes(&enc,(void*)data,0,(ctx->bits/8)); bnEnd(&enc); bnEnd(&m); return OK; }
int rsa_DECRYPTPUBLIC(RSA_CTX *ctx,unsigned char *data,unsigned long int *datLen){ int t; struct BigNum enc,m; /* decrypt (verify) data encrypted with private key (verfied by public key) */ /* datLen must be == to bitsize/8 */ if(*datLen!=ctx->bits/8) return BADDATALEN; bnBegin(&enc); bnBegin(&m); t=bnInsertLittleBytes(&m,(void*)data,0,ctx->bits/8); if(t<0){ bnEnd(&enc); bnEnd(&m); return BADTHINGS; } t=bnExpMod(&enc,&m,&ctx->e,&ctx->n); if(t<0){ bnEnd(&enc); bnEnd(&m); return BADMOD; } bnExtractLittleBytes(&enc,(void*)data,0,ctx->bits/8); bnEnd(&enc); bnEnd(&m); return OK; }
static zrtp_status_t zrtp_dh_initialize( zrtp_pk_scheme_t *self, zrtp_dh_crypto_context_t *dh_cc) { unsigned char* buffer = zrtp_sys_alloc(sizeof(zrtp_uchar128_t)); struct BigNum* p = _zrtp_get_p(self); zrtp_time_t start_ts = zrtp_time_now(); ZRTP_LOG(1,(_ZTU_,"\tDH TEST: %.4s zrtp_dh_initialize() START. now=%llums.\n", self->base.type, start_ts)); if (!buffer) { return zrtp_status_alloc_fail; } if (!p) { zrtp_sys_free(buffer); return zrtp_status_bad_param; } if (64 != zrtp_randstr(self->base.zrtp, buffer, 64)) { zrtp_sys_free(buffer); return zrtp_status_rng_fail; } bnBegin(&dh_cc->sv); bnInsertBigBytes(&dh_cc->sv, (const unsigned char *)buffer, 0, self->sv_length); bnBegin(&dh_cc->pv); bnExpMod(&dh_cc->pv, &self->base.zrtp->G, &dh_cc->sv, p); zrtp_sys_free(buffer); ZRTP_LOG(1,(_ZTU_,"\tDH TEST: zrtp_dh_initialize() for %.4s was executed ts=%llums d=%llums.\n", self->base.type, zrtp_time_now(), zrtp_time_now()-start_ts)); return zrtp_status_ok; }
void pubKeyBegin(struct PubKey *pub) { if (pub) { bnBegin(&pub->n); bnBegin(&pub->e); } }
void secKeyBegin(struct SecKey *sec) { if (sec) { bnBegin(&sec->d); bnBegin(&sec->p); bnBegin(&sec->q); bnBegin(&sec->u); } }
/*----------------------------------------------------------------------------*/ zrtp_status_t zrtp_prepare_pkt(zrtp_global_t* zrtp) { bnInit(); bnBegin(&zrtp->one); bnSetQ(&zrtp->one, 1); bnBegin(&zrtp->G); bnSetQ(&zrtp->G, 2); return zrtp_status_ok; }
/*----------------------------------------------------------------------------*/ static zrtp_status_t zrtp_dh_self_test(zrtp_pk_scheme_t *self) { zrtp_status_t s = zrtp_status_ok; zrtp_dh_crypto_context_t alice_cc; zrtp_dh_crypto_context_t bob_cc; struct BigNum alice_k; struct BigNum bob_k; zrtp_time_t start_ts = zrtp_time_now(); ZRTP_LOG(3, (_ZTU_, "PKS %.4s testing... ", self->base.type)); bnBegin(&alice_k); bnBegin(&bob_k); do { /* Both sides initalise DH schemes and compute secret and public values. */ s = self->initialize(self, &alice_cc); if (zrtp_status_ok != s) { break; } s = self->initialize(self, &bob_cc); if (zrtp_status_ok != s) { break; } /* Both sides validate public values. (to provide exact performance estimation) */ s = self->validate(self, &bob_cc.pv); if (zrtp_status_ok != s) { break; } s = self->validate(self, &alice_cc.pv); if (zrtp_status_ok != s) { break; } /* Compute secret keys and compare them. */ s = self->compute(self, &alice_cc, &alice_k, &bob_cc.pv); if (zrtp_status_ok != s) { break; } s= self->compute(self, &bob_cc, &bob_k, &alice_cc.pv); if (zrtp_status_ok != s) { break; } s = (0 == bnCmp(&alice_k, &bob_k)) ? zrtp_status_ok : zrtp_status_algo_fail; } while (0); bnEnd(&alice_k); bnEnd(&bob_k); ZRTP_LOGC(3, ("%s (%llu ms)\n", zrtp_log_status2str(s), (zrtp_time_now()-start_ts)/2)); return s; }
/* * Generate a PGPPubKey from a PGPSecKey */ static PGPPubKey * dsaPubkey(PGPSecKey const *seckey) { DSAsecPlus const *sec = (DSAsecPlus *)seckey->priv; PGPPubKey *pubkey; DSApub *pub; PGPContextRef context; PGPMemoryMgrRef mgr = NULL; pgpAssertAddrValid( seckey, PGPSecKey ); context = seckey->context; mgr = PGPGetContextMemoryMgr( context ); ASSERTDSA(seckey->pkAlg); pub = (DSApub *)pgpContextMemAlloc( context, sizeof(*pub), kPGPMemoryMgrFlags_Clear); if (pub) { pubkey = (PGPPubKey *)pgpContextMemAlloc( context, sizeof(*pubkey), kPGPMemoryMgrFlags_Clear); if (pubkey) { pubkey->context = context; bnBegin(&pub->p, mgr, FALSE ); bnBegin(&pub->q, mgr, FALSE ); bnBegin(&pub->g, mgr, FALSE ); bnBegin(&pub->y, mgr, FALSE ); if (bnCopy(&pub->p, &sec->s.p) >= 0 && bnCopy(&pub->q, &sec->s.q) >= 0 && bnCopy(&pub->g, &sec->s.g) >= 0 && bnCopy(&pub->y, &sec->s.y) >= 0) { dsaFillPubkey(pubkey, pub); pubkey->pkAlg = seckey->pkAlg; memcpy(pubkey->keyID, seckey->keyID, sizeof(pubkey->keyID)); return pubkey; } /* Failed = clean up and return NULL */ bnEnd(&pub->p); bnEnd(&pub->q); bnEnd(&pub->g); bnEnd(&pub->y); pgpContextMemFree( context, pubkey); } pgpContextMemFree( context, pub); } return NULL; }
/* Creates a new bignum */ PGPError PGPNewBigNum( PGPMemoryMgrRef mgr, PGPBoolean secure, PGPBigNumRef * newBN ) { PGPError err = kPGPError_NoErr; PGPBigNumRef ref; PGPValidatePtr( newBN ); *newBN = kPGPInvalidBigNumRef; ref = (PGPBigNumRef) PGPNewData( mgr, sizeof( **newBN ), kPGPMemoryMgrFlags_Clear); if ( IsntNull( ref ) ) { bnBegin( &ref->bn, mgr, secure ); *newBN = ref; } else { err = kPGPError_OutOfMemory; } return( err ); }
int main(void) { struct BigNum p, q, d, u; int i; clock_t interval; static unsigned const sizetable[] = { 384, 512, 513, 514, 515, 768, 1024, 1536, 2048, 0 }; unsigned const *sizeptr = sizetable; bnInit(); bnRandSeed(1); bnBegin(&p); bnBegin(&q); bnBegin(&d); bnBegin(&u); while (*sizeptr) { printf("Generating a %u-bit RSA key\n", *sizeptr); interval = clock(); i = genRsaKey(&p, &q, &d, &u, *sizeptr, 17, stdout); interval = clock() - interval; printf("genRsaKey returned %d. %ld.%06ld s\n", i, interval / 1000000, interval % 1000000); fputs("p = ", stdout); bnPrint(stdout, &p); fputs("\nq = ", stdout); bnPrint(stdout, &q); fputs("\nd = ", stdout); bnPrint(stdout, &d); fputs("\nu = ", stdout); bnPrint(stdout, &u); putchar('\n'); sizeptr++; } bnEnd(&p); bnEnd(&q); bnEnd(&d); bnEnd(&u); return 0; }
int rsa_INIT(RSA_CTX *ctx,unsigned long int bitlen){ /* e is <i> always </i> 3 ;) */ int t; bnBegin(&ctx->n); bnBegin(&ctx->e); bnBegin(&ctx->d); t=bnSetQ(&ctx->e,(unsigned long int)3); if(t<0){ bnEnd(&ctx->n); bnEnd(&ctx->e); bnEnd(&ctx->d); return BADTHINGS; } ctx->bits=bitlen; ctx->ebits=sizeof(unsigned long int); return OK; }
int bnPrint10(FILE *f, char const *prefix, BigNum const *bn, char const *suffix) { BigNum pbig, pbig1; BigNum ten, zero, rem; char buf[3000]; /* up to 9000 bits */ int bufi = sizeof(buf)-1; int n; buf[bufi] = '\0'; bnBegin (&pbig); bnBegin (&pbig1); bnBegin (&rem); bnBegin (&ten); bnAddQ (&ten, 10); bnBegin (&zero); bnCopy (&pbig, bn); while (bnCmp (&pbig, &zero) != 0) { bnDivMod (&pbig1, &rem, &pbig, &ten); bnCopy (&pbig, &pbig1); n = bnLSWord (&rem); buf[--bufi] = n + '0'; } bnEnd (&pbig); bnEnd (&pbig1); bnEnd (&rem); if (prefix && fputs(prefix, f) < 0) return EOF; fputs (buf+bufi, f); pgpClearMemory (buf, sizeof(buf)); return suffix ? fputs(suffix, f) : 0; }
int32_t ZrtpDH::checkPubKey(uint8_t *pubKeyBytes) const { /* ECC validation (partial), NIST SP800-56A, section 5.6.2.6 */ if (pkType == EC25 || pkType == EC38 || pkType == E414) { dhCtx* tmpCtx = static_cast<dhCtx*>(ctx); EcPoint pub; INIT_EC_POINT(&pub); int32_t len = getPubKeySize() / 2; bnInsertBigBytes(pub.x, pubKeyBytes, 0, len); bnInsertBigBytes(pub.y, pubKeyBytes+len, 0, len); return ecCheckPubKey(&tmpCtx->curve, &pub); } if (pkType == E255) { return 1; } BigNum pubKeyOther; bnBegin(&pubKeyOther); bnInsertBigBytes(&pubKeyOther, pubKeyBytes, 0, getDhSize()); if (pkType == DH2K) { if (bnCmp(&bnP2048MinusOne, &pubKeyOther) == 0) { return 0; } } else if (pkType == DH3K) { if (bnCmp(&bnP3072MinusOne, &pubKeyOther) == 0) { return 0; } } else { return 0; } if (bnCmpQ(&pubKeyOther, 1) == 0) { return 0; } bnEnd(&pubKeyOther); return 1; }
int32_t ZrtpDH::generatePublicKey() { dhCtx* tmpCtx = static_cast<dhCtx*>(ctx); bnBegin(&tmpCtx->pubKey); switch (pkType) { case DH2K: bnExpMod(&tmpCtx->pubKey, &two, &tmpCtx->privKey, &bnP2048); break; case DH3K: bnExpMod(&tmpCtx->pubKey, &two, &tmpCtx->privKey, &bnP3072); break; case EC25: case EC38: case E255: case E414: while (!ecdhGeneratePublic(&tmpCtx->curve, &tmpCtx->pubPoint, &tmpCtx->privKey)) ecGenerateRandomNumber(&tmpCtx->curve, &tmpCtx->privKey); } return 0; }
/* * Return 1 if (sig,siglen) is a valid MPI which signs * hash, of type h. Verify that the type is SHA.1 and * the hash itself matches. */ static int dsaVerify(PGPPubKey const *pubkey, PGPByte const *sig, size_t siglen, PGPHashVTBL const *h, PGPByte const *hash, PGPPublicKeyMessageFormat format) { #if PGP_VERIFY_DISABLE /* [ */ (void)pubkey; (void)sig; (void)siglen; (void)h; (void)hash; (void)format; return kPGPError_FeatureNotAvailable; #else /* PGP_VERIFY_DISABLE */ /* ] [ */ DSApub const *pub = (DSApub *)pubkey->priv; BigNum r, s, w, u2; int i; unsigned qbytes; size_t off; PGPMemoryMgrRef mgr = PGPGetContextMemoryMgr( pubkey->context ); ASSERTDSA(pubkey->pkAlg); /* Hashsize must be at least as big as size of q for legal sig */ if (h->hashsize*8 < bnBits(&pub->q)) { return 0; } #if 0 /* Allow generalizations of SHA, as long as they are big enough */ if (h->algorithm != kPGPHashAlgorithm_SHA) return 0; /* No match for sure! */ #endif bnBegin(&r, mgr, FALSE ); bnBegin(&s, mgr, FALSE ); bnBegin(&w, mgr, FALSE ); bnBegin(&u2, mgr, FALSE ); qbytes = bnBytes(&pub->q); /* sig holds two values. Get first, r, from sig. */ off = 0; if (format == kPGPPublicKeyMessageFormat_X509) { /* Parse SEQUENCE header for 509 sig data */ PGPByte const *sigp = sig + off; PGPUInt32 len; if (pgpBnX509TagLen(&sigp, &len) != X509_TAG_SEQUENCE) { i = kPGPError_MalformedKeyComponent; goto done; } off += sigp - sig; if (len != siglen - off) { i = kPGPError_MalformedKeyComponent; goto done; } } i = pgpBnGetFormatted(&r, sig+off, siglen-off, qbytes, format); if (i <= 0) goto fail; /* Get 2nd value, s, from SIG */ off += i; i = pgpBnGetFormatted(&s, sig+off, siglen-off, qbytes, format); if (i <= 0) goto fail; off += i; if (off != siglen) { i = kPGPError_BadSignatureSize; goto done; } /* * Sanity-check r and s against the subprime q. Both should * be less than q. If not, the signature is clearly bad. */ if (bnCmp(&r, &pub->q) >= 0 || bnCmp(&s, &pub->q) >= 0) { i = 0; /* FAIL */ goto done; } /* Reconstruct hash as u2 */ if (bnInsertBigBytes(&u2, hash, 0, bnBytes(&pub->q)) < 0) goto nomem; /* * Calculate DSS check function.... * Given signature (r,s) and hash H (in bn), compute: * w = s^-1 mod q * u1 = H * w mod q * u2 = r * w mod q * v = g^u1 * y^u2 mod p * if v == r mod q, the signature checks. * * To save space, we put u1 into s, H into u2, and v into w. */ if (bnInv(&w, &s, &pub->q) < 0) goto nomem; if (bnMul(&s, &u2, &w) < 0 || bnMod(&s, &s, &pub->q) < 0) goto nomem; if (bnMul(&u2, &r, &w) < 0 || bnMod(&u2, &u2, &pub->q) < 0) goto nomem; /* Now for the expensive part... */ if (bnDoubleExpMod(&w, &pub->g, &s, &pub->y, &u2, &pub->p) < 0) goto nomem; if (bnMod(&w, &w, &pub->q) < 0) goto nomem; /* Compare result with r, should be equal */ i = bnCmp(&w, &r) == 0; goto done; fail: if (!i) i = kPGPError_BadSignatureSize; goto done; nomem: i = kPGPError_OutOfMemory; goto done; done: bnEnd(&u2); bnEnd(&w); bnEnd(&s); bnEnd(&r); return i; #endif /* PGP_VERIFY_DISABLE */ /* ] */ }
/* * This performs a modular exponentiation using the Chinese Remainder * Algorithm when the modulus is known to have two relatively prime * factors n = p * q, and u = p^-1 (mod q) has been precomputed. * * The chinese remainder algorithm lets a computation mod n be performed * mod p and mod q, and the results combined. Since it takes * (considerably) more than twice as long to perform modular exponentiation * mod n as it does to perform it mod p and mod q, time is saved. * * If x is the desired result, let xp and xq be the values of x mod p * and mod q, respectively. Obviously, x = xp + p * k for some k. * Taking this mod q, xq == xp + p*k (mod q), so p*k == xq-xp (mod q) * and k == p^-1 * (xq-xp) (mod q), so k = u * (xq-xp mod q) mod q. * After that, x = xp + p * k. * * Another savings comes from reducing the exponent d modulo phi(p) * and phi(q). Here, we assume that p and q are prime, so phi(p) = p-1 * and phi(q) = q-1. */ static int bnExpModCRA(BigNum *x, BigNum const *d, BigNum const *p, BigNum const *q, BigNum const *u) { BigNum xp, xq, k; int i; PGPMemoryMgrRef mgr = x->mgr; bndPrintf("Performing Chinese Remainder Algorithm\n"); bndPut("x = ", x); bndPut("p = ", p); bndPut("q = ", q); bndPut("d = ", d); bndPut("u = ", u); bnBegin(&xp, mgr, TRUE); bnBegin(&xq, mgr, TRUE); bnBegin(&k, mgr, TRUE); /* Compute xp = (x mod p) ^ (d mod p-1) mod p */ if (bnCopy(&xp, p) < 0) /* First, use xp to hold p-1 */ goto fail; (void)bnSubQ(&xp, 1); /* p > 1, so subtracting is safe. */ if (bnMod(&k, d, &xp) < 0) /* k = d mod (p-1) */ goto fail; bndPut("d mod p-1 = ", &k); if (bnMod(&xp, x, p) < 0) /* Now xp = (x mod p) */ goto fail; bndPut("x mod p = ", &xp); if (bnExpMod(&xp, &xp, &k, p) < 0) /* xp = (x mod p)^k mod p */ goto fail; bndPut("xp = x^d mod p = ", &xp); /* Compute xq = (x mod q) ^ (d mod q-1) mod q */ if (bnCopy(&xq, q) < 0) /* First, use xq to hold q-1 */ goto fail; (void)bnSubQ(&xq, 1); /* q > 1, so subtracting is safe. */ if (bnMod(&k, d, &xq) < 0) /* k = d mod (q-1) */ goto fail; bndPut("d mod q-1 = ", &k); if (bnMod(&xq, x, q) < 0) /* Now xq = (x mod q) */ goto fail; bndPut("x mod q = ", &xq); if (bnExpMod(&xq, &xq, &k, q) < 0) /* xq = (x mod q)^k mod q */ goto fail; bndPut("xq = x^d mod q = ", &xq); /* xp < p and PGP has p < q, so this is a no-op, but just in case */ if (bnMod(&k, &xp, q) < 0) goto fail; bndPut("xp mod q = ", &k); i = bnSub(&xq, &k); bndPut("xq - xp = ", &xq); bndPrintf("With sign %d\n", i); if (i < 0) goto fail; if (i) { /* * Borrow out - xq-xp is negative, so bnSub returned * xp-xq instead, the negative of the true answer. * Add q back (which is subtracting from the negative) * so the sign flips again. */ i = bnSub(&xq, q); if (i < 0) goto fail; bndPut("xq - xp mod q = ", &xq); bndPrintf("With sign %d\n", i); /* Must be 1 */ } /* Compute k = xq * u mod q */ if (bnMul(&k, u, &xq) < 0) goto fail; bndPut("(xq-xp) * u = ", &k); if (bnMod(&k, &k, q) < 0) goto fail; bndPut("k = (xq-xp)*u % q = ", &k); /* Now x = k * p + xp is the final answer */ if (bnMul(x, &k, p) < 0) goto fail; bndPut("k * p = ", x); if (bnAdd(x, &xp) < 0) goto fail; bndPut("k*p + xp = ", x); #if BNDEBUG /* @@@ DEBUG - do it the slow way for comparison */ if (bnMul(&xq, p, q) < 0) goto fail; bndPut("n = p*q = ", &xq); if (bnExpMod(&xp, x, d, &xq) < 0) goto fail; bndPut("x^d mod n = ", &xp); if (bnCmp(x, &xp) != 0) { bndPrintf("Nasty!!!\n"); goto fail; } bnSetQ(&k, 17); bnExpMod(&xp, &xp, &k, &xq); bndPut("x^17 mod n = ", &xp); #endif bnEnd(&xp); bnEnd(&xq); bnEnd(&k); return 0; fail: bnEnd(&xp); bnEnd(&xq); bnEnd(&k); return kPGPError_OutOfMemory; }
/* * Similar, but searches forward from the given starting value in steps of * "step" rather than 1. The step size must be even, and bn must be odd. * Among other possibilities, this can be used to generate "strong" * primes, where p-1 has a large prime factor. */ int bnPrimeGenStrong(BigNum *bn, BigNum const *step, int (*f)(void *arg, int c), void *arg) { int retval; unsigned p, prev; BigNum a, e; int modexps = 0; #ifdef MSDOS unsigned char *sieve; #else unsigned char sieve[SIEVE]; #endif PGPBoolean isSecure = bn->isSecure; PGPMemoryMgrRef mgr = bn->mgr; #ifdef MSDOS sieve = bniMemAlloc(SIEVE); if (!sieve) return -1; #endif /* Step must be even and bn must be odd */ pgpAssert((bnLSWord(step) & 1) == 0); pgpAssert((bnLSWord(bn) & 1) == 1); bnBegin(&a, mgr, isSecure); bnBegin(&e, mgr, isSecure); for (;;) { if (sieveBuildBig(sieve, SIEVE, bn, step, 0) < 0) goto failed; p = prev = 0; if (sieve[0] & 1 || (p = sieveSearch(sieve, SIEVE, p)) != 0) { do { /* * Adjust bn to have the right value, * adding (p-prev) * 2*step. */ pgpAssert(p >= prev); /* Compute delta into a */ if (bnMulQ(&a, step, p-prev) < 0) goto failed; if (bnAdd(bn, &a) < 0) goto failed; prev = p; retval = primeTest(bn, &e, &a, f, arg); if (retval <= 0) goto done; /* Success! */ modexps += retval; if (f && (retval = f(arg, '.')) < 0) goto done; /* And try again */ p = sieveSearch(sieve, SIEVE, p); } while (p); } /* Ran out of sieve space - increase bn and keep trying. */ #if SIEVE*8 == 65536 /* Corner case that will never actually happen */ if (!prev) { if (bnAdd(bn, step) < 0) goto failed; p = 65535; } else { p = (unsigned)(SIEVE*8 - prev); } #else p = SIEVE*8 - prev; #endif if (bnMulQ(&a, step, p) < 0 || bnAdd(bn, &a) < 0) goto failed; if (f && (retval = f(arg, '/')) < 0) goto done; } /* for (;;) */ failed: retval = -1; done: bnEnd(&e); bnEnd(&a); #ifdef MSDOS bniMemFree(sieve, SIEVE); #else bniMemWipe(sieve, sizeof(sieve)); #endif return retval < 0 ? retval : modexps + CONFIRMTESTS; }
/* * Modifies the bignum to return a nearby (slightly larger) number which * is a probable prime. Returns >=0 on success or -1 on failure (out of * memory). The return value is the number of unsuccessful modular * exponentiations performed. This never gives up searching. * * All other arguments are optional. They may be NULL. They are: * * unsigned (*randfunc)(unsigned limit) * For better distributed numbers, supply a non-null pointer to a * function which returns a random x, 0 <= x < limit. (It may make it * simpler to know that 0 < limit <= SHUFFLE, so you need at most a byte.) * The program generates a large window of sieve data and then does * pseudoprimality tests on the data. If a randfunc function is supplied, * the candidates which survive sieving are shuffled with a window of * size SHUFFLE before testing to increase the uniformity of the prime * selection. This isn't perfect, but it reduces the correlation between * the size of the prime-free gap before a prime and the probability * that that prime will be found by a sequential search. * * If randfunc is NULL, sequential search is used. If you want sequential * search, note that the search begins with the given number; if you're * trying to generate consecutive primes, you must increment the previous * one by two before calling this again. * * int (*f)(void *arg, int c), void *arg * The function f argument, if non-NULL, is called with progress indicator * characters for printing. A dot (.) is written every time a primality test * is failed, a star (*) every time one is passed, and a slash (/) in the * (very rare) case that the sieve was emptied without finding a prime * and is being refilled. f is also passed the void *arg argument for * private context storage. If f returns < 0, the test aborts and returns * that value immediately. (bn is set to the last value tested, so you * can increment bn and continue.) * * The "exponent" argument, and following unsigned numbers, are exponents * for which an inverse is desired, modulo p. For a d to exist such that * (x^e)^d == x (mod p), then d*e == 1 (mod p-1), so gcd(e,p-1) must be 1. * The prime returned is constrained to not be congruent to 1 modulo * any of the zero-terminated list of 16-bit numbers. Note that this list * should contain all the small prime factors of e. (You'll have to test * for large prime factors of e elsewhere, but the chances of needing to * generate another prime are low.) * * The list is terminated by a 0, and may be empty. */ int bnPrimeGen(BigNum *bn, unsigned (*randfunc)(unsigned), int (*f)(void *arg, int c), void *arg, unsigned exponent, ...) { int retval; int modexps = 0; unsigned short offsets[SHUFFLE]; unsigned i, j; unsigned p, q, prev; BigNum a, e; #ifdef MSDOS unsigned char *sieve; #else unsigned char sieve[SIEVE]; #endif #ifdef MSDOS sieve = bniMemAlloc(SIEVE); if (!sieve) return -1; #endif PGPBoolean isSecure = TRUE; PGPMemoryMgrRef mgr = bn->mgr; bnBegin(&a, mgr, isSecure); bnBegin(&e, mgr, isSecure); #if 0 /* Self-test (not used for production) */ { BigNum t; static unsigned char const prime1[] = {5}; static unsigned char const prime2[] = {7}; static unsigned char const prime3[] = {11}; static unsigned char const prime4[] = {1, 1}; /* 257 */ static unsigned char const prime5[] = {0xFF, 0xF1}; /* 65521 */ static unsigned char const prime6[] = {1, 0, 1}; /* 65537 */ static unsigned char const prime7[] = {1, 0, 3}; /* 65539 */ /* A small prime: 1234567891 */ static unsigned char const prime8[] = {0x49, 0x96, 0x02, 0xD3}; /* A slightly larger prime: 12345678901234567891 */ static unsigned char const prime9[] = { 0xAB, 0x54, 0xA9, 0x8C, 0xEB, 0x1F, 0x0A, 0xD3 }; /* * No, 123456789012345678901234567891 isn't prime; it's just a * lucky, easy-to-remember conicidence. (You have to go to * ...4567907 for a prime.) */ static struct { unsigned char const *prime; unsigned size; } const primelist[] = { { prime1, sizeof(prime1) }, { prime2, sizeof(prime2) }, { prime3, sizeof(prime3) }, { prime4, sizeof(prime4) }, { prime5, sizeof(prime5) }, { prime6, sizeof(prime6) }, { prime7, sizeof(prime7) }, { prime8, sizeof(prime8) }, { prime9, sizeof(prime9) } }; bnBegin(&t); for (i = 0; i < sizeof(primelist)/sizeof(primelist[0]); i++) { bnInsertBytes(&t, primelist[i].prime, 0, primelist[i].size); bnCopy(&e, &t); (void)bnSubQ(&e, 1); bnTwoExpMod(&a, &e, &t); p = bnBits(&a); if (p != 1) { printf( "Bug: Fermat(2) %u-bit output (1 expected)\n", p); fputs("Prime = 0x", stdout); for (j = 0; j < primelist[i].size; j++) printf("%02X", primelist[i].prime[j]); putchar('\n'); } bnSetQ(&a, 3); bnExpMod(&a, &a, &e, &t); p = bnBits(&a); if (p != 1) { printf( "Bug: Fermat(3) %u-bit output (1 expected)\n", p); fputs("Prime = 0x", stdout); for (j = 0; j < primelist[i].size; j++) printf("%02X", primelist[i].prime[j]); putchar('\n'); } } bnEnd(&t); } #endif /* First, make sure that bn is odd. */ if ((bnLSWord(bn) & 1) == 0) (void)bnAddQ(bn, 1); retry: /* Then build a sieve starting at bn. */ sieveBuild(sieve, SIEVE, bn, 2, 0); /* Do the extra exponent sieving */ if (exponent) { va_list ap; unsigned t = exponent; va_start(ap, exponent); do { /* The exponent had better be odd! */ pgpAssert(t & 1); i = bnModQ(bn, t); /* Find 1-i */ if (i == 0) i = 1; else if (--i) i = t - i; /* Divide by 2, modulo the exponent */ i = (i & 1) ? i/2 + t/2 + 1 : i/2; /* Remove all following multiples from the sieve. */ sieveSingle(sieve, SIEVE, i, t); /* Get the next exponent value */ t = va_arg(ap, unsigned); } while (t); va_end(ap); } /* Fill up the offsets array with the first SHUFFLE candidates */ i = p = 0; /* Get first prime */ if (sieve[0] & 1 || (p = sieveSearch(sieve, SIEVE, p)) != 0) { offsets[i++] = p; p = sieveSearch(sieve, SIEVE, p); } /* * Okay, from this point onwards, p is always the next entry * from the sieve, that has not been added to the shuffle table, * and is 0 iff the sieve has been exhausted. * * If we want to shuffle, then fill the shuffle table until the * sieve is exhausted or the table is full. */ if (randfunc && p) { do { offsets[i++] = p; p = sieveSearch(sieve, SIEVE, p); } while (p && i < SHUFFLE); } /* Choose a random candidate for experimentation */ prev = 0; while (i) { /* Pick a random entry from the shuffle table */ j = randfunc ? randfunc(i) : 0; q = offsets[j]; /* The entry to use */ /* Replace the entry with some more data, if possible */ if (p) { offsets[j] = p; p = sieveSearch(sieve, SIEVE, p); } else { offsets[j] = offsets[--i]; offsets[i] = 0; } /* Adjust bn to have the right value */ if ((q > prev ? bnAddMult(bn, q-prev, 2) : bnSubMult(bn, prev-q, 2)) < 0) goto failed; prev = q; /* Now do the Fermat tests */ retval = primeTest(bn, &e, &a, f, arg); if (retval <= 0) goto done; /* Success or error */ modexps += retval; if (f && (retval = f(arg, '.')) < 0) goto done; } /* Ran out of sieve space - increase bn and keep trying. */ if (bnAddMult(bn, SIEVE*8-prev, 2) < 0) goto failed; if (f && (retval = f(arg, '/')) < 0) goto done; goto retry; failed: retval = -1; done: bnEnd(&e); bnEnd(&a); bniMemWipe(offsets, sizeof(offsets)); #ifdef MSDOS bniMemFree(sieve, SIEVE); #else bniMemWipe(sieve, sizeof(sieve)); #endif return retval < 0 ? retval : modexps + CONFIRMTESTS; }
int rsa_INIT_e(RSA_CTX *ctx){ bnBegin(&ctx->e); ctx->ebits=sizeof(unsigned long int); return OK; }
int rsa_INIT_d(RSA_CTX *ctx,unsigned long int bitlen){ bnBegin(&ctx->d); ctx->bits=bitlen; return OK; }
/*----------------------------------------------------------------------------*/ zrtp_status_t zrtp_stream_attach(zrtp_session_t *session, zrtp_stream_t** stream) { uint32_t i = 0; zrtp_status_t s = zrtp_status_fail; zrtp_stream_t* new_stream = NULL; ZRTP_LOG(3, (_ZTU_,"ATTACH NEW STREAM to sID=%d:\n", session->id)); /* * Initialize first unused stream. If there are no available streams return error. */ zrtp_mutex_lock(session->streams_protector); for (i=0; i<ZRTP_MAX_STREAMS_PER_SESSION; i++) { if (ZRTP_STATE_NONE == session->streams[i].state) { new_stream = &session->streams[i]; zrtp_memset(new_stream, 0, sizeof(zrtp_stream_t)); break; } } zrtp_mutex_unlock(session->streams_protector); if (!new_stream) { ZRTP_LOG(1, (_ZTU_,"\tWARNING! Can't attach one more stream. Limit is reached." " Use #ZRTP_MAX_STREAMS_PER_SESSION. sID=%u\n", session->id)); return zrtp_status_alloc_fail; } /* * Initialize the private data stream with default initial values */ zrtp_mutex_init(&new_stream->stream_protector); _zrtp_change_state(new_stream, ZRTP_STATE_ACTIVE); new_stream->mode = ZRTP_STREAM_MODE_CLEAR; new_stream->id = session->zrtp->streams_count++; new_stream->session = session; new_stream->zrtp = session->zrtp; new_stream->mitm_mode = ZRTP_MITM_MODE_UNKN; new_stream->is_hello_received = 0; ZSTR_SET_EMPTY(new_stream->cc.hmackey); ZSTR_SET_EMPTY(new_stream->cc.peer_hmackey); ZSTR_SET_EMPTY(new_stream->cc.zrtp_key); ZSTR_SET_EMPTY(new_stream->cc.peer_zrtp_key); new_stream->dh_cc.initialized_with = ZRTP_COMP_UNKN; bnBegin(&new_stream->dh_cc.peer_pv); ZSTR_SET_EMPTY(new_stream->dh_cc.dhss); ZRTP_LOG(3, (_ZTU_,"\tEmpty slot was found - initializing new stream with ID=%u.\n", new_stream->id)); do { zrtp_string32_t hash_buff = ZSTR_INIT_EMPTY(hash_buff); zrtp_hash_t *hash = zrtp_comp_find(ZRTP_CC_HASH, ZRTP_HASH_SHA256, new_stream->zrtp); s = zrtp_status_algo_fail; if (sizeof(uint16_t) != zrtp_randstr( new_stream->zrtp, (uint8_t*)&new_stream->media_ctx.high_out_zrtp_seq, sizeof(uint16_t))) { break; } /* * Compute and store message hashes to prevent DoS attacks. * Generate H0 as a random nonce and compute H1, H2 and H3 * using the leftmost 128 bits from every hash. * Then insert these directly into the message structures. */ zrtp_memset(&new_stream->messages, 0, sizeof(new_stream->messages)); ZSTR_SET_EMPTY(new_stream->messages.h0); ZSTR_SET_EMPTY(new_stream->messages.signaling_hash); /* Generate Random nonce, compute H1 and store in the DH packet */ new_stream->messages.h0.length = (uint16_t)zrtp_randstr( new_stream->zrtp, (unsigned char*)new_stream->messages.h0.buffer, ZRTP_MESSAGE_HASH_SIZE); if (ZRTP_MESSAGE_HASH_SIZE != new_stream->messages.h0.length) { break; } s = hash->hash(hash, ZSTR_GV(new_stream->messages.h0), ZSTR_GV(hash_buff)); if (zrtp_status_ok != s) { break; } zrtp_memcpy(new_stream->messages.dhpart.hash, hash_buff.buffer, ZRTP_MESSAGE_HASH_SIZE); /* Compute H2 for the Commit */ s = hash->hash_c(hash, (char*)new_stream->messages.dhpart.hash, ZRTP_MESSAGE_HASH_SIZE, ZSTR_GV(hash_buff)); if (zrtp_status_ok != s) { break; } zrtp_memcpy(new_stream->messages.commit.hash, hash_buff.buffer, ZRTP_MESSAGE_HASH_SIZE); /* Compute H3 for the Hello message */ s = hash->hash_c(hash, (char*)new_stream->messages.commit.hash, ZRTP_MESSAGE_HASH_SIZE, ZSTR_GV(hash_buff)); if (zrtp_status_ok != s) { break; } zrtp_memcpy(new_stream->messages.hello.hash, hash_buff.buffer, ZRTP_MESSAGE_HASH_SIZE); s = zrtp_status_ok; } while (0); if (zrtp_status_ok != s) { ZRTP_LOG(1, (_ZTU_,"\tERROR! Fail to compute messages hashes <%s>.\n", zrtp_log_status2str(s))); return s; } /* * Preparing HELLO based on user's profile */ ZRTP_LOG(3, (_ZTU_,"\tPreparing ZRTP Hello according to the Session profile.\n")); { zrtp_packet_Hello_t* hello = &new_stream->messages.hello; uint8_t i = 0; int8_t* comp_ptr = NULL; /* Set Protocol Version and ClientID */ zrtp_memcpy(hello->version, ZRTP_PROTOCOL_VERSION, ZRTP_VERSION_SIZE); zrtp_memcpy(hello->cliend_id, session->zrtp->client_id.buffer, session->zrtp->client_id.length); /* Set flags. */ hello->pasive = (ZRTP_LICENSE_MODE_PASSIVE == session->zrtp->lic_mode) ? 1 : 0; hello->uflag = (ZRTP_LICENSE_MODE_UNLIMITED == session->zrtp->lic_mode) ? 1 : 0; hello->mitmflag = session->zrtp->is_mitm; hello->sigflag = 0; zrtp_memcpy(hello->zid, session->zid.buffer, session->zid.length); comp_ptr = (int8_t*)hello->comp; i = 0; while ( session->profile.hash_schemes[i]) { zrtp_memcpy( comp_ptr, zrtp_comp_id2type(ZRTP_CC_HASH, session->profile.hash_schemes[i++]), ZRTP_COMP_TYPE_SIZE ); comp_ptr += ZRTP_COMP_TYPE_SIZE; } hello->hc = i; i = 0; while (session->profile.cipher_types[i]) { zrtp_memcpy( comp_ptr, zrtp_comp_id2type(ZRTP_CC_CIPHER, session->profile.cipher_types[i++]), ZRTP_COMP_TYPE_SIZE ); comp_ptr += ZRTP_COMP_TYPE_SIZE; } hello->cc = i; i = 0; while (session->profile.auth_tag_lens[i] ) { zrtp_memcpy( comp_ptr, zrtp_comp_id2type(ZRTP_CC_ATL, session->profile.auth_tag_lens[i++]), ZRTP_COMP_TYPE_SIZE ); comp_ptr += ZRTP_COMP_TYPE_SIZE; } hello->ac = i; i = 0; while (session->profile.pk_schemes[i] ) { zrtp_memcpy( comp_ptr, zrtp_comp_id2type(ZRTP_CC_PKT, session->profile.pk_schemes[i++]), ZRTP_COMP_TYPE_SIZE ); comp_ptr += ZRTP_COMP_TYPE_SIZE; } hello->kc = i; i = 0; while (session->profile.sas_schemes[i]) { zrtp_memcpy( comp_ptr, zrtp_comp_id2type(ZRTP_CC_SAS, session->profile.sas_schemes[i++]), ZRTP_COMP_TYPE_SIZE ); comp_ptr += ZRTP_COMP_TYPE_SIZE; } hello->sc = i; /* * Hmac will appear at the end of the message, after the dynamic portion. * i is the length of the dynamic part. */ i = (hello->hc + hello->cc + hello->ac + hello->kc + hello->sc) * ZRTP_COMP_TYPE_SIZE; _zrtp_packet_fill_msg_hdr( new_stream, ZRTP_HELLO, ZRTP_HELLO_STATIC_SIZE + i + ZRTP_HMAC_SIZE, &hello->hdr); } *stream = new_stream; ZRTP_LOG(3, (_ZTU_,"ATTACH NEW STREAM - DONE.\n")); return zrtp_status_ok; }
static int dsaUnlock(PGPSecKey *seckey, PGPEnv const *env, char const *phrase, size_t plen, PGPBoolean hashedPhrase) { DSAsecPlus *sec = (DSAsecPlus *)seckey->priv; BigNum x; PGPCFBContext *cfb = NULL; unsigned v; unsigned alg; unsigned checksum; int i; PGPMemoryMgrRef mgr = NULL; mgr = PGPGetContextMemoryMgr( seckey->context ); bnBegin(&x, mgr, TRUE); ASSERTDSA(seckey->pkAlg); /* Check packet for basic consistency */ i = pgpBnParse(sec->cryptkey, sec->cklen, 4, &v, NULL, NULL, NULL); if (i <= 0) goto fail; /* OK, read the public data */ i = pgpBnGetPlain(&sec->s.p, sec->cryptkey+v, sec->cklen-v); if (i <= 0) goto fail; v += i; i = pgpBnGetPlain(&sec->s.q, sec->cryptkey+v, sec->cklen-v); if (i <= 0) goto fail; v += i; i = pgpBnGetPlain(&sec->s.g, sec->cryptkey+v, sec->cklen-v); if (i <= 0) goto fail; v += i; i = pgpBnGetPlain(&sec->s.y, sec->cryptkey+v, sec->cklen-v); if (i <= 0) goto fail; v += i; /* Get the encryption algorithm (cipher number). 0 == no encryption */ alg = sec->cryptkey[v]; /* If the phrase is empty, set it to NULL */ if (plen == 0) phrase = NULL; /* * We need a pass if it is encrypted, and we cannot have a * password if it is NOT encrypted. I.e., this is a logical * xor (^^) */ if (!phrase != !sec->cryptkey[v]) goto badpass; i = pgpCipherSetup(sec->cryptkey + v, sec->cklen - v, phrase, plen, hashedPhrase, env, &cfb); if (i < 0) goto done; v += i; checksum = 0; i = pgpBnGetNew(&x, sec->cryptkey + v, sec->cklen - v, cfb, &checksum); if (i <= 0) goto badpass; v += i; if (bnCmp(&x, &sec->s.q) >= 0) goto badpass; /* Wrong passphrase: x must be < q */ /* Check that we ended in the right place */ if (sec->cklen - v != 2) { i = kPGPError_KEY_LONG; goto fail; } checksum &= 0xffff; if (checksum != pgpChecksumGetNew(sec->cryptkey+v, cfb)) goto badpass; /* * Note that the "nomem" case calls bnEnd() * more than once, but this is guaranteed harmless. */ if (bnCopy(&sec->s.x, &x) < 0) goto nomem; i = 1; /* Decrypted! */ sec->locked = 0; goto done; nomem: i = kPGPError_OutOfMemory; goto done; fail: if (!i) i = kPGPError_KeyPacketTruncated; goto done; badpass: i = 0; /* Incorrect passphrase */ goto done; done: bnEnd(&x); if (cfb) PGPFreeCFBContext(cfb); return i; }
/* * lhs-rhs. dest and src may be the same, but bnSetQ(dest, 0) is faster. * if dest < src, returns error and dest is undefined. */ PGPError PGPBigNumSubtract( PGPBigNumRef lhs, PGPBigNumRef rhs, PGPBigNumRef dest, PGPBoolean * underflowPtr ) { PGPError err = kPGPError_NoErr; int bnError; PGPBoolean underflow = FALSE; if ( IsntNull( underflowPtr ) ) *underflowPtr = FALSE; pgpValidateBigNum( lhs ); pgpValidateBigNum( rhs ); pgpValidateBigNum( dest ); if ( lhs == dest ) { bnError = bnSub( &dest->bn, &rhs->bn ); underflow = (bnError == 1); bnError = 0; } else if ( rhs == dest ) { BigNum temp; PGPBoolean secure; secure = lhs->bn.isSecure || rhs->bn.isSecure || dest->bn.isSecure; bnBegin( &temp, dest->bn.mgr, secure ); bnError = bnCopy( &temp, &lhs->bn ); if ( bnError == 0 ) { bnError = bnSub( &temp, &rhs->bn ); underflow = (bnError == 1); bnError = 0; bnError = bnCopy( &dest->bn, &temp ); } bnEnd( &temp ); } else { bnError = bnCopy( &dest->bn, &lhs->bn ); if ( bnError == 0 ) { bnError = bnSub( &dest->bn, &rhs->bn ); underflow = (bnError == 1); bnError = 0; } } if ( IsntNull( underflowPtr ) ) *underflowPtr = underflow; if ( bnError == -1 ) err = kPGPError_OutOfMemory; return( err ); }
/* * Turn the algorithm-specific parts of a public key into a PGPPubKey * structure. A public key's DSA-specific part is: * * 0 2+i MPI for prime * 2+i 2+t MPI for order * 4+i+t 2+u MPI for generator * 6+i+t+u 2+v MPI for public key * 8+i+t+u+v */ PGPPubKey * dsaPubFromBuf( PGPContextRef context, PGPByte const * buf, size_t size, PGPError * error) { PGPPubKey *pubkey; DSApub *pub; unsigned i, t, u, v; int w; PGPError err = kPGPError_OutOfMemory; PGPMemoryMgrRef mgr = PGPGetContextMemoryMgr( context ); bnInit(); w = pgpBnParse(buf, size, 4, &i, &t, &u, &v); if (w < 0) { *error = (PGPError)w; return NULL; } if (t <= i+2 || (buf[t-1] & 1) == 0) { /* Too small or even prime p */ *error = kPGPError_MalformedKeyComponent; return NULL; } if (u <= t+2 || (buf[u-1] & 1) == 0) { /* Too small or even order q */ *error = kPGPError_MalformedKeyComponent; return NULL; } pub = (DSApub *)pgpContextMemAlloc( context, sizeof(*pub), kPGPMemoryMgrFlags_Clear); if (pub) { pubkey = (PGPPubKey *)pgpContextMemAlloc( context, sizeof(*pubkey), kPGPMemoryMgrFlags_Clear); if (pubkey) { pubkey->context = context; bnBegin(&pub->p, mgr, FALSE ); bnBegin(&pub->q, mgr, FALSE ); bnBegin(&pub->g, mgr, FALSE ); bnBegin(&pub->y, mgr, FALSE ); if (bnInsertBigBytes(&pub->p, buf+i+2, 0, t-i-2) >= 0 && bnInsertBigBytes(&pub->q, buf+t+2, 0, u-t-2) >= 0 && bnInsertBigBytes(&pub->g, buf+u+2, 0, v-u-2) >= 0 && bnInsertBigBytes(&pub->y, buf+v+2, 0, w-v-2) >= 0) { if (dsaKeyTooBig (pub, NULL)) { err = kPGPError_KeyTooLarge; } else { dsaFillPubkey(pubkey, pub); *error = 0; return pubkey; } } /* Failed = clean up and return NULL */ bnEnd(&pub->p); bnEnd(&pub->q); bnEnd(&pub->g); bnEnd(&pub->y); pgpContextMemFree( context, pubkey); } pgpContextMemFree( context, pub); } *error = err; return NULL; }
/* * Modifies the given bnq to return a prime slightly larger, and then * modifies the given bnp to be a prime which is == 1 (mod bnq). * This is done by decreasing bnp until it is == 1 (mod 2*bnq), and * then searching forward in steps of 2*bnq. * Returns >=0 on success or -1 on failure (out of memory). On * success, the return value is the number of modular exponentiations * performed (excluding the final confirmation). * This never gives up searching. * * int (*f)(void *arg, int c), void *arg * The function f argument, if non-NULL, is called with progress indicator * characters for printing. A dot (.) is written every time a primality test * is failed, a star (*) every time one is passed, and a slash (/) in the * case that the sieve was emptied without finding a prime and is being * refilled. f is also passed the void *arg argument for private * context storage. If f returns < 0, the test aborts and returns * that value immediately. * * Apologies to structured programmers for all the GOTOs. */ int dsaPrimeGen(BigNum *bnq, BigNum *bnp, int (*f)(void *arg, int c), void *arg) { int retval; unsigned p, prev; BigNum a, e; int modexps = 0; #ifdef MSDOS unsigned char *sieve; #else unsigned char sieve[SIEVE]; #endif #ifdef MSDOS sieve = bniMemAlloc(SIEVE); if (!sieve) return -1; #endif bnBegin(&a); bnBegin(&e); /* Phase 1: Search forwards from bnq for a suitable prime. */ /* First, make sure that bnq is odd. */ (void)bnAddQ(bnq, ~bnLSWord(bnq) & 1); for (;;) { if (sieveBuild(sieve, SIEVE, bnq, 2, 1) < 0) goto failed; p = prev = 0; if (sieve[0] & 1 || (p = sieveSearch(sieve, SIEVE, p)) != 0) { do { /* * Adjust bn to have the right value, * incrementing in steps of < 65536. * 32767 = 65535/2. */ pgpAssert(p >= prev); prev = p-prev; /* Delta - add 2*prev to bn */ #if SIEVE*8*2 >= 65536 while (prev > 32767) { if (bnAddQ(bnq, 2*32767) < 0) goto failed; prev -= 32767; } #endif if (bnAddQ(bnq, 2*prev) < 0) goto failed; prev = p; retval = primeTest(bnq, &e, &a, f, arg); if (retval <= 0) goto phase2; /* Success! */ modexps += retval; if (f && (retval = f(arg, '.')) < 0) goto done; /* And try again */ p = sieveSearch(sieve, SIEVE, p); } while (p); } /* Ran out of sieve space - increase bn and keep trying. */ #if SIEVE*8*2 >= 65536 p = ((SIEVE-1)*8+7) - prev; /* Number of steps (of 2) */ while (p >= 32737) { if (bnAddQ(bnq, 2*32767) < 0) goto failed; p -= 32767; } if (bnAddQ(bnq, 2*(p+1)) < 0) goto failed; #else if (bnAddQ(bnq, SIEVE*8*2 - prev) < 0) goto failed; #endif if (f && (retval = f(arg, '/')) < 0) goto done; } /* for (;;) */ /* * Phase 2: find a suitable prime bnp == 1 (mod bnq). */ /* * Since bnp will be, and bnq is, odd, bnp-1 must be a multiple * of 2*bnq. So start by subtracting the excess. */ phase2: /* Double bnq until end of bnp search. */ if (bnAdd(bnq, bnq) < 0) goto failed; bnMod(&a, bnp, bnq); if (bnBits(&a)) { /* Will always be true, but... */ (void)bnSubQ(&a, 1); if (bnSub(bnp, &a)) /* Also error on underflow */ goto failed; } /* Okay, now we're ready. */ for (;;) { if (sieveBuildBig(sieve, SIEVE, bnp, bnq, 0) < 0) goto failed; if (f && (retval = f(arg, '/')) < 0) goto done; p = prev = 0; if (sieve[0] & 1 || (p = sieveSearch(sieve, SIEVE, p)) != 0) { do { /* * Adjust bn to have the right value, * adding (p-prev) * 2*bnq. */ pgpAssert(p >= prev); /* Compute delta into a */ if (bnMulQ(&a, bnq, p-prev) < 0) goto failed; if (bnAdd(bnp, &a) < 0) goto failed; prev = p; retval = primeTest(bnp, &e, &a, f, arg); if (retval <= 0) goto done; /* Success! */ modexps += retval; if (f && (retval = f(arg, '.')) < 0) goto done; /* And try again */ p = sieveSearch(sieve, SIEVE, p); } while (p); } /* Ran out of sieve space - increase bn and keep trying. */ #if SIEVE*8 == 65536 if (prev) { p = (unsigned)(SIEVE*8ul - prev); } else { /* Corner case that will never actually happen */ if (bnAdd(bnp, bnq) < 0) goto failed; p = 65535; } #else p = SIEVE*8 - prev; #endif /* Add p * bnq to bnp */ if (bnMulQ(&a, bnq, p) < 0) goto failed; if (bnAdd(bnp, &a) < 0) goto failed; } /* for (;;) */ failed: retval = -1; done: /* Shift bnq back down by the extra bit again. */ bnRShift(bnq, 1); /* Harmless even if bnq is random */ bnEnd(&e); bnEnd(&a); #ifdef MSDOS bniMemFree(sieve, SIEVE); #else bniMemWipe(sieve, sizeof(sieve)); #endif return retval < 0 ? retval : modexps + 2*CONFIRMTESTS; }
/*---------------------------------------------------------------------------*/ static zrtp_status_t _derive_s0(zrtp_stream_t* stream, int is_initiator) { static const zrtp_string32_t zrtp_kdf_label = ZSTR_INIT_WITH_CONST_CSTRING(ZRTP_KDF_STR); static const zrtp_string32_t zrtp_sess_label = ZSTR_INIT_WITH_CONST_CSTRING(ZRTP_SESS_STR); static const zrtp_string32_t zrtp_multi_label = ZSTR_INIT_WITH_CONST_CSTRING(ZRTP_MULTI_STR); static const zrtp_string32_t zrtp_presh_label = ZSTR_INIT_WITH_CONST_CSTRING(ZRTP_PRESH_STR); zrtp_session_t *session = stream->session; zrtp_secrets_t* secrets = &session->secrets; zrtp_proto_crypto_t* cc = stream->protocol->cc; void* hash_ctx = NULL; char print_buff[256]; switch (stream->mode) { /* * S0 computing for FULL DH exchange * S0 computing. s0 is the master shared secret used for all * cryptographic operations. In particular, note the inclusion * of "total_hash", a hash of all packets exchanged up to this * point. This belatedly detects any tampering with earlier * packets, e.g. bid-down attacks. * * s0 = hash( 1 | DHResult | "ZRTP-HMAC-KDF" | ZIDi | ZIDr | * total_hash | len(s1) | s1 | len(s2) | s2 | len(s3) | s3 ) * The constant 1 and all lengths are 32 bits big-endian values. * The fields without length prefixes are fixed-witdh: * - DHresult is fixed to the width of the DH prime. * - The hash type string and ZIDs are fixed width. * - total_hash is fixed by the hash negotiation. * The constant 1 is per NIST SP 800-56A section 5.8.1, and is * a counter which can be incremented to generate more than 256 * bits of key material. * ======================================================================== */ case ZRTP_STREAM_MODE_DH: { zrtp_proto_secret_t *C[3] = { 0, 0, 0}; int i = 0; uint32_t comp_length = 0; zrtp_stringn_t *zidi = NULL, *zidr = NULL; struct BigNum dhresult; #if (defined(ZRTP_USE_STACK_MINIM) && (ZRTP_USE_STACK_MINIM == 1)) zrtp_uchar1024_t* buffer = zrtp_sys_alloc( sizeof(zrtp_uchar1024_t) ); if (!buffer) { return zrtp_status_alloc_fail; } #else zrtp_uchar1024_t holder; zrtp_uchar1024_t* buffer = &holder; #endif ZRTP_LOG(3,(_ZTU_,"\tDERIVE S0 from DH exchange and RS secrets...\n")); ZRTP_LOG(3,(_ZTU_,"\t my rs1ID:%s\n", hex2str(cc->rs1.id.buffer, cc->rs1.id.length, print_buff, sizeof(print_buff)))); ZRTP_LOG(3,(_ZTU_,"\t his rs1ID:%s\n", hex2str((const char*)stream->messages.peer_dhpart.rs1ID, ZRTP_RSID_SIZE, print_buff, sizeof(print_buff)))); ZRTP_LOG(3,(_ZTU_,"\t his rs1ID comp:%s\n", hex2str(cc->rs1.peer_id.buffer, cc->rs1.peer_id.length, print_buff, sizeof(print_buff)))); ZRTP_LOG(3,(_ZTU_,"\t my rs2ID:%s\n", hex2str(cc->rs2.id.buffer, cc->rs2.id.length, print_buff, sizeof(print_buff)))); ZRTP_LOG(3,(_ZTU_,"\t his rs2ID:%s\n", hex2str((const char*)stream->messages.peer_dhpart.rs2ID, ZRTP_RSID_SIZE, print_buff, sizeof(print_buff)))); ZRTP_LOG(3,(_ZTU_,"\t his rs2ID comp:%s\n", hex2str(cc->rs2.peer_id.buffer, cc->rs2.peer_id.length, print_buff, sizeof(print_buff)))); ZRTP_LOG(3,(_ZTU_,"\t my pbxsID:%s\n", hex2str(cc->pbxs.id.buffer, cc->pbxs.id.length, print_buff, sizeof(print_buff)))); ZRTP_LOG(3,(_ZTU_,"\t his pbxsID:%s\n", hex2str((const char*)stream->messages.peer_dhpart.pbxsID, ZRTP_RSID_SIZE, print_buff, sizeof(print_buff)))); ZRTP_LOG(3,(_ZTU_,"\this pbxsID comp:%s\n", hex2str(cc->pbxs.peer_id.buffer, cc->pbxs.peer_id.length, print_buff, sizeof(print_buff)))); hash_ctx = session->hash->hash_begin(session->hash); if (0 == hash_ctx) { ZRTP_LOG(1,(_ZTU_, "\tERROR! can't start hash calculation for S0 computing. ID=%u.\n", stream->id)); return zrtp_status_fail; } /* * NIST requires a 32-bit big-endian integer counter to be included * in the hash each time the hash is computed, which we have set to * the fixed value of 1, because we only compute the hash once. */ comp_length = zrtp_hton32(1L); session->hash->hash_update(session->hash, hash_ctx, (const int8_t*)&comp_length, 4); switch (stream->pubkeyscheme->base.id) { case ZRTP_PKTYPE_DH2048: case ZRTP_PKTYPE_DH3072: case ZRTP_PKTYPE_DH4096: comp_length = stream->pubkeyscheme->pv_length; ZRTP_LOG(3,(_ZTU_,"DH comp_length=%u\n", comp_length)); break; case ZRTP_PKTYPE_EC256P: case ZRTP_PKTYPE_EC384P: case ZRTP_PKTYPE_EC521P: comp_length = stream->pubkeyscheme->pv_length/2; ZRTP_LOG(3,(_ZTU_,"ECDH comp_length=%u\n", comp_length)); break; default: break; } bnBegin(&dhresult); stream->pubkeyscheme->compute(stream->pubkeyscheme, &stream->dh_cc, &dhresult, &stream->dh_cc.peer_pv); bnExtractBigBytes(&dhresult, (uint8_t *)buffer, 0, comp_length); session->hash->hash_update(session->hash, hash_ctx, (const int8_t*)buffer, comp_length); bnEnd(&dhresult); #if (defined(ZRTP_USE_STACK_MINIM) && (ZRTP_USE_STACK_MINIM == 1)) zrtp_sys_free(buffer); #endif /* Add "ZRTP-HMAC-KDF" to the S0 hash */ session->hash->hash_update( session->hash, hash_ctx, (const int8_t*)&zrtp_kdf_label.buffer, zrtp_kdf_label.length); /* Then Initiator's and Responder's ZIDs */ if (stream->protocol->type == ZRTP_STATEMACHINE_INITIATOR) { zidi = ZSTR_GV(stream->session->zrtp->zid); zidr = ZSTR_GV(stream->session->peer_zid); } else { zidr = ZSTR_GV(stream->session->zrtp->zid); zidi = ZSTR_GV(stream->session->peer_zid); } session->hash->hash_update(session->hash, hash_ctx, (const int8_t*)&zidi->buffer, zidi->length); session->hash->hash_update(session->hash, hash_ctx, (const int8_t*)&zidr->buffer, zidr->length); session->hash->hash_update(session->hash, hash_ctx, (const int8_t*)&cc->mes_hash.buffer, cc->mes_hash.length); /* If everything is OK - RS1 should much */ if (!zrtp_memcmp(cc->rs1.peer_id.buffer, stream->messages.peer_dhpart.rs1ID, ZRTP_RSID_SIZE)) { C[0] = &cc->rs1; secrets->matches |= ZRTP_BIT_RS1; } /* If we have lost our RS1 - remote party should use backup (RS2) instead */ else if (!zrtp_memcmp(cc->rs1.peer_id.buffer, stream->messages.peer_dhpart.rs2ID, ZRTP_RSID_SIZE)) { C[0] = &cc->rs1; secrets->matches |= ZRTP_BIT_RS1; ZRTP_LOG(2,(_ZTU_,"\tINFO! We have lost our RS1 from previous broken exchange" " - remote party will use RS2 backup. ID=%u\n", stream->id)); } /* If remote party lost it's secret - we will use backup */ else if (!zrtp_memcmp(cc->rs2.peer_id.buffer, stream->messages.peer_dhpart.rs1ID, ZRTP_RSID_SIZE)) { C[0] = &cc->rs2; cc->rs1 = cc->rs2; secrets->matches |= ZRTP_BIT_RS1; secrets->cached |= ZRTP_BIT_RS1; ZRTP_LOG(2,(_ZTU_,"\tINFO! Remote party has lost it's RS1 - use RS2 backup. ID=%u\n", stream->id)); } else { secrets->matches &= ~ZRTP_BIT_RS1; zrtp_cache_set_verified(session->zrtp->cache, ZSTR_GV(session->peer_zid), 0); zrtp_cache_reset_secure_since(session->zrtp->cache, ZSTR_GV(session->peer_zid)); ZRTP_LOG(2,(_ZTU_,"\tINFO! Our RS1 doesn't equal to other-side's one %s. ID=%u\n", cc->rs1.secret->_cachedflag ? " - drop verified!" : "", stream->id)); } if (!zrtp_memcmp(cc->rs2.peer_id.buffer, stream->messages.peer_dhpart.rs2ID, ZRTP_RSID_SIZE)) { secrets->matches |= ZRTP_BIT_RS2; if (0 == C[0]) { C[0] = &cc->rs2; } } if (secrets->auxs && (!zrtp_memcmp(stream->messages.peer_dhpart.auxsID, cc->auxs.peer_id.buffer, ZRTP_RSID_SIZE)) ) { C[1] =&cc->auxs; secrets->matches |= ZRTP_BIT_AUX; } if ( secrets->pbxs && (!zrtp_memcmp(stream->messages.peer_dhpart.pbxsID, cc->pbxs.peer_id.buffer, ZRTP_RSID_SIZE)) ) { C[2] = &cc->pbxs; secrets->matches |= ZRTP_BIT_PBX; } /* Finally hashing matched shared secrets */ for (i=0; i<3; i++) { /* * Some of the shared secrets s1 through s5 may have lengths of zero * if they are null (not shared), and are each preceded by a 4-octet * length field. For example, if s4 is null, len(s4) is 00 00 00 00, * and s4 itself would be absent from the hash calculation, which * means len(s5) would immediately follow len(s4). */ comp_length = C[i] ? zrtp_hton32(ZRTP_RS_SIZE) : 0; session->hash->hash_update(session->hash, hash_ctx, (const int8_t*)&comp_length, 4); if (C[i]) { session->hash->hash_update( session->hash, hash_ctx, (const int8_t*)C[i]->secret->value.buffer, C[i]->secret->value.length ); ZRTP_LOG(3,(_ZTU_,"\tUse S%d in calculations.\n", i+1)); } } session->hash->hash_end(session->hash, hash_ctx, ZSTR_GV(cc->s0)); } break; /* S0 for for DH and Preshared streams */ /* * Compute all possible combinations of preshared_key: * hash(len(rs1) | rs1 | len(auxsecret) | auxsecret | len(pbxsecret) | pbxsecret) * Find matched preshared_key and derive S0 from it: * s0 = KDF(preshared_key, "ZRTP Stream Key", KDF_Context, negotiated hash length) * * INFO: Take into account that RS1 and RS2 may be swapped. * If no matched were found - generate DH commit. * ======================================================================== */ case ZRTP_STREAM_MODE_PRESHARED: { zrtp_status_t s = zrtp_status_ok; zrtp_string32_t presh_key = ZSTR_INIT_EMPTY(presh_key); ZRTP_LOG(3,(_ZTU_,"\tDERIVE S0 for PRESHARED from cached secret. ID=%u\n", stream->id)); /* Use the same hash as we used for Commitment */ if (is_initiator) { s = _zrtp_compute_preshared_key( session, ZSTR_GV(session->secrets.rs1->value), (session->secrets.auxs->_cachedflag) ? ZSTR_GV(session->secrets.auxs->value) : NULL, (session->secrets.pbxs->_cachedflag) ? ZSTR_GV(session->secrets.pbxs->value) : NULL, ZSTR_GV(presh_key), NULL); if (zrtp_status_ok != s) { return s; } secrets->matches |= ZRTP_BIT_RS1; if (session->secrets.auxs->_cachedflag) { secrets->matches |= ZRTP_BIT_AUX; } if (session->secrets.pbxs->_cachedflag) { secrets->matches |= ZRTP_BIT_PBX; } } /* * Let's find appropriate hv key for Responder: * <RS1, 0, 0>, <RS1, AUX, 0>, <RS1, 0, PBX>, <RS1, AUX, PBX>. */ else { int res=-1; char* peer_key_id = (char*)stream->messages.peer_commit.hv+ZRTP_HV_NONCE_SIZE; zrtp_string8_t key_id = ZSTR_INIT_EMPTY(key_id); do { /* RS1 MUST be available at this stage.*/ s = _zrtp_compute_preshared_key( session, ZSTR_GV(secrets->rs1->value), NULL, NULL, ZSTR_GV(presh_key), ZSTR_GV(key_id)); if (zrtp_status_ok == s) { res = zrtp_memcmp(peer_key_id, key_id.buffer, ZRTP_HV_KEY_SIZE); if (0 == res) { secrets->matches |= ZRTP_BIT_RS1; break; } } if (session->secrets.pbxs->_cachedflag) { s = _zrtp_compute_preshared_key( session, ZSTR_GV(secrets->rs1->value), NULL, ZSTR_GV(secrets->pbxs->value), ZSTR_GV(presh_key), ZSTR_GV(key_id)); if (zrtp_status_ok == s) { res = zrtp_memcmp(peer_key_id, key_id.buffer, ZRTP_HV_KEY_SIZE); if (0 == res) { secrets->matches |= ZRTP_BIT_PBX; break; } } } if (session->secrets.auxs->_cachedflag) { s = _zrtp_compute_preshared_key( session, ZSTR_GV(secrets->rs1->value), ZSTR_GV(secrets->auxs->value), NULL, ZSTR_GV(presh_key), ZSTR_GV(key_id)); if (zrtp_status_ok == s) { res = zrtp_memcmp(peer_key_id, key_id.buffer, ZRTP_HV_KEY_SIZE); if (0 == res) { secrets->matches |= ZRTP_BIT_AUX; break; } } } if ((session->secrets.pbxs->_cachedflag) && (session->secrets.auxs->_cachedflag)) { s = _zrtp_compute_preshared_key( session, ZSTR_GV(secrets->rs1->value), ZSTR_GV(secrets->auxs->value), ZSTR_GV(secrets->pbxs->value), ZSTR_GV(presh_key), ZSTR_GV(key_id)); if (zrtp_status_ok == s) { res = zrtp_memcmp(peer_key_id, key_id.buffer, ZRTP_HV_KEY_SIZE); if (0 == res) { secrets->matches |= ZRTP_BIT_AUX; secrets->matches |= ZRTP_BIT_PBX; break; } } } } while (0); if (0 != res) { ZRTP_LOG(3,(_ZTU_,"\tINFO! Matched Key wasn't found - initate DH exchange.\n")); secrets->cached = 0; secrets->rs1->_cachedflag = 0; _zrtp_machine_start_initiating_secure(stream); return zrtp_status_ok; } } ZRTP_LOG(3,(_ZTU_,"\tUse RS1, %s, %s in calculations.\n", (session->secrets.matches & ZRTP_BIT_AUX) ? "AUX" : "NULL", (session->secrets.matches & ZRTP_BIT_PBX) ? "PBX" : "NULL")); _zrtp_kdf( stream, ZSTR_GV(presh_key), ZSTR_GV(zrtp_presh_label), ZSTR_GV(stream->protocol->cc->kdf_context), session->hash->digest_length, ZSTR_GV(cc->s0)); } break; /* * For FAST Multistream: * s0n = KDF(ZRTPSess, "ZRTP Multistream Key", KDF_Context, negotiated hash length) * ======================================================================== */ case ZRTP_STREAM_MODE_MULT: { ZRTP_LOG(3,(_ZTU_,"\tDERIVE S0 for MULTISTREAM from ZRTP Session key... ID=%u\n", stream->id)); _zrtp_kdf( stream, ZSTR_GV(session->zrtpsess), ZSTR_GV(zrtp_multi_label), ZSTR_GV(stream->protocol->cc->kdf_context), session->hash->digest_length, ZSTR_GV(cc->s0)); } break; default: break; } /* * Compute ZRTP session key for FULL streams only: * ZRTPSess = KDF(s0, "ZRTP Session Key", KDF_Context, negotiated hash length) */ if (!ZRTP_IS_STREAM_MULT(stream)) { if (session->zrtpsess.length == 0) { _zrtp_kdf( stream, ZSTR_GV(cc->s0), ZSTR_GV(zrtp_sess_label), ZSTR_GV(stream->protocol->cc->kdf_context), session->hash->digest_length, ZSTR_GV(session->zrtpsess)); } } return zrtp_status_ok; }
static int dsaSign(PGPSecKey *seckey, PGPHashVTBL const *h, PGPByte const *hash, PGPByte *sig, size_t *siglen, PGPRandomContext const *rc, PGPPublicKeyMessageFormat format) { #if PGP_SIGN_DISABLE /* [ */ (void)seckey; (void)h; (void)hash; (void)sig; (void)siglen; (void)rc; (void)format; return kPGPError_FeatureNotAvailable; #else /* PGP_SIGN_DISABLE */ /* ] [ */ DSAsecPlus *sec = (DSAsecPlus *)seckey->priv; BigNum r, s, bn, k; unsigned t; unsigned qbits; unsigned qbytes; int i; PGPRandomContext *rc2; PGPMemoryMgrRef mgr = NULL; mgr = PGPGetContextMemoryMgr( seckey->context ); (void)h; /* We don't need this argument, although other algorithms may... */ (void)format; ASSERTDSA(seckey->pkAlg); /* Allow generalizations of SHA as long as they are big enough */ #if 0 pgpAssert(h->algorithm == kPGPHashAlgorithm_SHA); #else pgpAssert(h->hashsize*8 >= bnBits(&sec->s.q)); /* Make sure that q is the right size of we are using regular SHA hash */ pgpAssert( ! (h->algorithm == kPGPHashAlgorithm_SHA && bnBits(&sec->s.q) != h->hashsize*8) ); #endif if (sec->locked) return kPGPError_KeyIsLocked; /* * DSA requires a secret k. This k is *very* important * to keep secret. Consider, the DSA signing equations are: * r = (g^k mod p) mod q, and * s = k^-1 * (H(m) + x*r) mod q, * so if you know k (and, the signature r, s and H), then * x = r^-1 * (k*s - H(m)) * If we ever pick two k values the same, then * r = (g^k mod p) mod q is the same for both signatures, and * s1 = k^-1 * (H1 + x * r) * s2 = k^-1 * (H2 + x * r) * k = (H1-H2) / (s1-s2) * and proceed from there. * * So we need to make *very* sure there's no problem. To make * sure, we add a layer on top of the passed-in RNG. We assume * the passed-in RNG is good enough to never repeat (not a * difficult task), and apply an additional X9.17 generator on * top of that, seeded with the secret x, which is destroyed * before leaving this function. * * In addition, we add entropy from the hash to the original RNG. * This will prevent us from using the same k value twice if the * messages are different. */ pgpRandomAddBytes(rc, hash, bnBytes(&sec->s.q)); rc2 = pgpRandomCreateX9_17( rc->context, kPGPCipherAlgorithm_CAST5, rc); if (!rc2) return kPGPError_OutOfMemory; pgpRandomBnSeed(rc2, &sec->s.x); /* * Of these values, only k is inherently sensitive, but others may * hold some intermediate results we would prefer not to have leaked. * So mark all as sensitive. */ bnBegin(&r, mgr, TRUE ); bnBegin(&s, mgr, TRUE ); bnBegin(&bn, mgr, TRUE ); bnBegin(&k, mgr, TRUE ); /* * Choose the random k value to be used for this signature. * Make it a bit bigger than q so it is fairly uniform mod q. */ qbits = bnBits(&sec->s.q); qbytes = bnBytes(&sec->s.q); if (pgpBnGenRand(&k, rc2, qbits+8, 0, 1, qbits) < 0 || bnMod(&k, &k, &sec->s.q) < 0) goto nomem; /* Raise g to k power mod p then mod q to get r */ if (bnExpMod(&r, &sec->s.g, &k, &sec->s.p) < 0 || bnMod(&r, &r, &sec->s.q) < 0) goto nomem; /* r*x mod q into s */ if (bnMul(&s, &r, &sec->s.x) < 0 || bnMod(&s, &s, &sec->s.q) < 0) goto nomem; /* Pack message hash M into buffer bn */ if (bnInsertBigBytes(&bn, hash, 0, bnBytes(&sec->s.q)) < 0) goto nomem; if (bnMod(&bn, &bn, &sec->s.q) < 0) goto nomem; /* Add into s */ if (bnAdd(&s, &bn) < 0 || bnMod(&s, &s, &sec->s.q) < 0) goto nomem; /* Divide by k, mod q (k inverse held in bn) */ if (bnInv(&bn, &k, &sec->s.q) < 0 || bnMul(&s, &s, &bn) < 0 || bnMod(&s, &s, &sec->s.q) < 0) goto nomem; /* That's it, now to pack r and then s into the buffer */ t = 0; if (format == kPGPPublicKeyMessageFormat_X509) { /* Put in SEQUENCE header for 509 sig data */ PGPUInt32 len_seq, lenlen_seq; /* Count size of sequence, counting a 0 byte if hi bit is set */ if (8*qbytes == bnBits(&r)) len_seq = pgpBnX509LenLen(qbytes+1) + 1 + qbytes+1; else len_seq = pgpBnX509LenLen(qbytes) + 1 + qbytes; if (8*qbytes == bnBits(&s)) len_seq += pgpBnX509LenLen(qbytes+1) + 1 + qbytes+1; else len_seq += pgpBnX509LenLen(qbytes) + 1 + qbytes; lenlen_seq = pgpBnX509LenLen(len_seq); sig[t++] = X509_TAG_SEQUENCE | X509_TAG_CONSTRUCTED; if (--lenlen_seq == 0) { sig[t++] = len_seq; } else { sig[t++] = 0x80 | lenlen_seq; len_seq <<= 8 * (4-lenlen_seq); while (lenlen_seq--) { sig[t++] = (PGPByte)(len_seq >> 24); len_seq <<= 8; } } }
int rsa_GENKEYS(RSA_CTX *ctx,unsigned char *s1,unsigned char *s2){ int t,c; unsigned long int MB=(ctx->bits)/2; struct BigNum bn; struct BigNum p,q; int len=MB/8; if(ctx->bits==0) return BADDATALEN; bnBegin(&bn); bnBegin(&p); bnBegin(&q); t=bnInsertBigBytes(&p,(void*)s1,0,len); c=bnInsertBigBytes(&q,(void*)s2,0,len); if(t<0 || c<0){ bnEnd(&bn); bnEnd(&p); bnEnd(&q); return BADTHINGS; } t=primeGen(&p,NULL,NULL,NULL,1,3,5,0); c=primeGen(&q,NULL,NULL,NULL,1,3,5,0); if(t<0 || c<0){ bnEnd(&bn); bnEnd(&p); bnEnd(&q); return BADTHINGS; } t=bnMul(&ctx->n,&p,&q); if(t<0){ bnEnd(&bn); bnEnd(&p); bnEnd(&q); return BADTHINGS; } t=bnSubQ(&p,1); if(t<0){ bnEnd(&bn); bnEnd(&p); bnEnd(&q); return BADTHINGS; } t=bnSubQ(&q,1); if(t<0){ bnEnd(&bn); bnEnd(&p); bnEnd(&q); return BADTHINGS; } t=bnMul(&bn,&p,&q); if(t<0){ bnEnd(&bn); bnEnd(&p); bnEnd(&q); return BADTHINGS; } t=bnInv(&ctx->d,&ctx->e,&bn); if(t<0){ bnEnd(&bn); bnEnd(&p); bnEnd(&q); return BADTHINGS; } bnEnd(&bn); bnEnd(&p); bnEnd(&q); return OK; }