ZrtpDH::~ZrtpDH() { if (ctx == NULL) return; dhCtx* tmpCtx = static_cast<dhCtx*>(ctx); FREE_EC_POINT(&tmpCtx->pubPoint); bnEnd(&tmpCtx->privKey); switch (pkType) { case DH2K: case DH3K: bnEnd(&tmpCtx->pubKey); break; case EC25: case EC38: ecFreeCurveNistECp(&tmpCtx->curve); break; case E255: case E414: ecFreeCurvesCurve(&tmpCtx->curve); break; } delete tmpCtx; ctx = nullptr; }
zrtp_status_t zrtp_done_pkt(zrtp_global_t* zrtp) { bnEnd(&zrtp->one); bnEnd(&zrtp->G); return zrtp_status_ok; }
void pubKeyEnd(struct PubKey *pub) { if (pub) { bnEnd(&pub->n); bnEnd(&pub->e); wipe(pub); } }
/*----------------------------------------------------------------------------*/ 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; }
void secKeyEnd(struct SecKey *sec) { if (sec) { bnEnd(&sec->d); bnEnd(&sec->p); bnEnd(&sec->q); bnEnd(&sec->u); wipe(sec); } }
/* * 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; }
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 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; }
/*----------------------------------------------------------------------------*/ static zrtp_status_t zrtp_dh_free(void *s) { zrtp_pk_scheme_t *self = (zrtp_pk_scheme_t *) s; switch (self->base.id) { case ZRTP_PKTYPE_DH2048: bnEnd(&self->base.zrtp->P_2048); bnEnd(&self->base.zrtp->P_2048_1); break; case ZRTP_PKTYPE_DH3072: bnEnd(&self->base.zrtp->P_3072); bnEnd(&self->base.zrtp->P_3072_1); break; default: return zrtp_status_bad_param; } return zrtp_status_ok; }
/* * Relock the key. */ static void dsaLock(PGPSecKey *seckey) { DSAsecPlus *sec = (DSAsecPlus *)seckey->priv; ASSERTDSA(seckey->pkAlg); sec->locked = 1; /* bnEnd is documented as also doing a bnBegin */ bnEnd(&sec->s.x); }
/* destoys the bignum and all memory it uses */ PGPError PGPFreeBigNum( PGPBigNumRef bn ) { PGPError err = kPGPError_NoErr; pgpValidateBigNum( bn ); bnEnd( &bn->bn ); err = PGPFreeData( bn ); return( err ); }
static void dsaSecDestroy(PGPSecKey *seckey) { DSAsecPlus *sec = (DSAsecPlus *)seckey->priv; PGPContextRef context; pgpAssertAddrValid( seckey, PGPSecKey ); context = seckey->context; ASSERTDSA(seckey->pkAlg); bnEnd(&sec->s.p); bnEnd(&sec->s.q); bnEnd(&sec->s.g); bnEnd(&sec->s.y); bnEnd(&sec->s.x); pgpClearMemory(sec->cryptkey, sec->ckalloc); pgpContextMemFree( context, sec->cryptkey); PGPFreeData( sec ); /* Wipes as it frees */ pgpClearMemory( seckey, sizeof(seckey)); pgpContextMemFree( context, seckey); }
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 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; }
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 void dsaPubDestroy(PGPPubKey *pubkey) { DSApub *pub = (DSApub *)pubkey->priv; PGPContextRef context; pgpAssertAddrValid( pubkey, PGPPubKey ); context = pubkey->context; pgpAssert( pgpContextIsValid( context ) ); ASSERTDSA(pubkey->pkAlg); bnEnd(&pub->p); bnEnd(&pub->q); bnEnd(&pub->g); bnEnd(&pub->y); pgpClearMemory( pub, sizeof(pub)); pgpContextMemFree( context, pub); pgpClearMemory( pubkey, sizeof(pubkey)); pgpContextMemFree( context, pubkey); }
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; }
int rsa_END_d(RSA_CTX *ctx){ bnEnd(&ctx->d); return OK; }
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; }
/* * 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; }
/* * 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; }
/* * 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 */ /* ] */ }
/* * 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; }
int rsa_END_e(RSA_CTX *ctx){ bnEnd(&ctx->e); return 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; }
int rsa_END_N(RSA_CTX *ctx){ bnEnd(&ctx->n); return OK; }
int rsa_END(RSA_CTX *ctx){ bnEnd(&ctx->n); bnEnd(&ctx->e); bnEnd(&ctx->d); return OK; }
/* * 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; }
/* * 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; }