int rsaPublicEncrypt(BigNum *bn, PGPByte const *in, unsigned len, RSApub const *pub, PGPRandomContext const *rc) { unsigned bytes = (bnBits(&pub->n)+7)/8; pgpPKCSPack(bn, in, len, PKCS_PAD_ENCRYPTED, bytes, rc); bndPrintf("RSA encrypting.\n"); bndPut("plaintext = ", bn); return bnExpMod(bn, bn, &pub->e, &pub->n); }
/* * Performs an RSA decryption. Returns a prefix of the unwrapped * data in the given buf. Returns the length of the untruncated * data, which may exceed "len". Returns <0 on error. */ int rsaPrivateDecrypt(PGPByte *buf, unsigned len, BigNum *bn, RSAsec const *sec) { unsigned bytes; bndPrintf("RSA decrypting\n"); if (bnExpModCRA(bn, &sec->d, &sec->p, &sec->q, &sec->u) < 0) return kPGPError_OutOfMemory; bndPut("decrypted = ", bn); bytes = (bnBits(&sec->n)+7)/8; return pgpPKCSUnpack(buf, len, bn, PKCS_PAD_ENCRYPTED, bytes); }
/* * Decrypt a message with a public key. * These destroy (actually, replace with a decrypted version) the * input bignum bn. * * It recongizes the PGP 2.2 format, but not in all its generality; * only the one case (framing byte = 1, length = 16) which was ever * generated. It fakes the DER prefix in that case. * * Performs an RSA signature check. Returns a prefix of the unwrapped * data in the given buf. Returns the length of the untruncated * data, which may exceed "len". Returns <0 on error. */ int rsaPublicDecrypt(PGPByte *buf, unsigned len, BigNum *bn, RSApub const *pub) { unsigned bytes; bndPrintf("RSA signature checking.\n"); if (bnExpMod(bn, bn, &pub->e, &pub->n) < 0) return kPGPError_OutOfMemory; bndPut("decrypted = ", bn); bytes = (bnBits(&pub->n)+7)/8; return pgpPKCSUnpack(buf, len, bn, PKCS_PAD_SIGNED, bytes); }
int rsaPrivateEncrypt(BigNum *bn, PGPByte const *in, unsigned len, RSAsec const *sec) { unsigned bytes = (bnBits(&sec->n)+7)/8; pgpPKCSPack(bn, in, len, PKCS_PAD_SIGNED, bytes, (PGPRandomContext const *)NULL); bndPrintf("RSA signing.\n"); bndPut("plaintext = ", bn); return bnExpModCRA(bn, &sec->d, &sec->p, &sec->q, &sec->u); }
/* * 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; }
static int genDH(struct BigNum *bn, unsigned bits, unsigned char *seed, unsigned len, FILE *f) { #if CLOCK_AVAIL timetype start, stop; unsigned long s; #endif int i; unsigned char s1[1024], s2[1024]; unsigned p1, p2; struct BigNum step; struct Progress progress; if (f) fprintf(f, "Generating a %u-bit D-H prime with \"%.*s\"\n", bits, (int)len, (char *)seed); progress.f = f; progress.column = 0; progress.wrap = 78; /* Find p - choose a starting place */ if (genRandBn(bn, bits, 0xC0, 3, seed, len) < 0) return -1; #if BNDEBUG /* DEBUG - check that sieve works properly */ bnBegin(&step); bnSetQ(&step, 2); sieveBuild(s1, 1024, bn, 2, 0); sieveBuildBig(s2, 1024, bn, &step, 0); p1 = p2 = 0; if (s1[0] != s2[0]) printf("Difference: s1[0] = %x s2[0] = %x\n", s1[0], s2[0]); do { p1 = sieveSearch(s1, 1024, p1); p2 = sieveSearch(s2, 1024, p2); if (p1 != p2) printf("Difference: p1 = %u p2 = %u\n", p1, p2); } while (p1 && p2); bnEnd(&step); #endif /* And search for a prime */ #if CLOCK_AVAIL gettime(&start); #endif i = germainPrimeGen(bn, 1, f ? genProgress : 0, (void *)&progress); if (i < 0) return -1; #if CLOCK_AVAIL gettime(&stop); #endif if (f) { putc('\n', f); fprintf(f, "%d modular exponentiations performed.\n", i); } #if CLOCK_AVAIL subtime(stop, start); s = sec(stop); bndPrintf("%u-bit time = %lu.%03u sec.", bits, s, msec(stop)); if (s > 60) { putchar(' '); putchar('('); if (s > 3600) printf("%u:%02u", (unsigned)(s/3600), (unsigned)(s/60%60)); else printf("%u", (unsigned)(s/60)); printf(":%02u)", (unsigned)(s%60)); } putchar('\n'); #endif bndPut("p = ", bn); return 0; }