Пример #1
0
/*----------------------------------------------------------------------------*/
static zrtp_status_t zrtp_dh_validate(zrtp_pk_scheme_t *self, struct BigNum *pv)
{
	struct BigNum* p = _zrtp_get_p(self);
	if (!p) {		
		return zrtp_status_bad_param;
	}
	
    if (!pv || 0 == bnCmp(pv, &self->base.zrtp->one) || 0 == bnCmp(pv, p)) {
    	return zrtp_status_fail;
    } else {    
		return zrtp_status_ok;
	}
}
Пример #2
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;
}
Пример #3
0
/*----------------------------------------------------------------------------*/
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;
}
Пример #4
0
/* Return sign (-1, 0, +1) of a-b.  a <=> b --> bnCmp(a, b) <=> 0 */
	PGPInt32
PGPBigNumCompare(
	PGPBigNumRef	lhs,
	PGPBigNumRef	rhs )
{
	if ( pgpBigNumIsValid( lhs ) && pgpBigNumIsValid( rhs ) )
	{
		return( bnCmp( &lhs->bn, &rhs->bn ) );
	}
	
	return( 0 );
}
Пример #5
0
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;
}
Пример #6
0
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;
}
Пример #7
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 */ /* ] */
}
Пример #8
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;
}
Пример #9
0
/*
 * Helper function that does the slow primality test.
 * bn is the input bignum; a and e are temporary buffers that are
 * allocated by the caller to save overhead.
 *
 * Returns 0 if prime, >0 if not prime, and -1 on error (out of memory).
 * If not prime, returns the number of modular exponentiations performed.
 * Calls the given progress function with a '*' for each primality test
 * that is passed.
 *
 * The testing consists of strong pseudoprimality tests, to the bases given
 * in the confirm[] array above.  (Also called Miller-Rabin, although that's
 * not technically correct if we're using fixed bases.)  Some people worry
 * that this might not be enough.  Number theorists may wish to generate
 * primality proofs, but for random inputs, this returns non-primes with
 * a probability which is quite negligible, which is good enough.
 *
 * It has been proved (see Carl Pomerance, "On the Distribution of
 * Pseudoprimes", Math. Comp. v.37 (1981) pp. 587-593) that the number of
 * pseudoprimes (composite numbers that pass a Fermat test to the base 2)
 * less than x is bounded by:
 * exp(ln(x)^(5/14)) <= P_2(x)	### CHECK THIS FORMULA - it looks wrong! ###
 * P_2(x) <= x * exp(-1/2 * ln(x) * ln(ln(ln(x))) / ln(ln(x))).
 * Thus, the local density of Pseudoprimes near x is at most
 * exp(-1/2 * ln(x) * ln(ln(ln(x))) / ln(ln(x))), and at least
 * exp(ln(x)^(5/14) - ln(x)).  Here are some values of this function
 * for various k-bit numbers x = 2^k:
 * Bits	Density <=	Bit equivalent	Density >=	Bit equivalent
 *  128	3.577869e-07	 21.414396	4.202213e-37	 120.840190
 *  192	4.175629e-10	 31.157288	4.936250e-56	 183.724558
 *  256 5.804314e-13	 40.647940	4.977813e-75	 246.829095
 *  384 1.578039e-18	 59.136573	3.938861e-113	 373.400096
 *  512 5.858255e-24	 77.175803	2.563353e-151	 500.253110
 *  768 1.489276e-34	112.370944	7.872825e-228	 754.422724
 * 1024 6.633188e-45	146.757062	1.882404e-304	1008.953565
 *
 * As you can see, there's quite a bit of slop between these estimates.
 * In fact, the density of pseudoprimes is conjectured to be closer to the
 * square of that upper bound.  E.g. the density of pseudoprimes of size
 * 256 is around 3 * 10^-27.  The density of primes is very high, from
 * 0.005636 at 256 bits to 0.001409 at 1024 bits, i.e.  more than 10^-3.
 *
 * For those people used to cryptographic levels of security where the
 * 56 bits of DES key space is too small because it's exhaustible with
 * custom hardware searching engines, note that you are not generating
 * 50,000,000 primes per second on each of 56,000 custom hardware chips
 * for several hours.  The chances that another Dinosaur Killer asteroid
 * will land today is about 10^-11 or 2^-36, so it would be better to
 * spend your time worrying about *that*.  Well, okay, there should be
 * some derating for the chance that astronomers haven't seen it yet,
 * but I think you get the idea.  For a good feel about the probability
 * of various events, I have heard that a good book is by E'mile Borel,
 * "Les Probabilite's et la vie".  (The 's are accents, not apostrophes.)
 *
 * For more on the subject, try "Finding Four Million Large Random Primes",
 * by Ronald Rivest, in Advancess in Cryptology: Proceedings of Crypto
 * '90.  He used a small-divisor test, then a Fermat test to the base 2,
 * and then 8 iterations of a Miller-Rabin test.  About 718 million random
 * 256-bit integers were generated, 43,741,404 passed the small divisor
 * test, 4,058,000 passed the Fermat test, and all 4,058,000 passed all
 * 8 iterations of the Miller-Rabin test, proving their primality beyond
 * most reasonable doubts.
 *
 * If the probability of getting a pseudoprime is some small p, then the
 * probability of not getting it in t trials is (1-p)^t.  Remember that,
 * for small p, (1-p)^(1/p) ~ 1/e, the base of natural logarithms.
 * (This is more commonly expressed as e = lim_{x\to\infty} (1+1/x)^x.)
 * Thus, (1-p)^t ~ e^(-p*t) = exp(-p*t).  So the odds of being able to
 * do this many tests without seeing a pseudoprime if you assume that
 * p = 10^-6 (one in a million) is one in 57.86.  If you assume that
 * p = 2*10^-6, it's one in 3347.6.  So it's implausible that the density
 * of pseudoprimes is much more than one millionth the density of primes.
 *
 * He also gives a theoretical argument that the chance of finding a
 * 256-bit non-prime which satisfies one Fermat test to the base 2 is
 * less than 10^-22.  The small divisor test improves this number, and
 * if the numbers are 512 bits (as needed for a 1024-bit key) the odds
 * of failure shrink to about 10^-44.  Thus, he concludes, for practical
 * purposes *one* Fermat test to the base 2 is sufficient.
 */
