Exemple #1
0
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);
}
Exemple #2
0
/*
 * 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);
}
Exemple #3
0
/*
 * 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);
}
Exemple #4
0
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);
}
Exemple #5
0
/*
 * 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;
}
Exemple #6
0
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;
}
Exemple #7
0
static int
testDH(struct BigNum *bn)
{
    struct BigNum pub1, pub2, sec1, sec2;
    unsigned bits;
    int i = 0;
    char buf[4];

    bnBegin(&pub1);
    bnBegin(&pub2);
    bnBegin(&sec1);
    bnBegin(&sec2);

    /* Bits of secret - add a few to ensure an even distribution */
    bits = bnBits(bn)+4;
    /* Temporarily decrement bn for some operations */
    (void)bnSubQ(bn, 1);

    strcpy(buf, "foo");
    i = genRandBn(&sec1, bits, 0, 0, (unsigned char *)buf, 4);
    if (i < 0)
        goto done;
    /* Reduce sec1 to the correct range */
    i = bnMod(&sec1, &sec1, bn);
    if (i < 0)
        goto done;

    strcpy(buf, "bar");
    i = genRandBn(&sec2, bits, 0, 0, (unsigned char *)buf, 4);
    if (i < 0)
        goto done;
    /* Reduce sec2 to the correct range */
    i = bnMod(&sec2, &sec2, bn);
    if (i < 0)
        goto done;

    /* Re-increment bn */
    (void)bnAddQ(bn, 1);

    puts("Doing first half for party 1");
    i = bnTwoExpMod(&pub1, &sec1, bn);
    if (i < 0)
        goto done;
    puts("Doing first half for party 2");
    i = bnTwoExpMod(&pub2, &sec2, bn);
    if (i < 0)
        goto done;

    /* In a real protocol, pub1 and pub2 are now exchanged */

    puts("Doing second half for party 1");
    i = bnExpMod(&pub2, &pub2, &sec1, bn);
    if (i < 0)
        goto done;
    bndPut("shared = ", &pub2);
    puts("Doing second half for party 2");
    i = bnExpMod(&pub1, &pub1, &sec2, bn);
    if (i < 0)
        goto done;
    bndPut("shared = ", &pub1);

    if (bnCmp(&pub1, &pub2) != 0) {
        puts("Diffie-Hellman failed!");
        i = -1;
    } else {
        puts("Test successful.");
    }
done:
    bnEnd(&sec2);
    bnEnd(&sec1);
    bnEnd(&pub2);
    bnEnd(&pub1);

    return i;
}
Exemple #8
0
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;
}