Пример #1
0
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;
}
Пример #2
0
zrtp_status_t zrtp_done_pkt(zrtp_global_t* zrtp)
{
    bnEnd(&zrtp->one);
    bnEnd(&zrtp->G);
    
    return zrtp_status_ok;
}
Пример #3
0
void
pubKeyEnd(struct PubKey *pub)
{
	if (pub) {
		bnEnd(&pub->n);
		bnEnd(&pub->e);
		wipe(pub);
	}
}
Пример #4
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;
}
Пример #5
0
void
secKeyEnd(struct SecKey *sec)
{
	if (sec) {
		bnEnd(&sec->d);
		bnEnd(&sec->p);
		bnEnd(&sec->q);
		bnEnd(&sec->u);
		wipe(sec);
	}
}
Пример #6
0
/*
 * 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;
}
Пример #7
0
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;
}
Пример #8
0
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;
}
Пример #9
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;
}
Пример #10
0
/*
 * 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);
}
Пример #11
0
/* 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 );
}
Пример #12
0
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);
}
Пример #13
0
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;
}
Пример #14
0
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;
}
Пример #15
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;
}
Пример #16
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;
}
Пример #17
0
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);
}
Пример #18
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;
}
Пример #19
0
int rsa_END_d(RSA_CTX *ctx){
bnEnd(&ctx->d);
return OK;
}
Пример #20
0
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;
}
Пример #21
0
/*
 * 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;
}
Пример #22
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;
}
Пример #23
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 */ /* ] */
}
Пример #24
0
/*
 * 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;
}
Пример #25
0
int rsa_END_e(RSA_CTX *ctx){
bnEnd(&ctx->e);
return OK;
}
Пример #26
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;
}
Пример #27
0
int rsa_END_N(RSA_CTX *ctx){
bnEnd(&ctx->n);
return OK;
}
Пример #28
0
int rsa_END(RSA_CTX *ctx){
bnEnd(&ctx->n);
bnEnd(&ctx->e);
bnEnd(&ctx->d);
return OK;
}
Пример #29
0
/*
 * 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;
}
Пример #30
0
/*
 * 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;
}