static int
primeTest(BigNum const *bn, BigNum *e, BigNum *a,
	int (*f)(void *arg, int c), void *arg)
{
	unsigned i, j;
	unsigned k, l;
	int err;

#if BNDEBUG	/* Debugging */
	/*
	 * This is debugging code to test the sieving stage.
	 * If the sieving is wrong, it will let past numbers with
	 * small divisors.  The prime test here will still work, and
	 * weed them out, but you'll be doing a lot more slow tests,
	 * and presumably excluding from consideration some other numbers
	 * which might be prime.  This check just verifies that none
	 * of the candidates have any small divisors.  If this
	 * code is enabled and never triggers, you can feel quite
	 * confident that the sieving is doing its job.
	 */
	i = bnLSWord(bn);
	if (!(i % 2)) printf("bn div by 2!");
	i = bnModQ(bn, 51051);	/* 51051 = 3 * 7 * 11 * 13 * 17 */
	if (!(i % 3)) printf("bn div by 3!");
	if (!(i % 7)) printf("bn div by 7!");
	if (!(i % 11)) printf("bn div by 11!");
	if (!(i % 13)) printf("bn div by 13!");
	if (!(i % 17)) printf("bn div by 17!");
	i = bnModQ(bn, 63365);	/* 63365 = 5 * 19 * 23 * 29 */
	if (!(i % 5)) printf("bn div by 5!");
	if (!(i % 19)) printf("bn div by 19!");
	if (!(i % 23)) printf("bn div by 23!");
	if (!(i % 29)) printf("bn div by 29!");
	i = bnModQ(bn, 47027);	/* 47027 = 31 * 37 * 41 */
	if (!(i % 31)) printf("bn div by 31!");
	if (!(i % 37)) printf("bn div by 37!");
	if (!(i % 41)) printf("bn div by 41!");
#endif

	/*
	 * Now, check that bn is prime.  If it passes to the base 2,
	 * it's prime beyond all reasonable doubt, and everything else
	 * is just gravy, but it gives people warm fuzzies to do it.
	 *
	 * This starts with verifying Euler's criterion for a base of 2.
	 * This is the fastest pseudoprimality test that I know of,
	 * saving a modular squaring over a Fermat test, as well as
	 * being stronger.  7/8 of the time, it's as strong as a strong
	 * pseudoprimality test, too.  (The exception being when bn ==
	 * 1 mod 8 and 2 is a quartic residue, i.e. bn is of the form
	 * a^2 + (8*b)^2.)  The precise series of tricks used here is
	 * not documented anywhere, so here's an explanation.
	 * Euler's criterion states that if p is prime then a^((p-1)/2)
	 * is congruent to Jacobi(a,p), modulo p.  Jacobi(a,p) is
	 * a function which is +1 if a is a square modulo p, and -1 if
	 * it is not.  For a = 2, this is particularly simple.  It's
	 * +1 if p == +/-1 (mod 8), and -1 if m == +/-3 (mod 8).
	 * If p == 3 mod 4, then all a strong test does is compute
	 * 2^((p-1)/2). and see if it's +1 or -1.  (Euler's criterion
	 * says *which* it should be.)  If p == 5 (mod 8), then
	 * 2^((p-1)/2) is -1, so the initial step in a strong test,
	 * looking at 2^((p-1)/4), is wasted - you're not going to
	 * find a +/-1 before then if it *is* prime, and it shouldn't
	 * have either of those values if it isn't.  So don't bother.
	 *
	 * The remaining case is p == 1 (mod 8).  In this case, we
	 * expect 2^((p-1)/2) == 1 (mod p), so we expect that the
	 * square root of this, 2^((p-1)/4), will be +/-1 (mod p).
	 * Evaluating this saves us a modular squaring 1/4 of the time.
	 * If it's -1, a strong pseudoprimality test would call p
	 * prime as well.  Only if the result is +1, indicating that
	 * 2 is not only a quadratic residue, but a quartic one as well,
	 * does a strong pseudoprimality test verify more things than
	 * this test does.  Good enough.
	 *
	 * We could back that down another step, looking at 2^((p-1)/8)
	 * if there was a cheap way to determine if 2 were expected to
	 * be a quartic residue or not.  Dirichlet proved that 2 is
	 * a quartic residue iff p is of the form a^2 + (8*b^2).
	 * All primes == 1 (mod 4) can be expressed as a^2 + (2*b)^2,
	 * but I see no cheap way to evaluate this condition.
	 */
	if (bnCopy(e, bn) < 0)
		return -1;
	(void)bnSubQ(e, 1);
	l = bnLSWord(e);

	j = 1;	/* Where to start in prime array for strong prime tests */

	if (l & 7) {
		bnRShift(e, 1);
		if (bnTwoExpMod(a, e, bn) < 0)
			return -1;
		if ((l & 7) == 6) {
			/* bn == 7 mod 8, expect +1 */
			if (bnBits(a) != 1)
				return 1;	/* Not prime */
			k = 1;
		} else {
			/* bn == 3 or 5 mod 8, expect -1 == bn-1 */
			if (bnAddQ(a, 1) < 0)
				return -1;
			if (bnCmp(a, bn) != 0)
				return 1;	/* Not prime */
			k = 1;
			if (l & 4) {
				/* bn == 5 mod 8, make odd for strong tests */
				bnRShift(e, 1);
				k = 2;
			}
		}
	} else {
		/* bn == 1 mod 8, expect 2^((bn-1)/4) == +/-1 mod bn */
		bnRShift(e, 2);
		if (bnTwoExpMod(a, e, bn) < 0)
			return -1;
		if (bnBits(a) == 1) {
			j = 0;	/* Re-do strong prime test to base 2 */
		} else {
			if (bnAddQ(a, 1) < 0)
				return -1;
			if (bnCmp(a, bn) != 0)
				return 1;	/* Not prime */
		}
		k = 2 + bnMakeOdd(e);
	}
	/* It's prime!  Now go on to confirmation tests */

	/*
	 * Now, e = (bn-1)/2^k is odd.  k >= 1, and has a given value
	 * with probability 2^-k, so its expected value is 2.
	 * j = 1 in the usual case when the previous test was as good as
	 * a strong prime test, but 1/8 of the time, j = 0 because
	 * the strong prime test to the base 2 needs to be re-done.
	 */
	for (i = j; i < CONFIRMTESTS; i++) {
		if (f && (err = f(arg, '*')) < 0)
			return err;
		(void)bnSetQ(a, confirm[i]);
		if (bnExpMod(a, a, e, bn) < 0)
			return -1;
		if (bnBits(a) == 1)
			continue;	/* Passed this test */

		l = k;
		for (;;) {
			if (bnAddQ(a, 1) < 0)
				return -1;
			if (bnCmp(a, bn) == 0)	/* Was result bn-1? */
				break;	/* Prime */
			if (!--l)	/* Reached end, not -1? luck? */
				return i+2-j;	/* Failed, not prime */
			/* This portion is executed, on average, once. */
			(void)bnSubQ(a, 1);	/* Put a back where it was. */
			if (bnSquare(a, a) < 0 || bnMod(a, a, bn) < 0)
				return -1;
			if (bnBits(a) == 1)
				return i+2-j;	/* Failed, not prime */
		}
		/* It worked (to the base confirm[i]) */
	}
	
	/* Yes, we've decided that it's prime. */
	if (f && (err = f(arg, '*')) < 0)
		return err;
	return 0;	/* Prime! */
}
Пример #10
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;
}
Пример #11
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;
}