/* dest = src^-1, modulo "mod". dest may be the same as src. */ PGPError PGPBigNumInv( PGPBigNumRef src, PGPBigNumRef mod, PGPBigNumRef dest ) { PGPError err = kPGPError_NoErr; int bnError = 0; pgpValidateBigNum( src ); pgpValidateBigNum( mod ); pgpValidateBigNum( dest ); bnError = bnInv( &dest->bn, &src->bn, &mod->bn ); if ( IsBNError( bnError ) ) { if ( bnError == 1 ) err = kPGPError_BigNumNoInverse; else err = kPGPError_OutOfMemory; } return( err ); }
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; } } }
/* * 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 */ /* ] */ }
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; }
int genRsaKey(struct PubKey *pub, struct SecKey *sec, unsigned bits, unsigned exp, FILE *file) { int modexps = 0; struct BigNum t; /* Temporary */ int i; struct Progress progress; progress.f = file; progress.column = 0; progress.wrap = 78; if (bnSetQ(&pub->e, exp)) return -1; /* Find p - choose a starting place */ if (genRandBn(&sec->p, bits/2, 0xC0, 1) < 0) return -1; /* And search for a prime */ i = primeGen(&sec->p, randRange, file ? genProgress : 0, &progress, exp, 0); if (i < 0) goto error; modexps = i; assert(bnModQ(&sec->p, exp) != 1); bndPut("p = ", &sec->p); do { /* Visual separator between the two progress indicators */ if (file) genProgress(&progress, ' '); if (genRandBn(&sec->q, (bits+1)/2, 0xC0, 1) < 0) goto error; if (bnCopy(&pub->n, &sec->q) < 0) goto error; if (bnSub(&pub->n, &sec->p) < 0) goto error; /* Note that bnSub(a,b) returns abs(a-b) */ } while (bnBits(&pub->n) < bits/2-5); if (file) fflush(file); /* Ensure the separators are visible */ i = primeGen(&sec->q, randRange, file ? genProgress : 0, &progress, exp, 0); if (i < 0) goto error; modexps += i; assert(bnModQ(&sec->p, exp) != 1); bndPut("q = ", &sec->q); /* Wash the random number pool. */ randFlush(); /* Ensure that q is larger */ if (bnCmp(&sec->p, &sec->q) > 0) bnSwap(&sec->p, &sec->q); bndPut("p = ", &sec->p); bndPut("q = ", &sec->q); /* * Now we dive into a large amount of fiddling to compute d, * the decryption exponent, from the encryption exponent. * We require that e*d == 1 (mod p-1) and e*d == 1 (mod q-1). * This can alomost be done via the Chinese Remainder Algorithm, * but it doesn't quite apply, because p-1 and q-1 are not * realitvely prime. Our task is to massage these into * two numbers a and b such that a*b = lcm(p-1,q-1) and * gcd(a,b) = 1. The technique is not well documented, * so I'll describe it here. * First, let d = gcd(p-1,q-1), then let a' = (p-1)/d and * b' = (q-1)/d. By the definition of the gcd, gcd(a',b') at * this point is 1, but a'*b' is a factor of d shy of the desired * value. We have to produce a = a' * d1 and b = b' * d2 such * d1*d2 = d and gcd(a,b) is 1. This will be the case iff * gcd(a,d2) = gcd(b,d1) = 1. Since GCD is associative and * (gcd(x,y,z) = gcd(x,gcd(y,z)) = gcd(gcd(x,y),z), etc.), * gcd(a',b') = 1 implies that gcd(a',b',d) = 1 which implies * that gcd(a',gcd(b',d)) = gcd(gcd(a',d),b') = 1. So you can * extract gcd(b',d) from d and make it part of d2, and the * same for d1. And iterate? A pessimal example is x = 2*6^k * and y = 3*6^k. gcd(x,y) = 6^k and we have to divvy it up * somehow so that all the factors of 2 go to x and all the * factors of 3 go to y, ending up with a = 2*2^k and b = 3*3^k. * * Aah, f**k it. It's simpler to do one big inverse for now. * Later I'll figure out how to get this to work properly. */ /* Decrement q temporarily */ (void)bnSubQ(&sec->q, 1); /* And u = p-1, to be divided by gcd(p-1,q-1) */ if (bnCopy(&sec->u, &sec->p) < 0) goto error; (void)bnSubQ(&sec->u, 1); bndPut("p-1 = ", &sec->u); bndPut("q-1 = ", &sec->q); /* Use t to store gcd(p-1,q-1) */ bnBegin(&t); if (bnGcd(&t, &sec->q, &sec->u) < 0) { bnEnd(&t); goto error; } bndPut("t = gcd(p-1,q-1) = ", &t); /* Let d = (p-1) / gcd(p-1,q-1) (n is scratch for the remainder) */ i = bnDivMod(&sec->d, &pub->n, &sec->u, &t); bndPut("(p-1)/t = ", &sec->d); bndPut("(p-1)%t = ", &pub->n); bnEnd(&t); if (i < 0) goto error; assert(bnBits(&pub->n) == 0); /* Now we have q-1 and d = (p-1) / gcd(p-1,q-1) */ /* Find the product, n = lcm(p-1,q-1) = c * d */ if (bnMul(&pub->n, &sec->q, &sec->d) < 0) goto error; bndPut("(p-1)*(q-1)/t = ", &pub->n); /* Find the inverse of the exponent mod n */ i = bnInv(&sec->d, &pub->e, &pub->n); bndPut("e = ", &pub->e); bndPut("d = ", &sec->d); if (i < 0) goto error; assert(!i); /* We should NOT get an error here */ /* * Now we have the comparatively simple task of computing * u = p^-1 mod q. */ #if BNDEBUG bnMul(&sec->u, &sec->d, &pub->e); bndPut("d * e = ", &sec->u); bnMod(&pub->n, &sec->u, &sec->q); bndPut("d * e = ", &sec->u); bndPut("q-1 = ", &sec->q); bndPut("d * e % (q-1)= ", &pub->n); bnNorm(&pub->n); bnSubQ(&sec->p, 1); bndPut("d * e = ", &sec->u); bnMod(&sec->u, &sec->u, &sec->p); bndPut("p-1 = ", &sec->p); bndPut("d * e % (p-1)= ", &sec->u); bnNorm(&sec->u); bnAddQ(&sec->p, 1); #endif /* But it *would* be nice to have q back first. */ (void)bnAddQ(&sec->q, 1); bndPut("p = ", &sec->p); bndPut("q = ", &sec->q); /* Now compute u = p^-1 mod q */ i = bnInv(&sec->u, &sec->p, &sec->q); if (i < 0) goto error; bndPut("u = p^-1 % q = ", &sec->u); assert(!i); /* p and q had better be relatively prime! */ #if BNDEBUG bnMul(&pub->n, &sec->u, &sec->p); bndPut("u * p = ", &pub->n); bnMod(&pub->n, &pub->n, &sec->q); bndPut("u * p % q = ", &pub->n); bnNorm(&pub->n); #endif /* And finally, n = p * q */ if (bnMul(&pub->n, &sec->p, &sec->q) < 0) goto error; bndPut("n = p * q = ", &pub->n); /* And that's it... success! */ if (file) putc('\n', file); /* Signal done */ return modexps; error: if (file) fputs("?\n", file); /* Signal error */ return -1; }