⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pgpelgkey.c

📁 vc环境下的pgp源码
💻 C
📖 第 1 页 / 共 3 页
字号:
 * then the encryption IV.  That's 16 bytes plus the string-to-key
 * conversion length.
 */

static int
elgChangeLock(PGPSecKey *seckey, PGPEnv const *env, 
	PGPRandomContext const *rc, char const *phrase, size_t plen,
	PGPStringToKeyType s2ktype)
{
	ELGsecPlus *sec = (ELGsecPlus *)seckey->priv;
	PGPStringToKey *s2k = NULL;	/* Shut up warnings */
	PGPCipherVTBL const *cipher = NULL;	/* Shut up warnings */
	PGPCFBContext *cfb = NULL;	/* This is realy needed */
	PGPByte *p;
	PGPByte key[PGP_CIPHER_MAXKEYSIZE];
	int oldf = 0;				/* Shut up warnings */
	unsigned len;
	unsigned checksum;
	PGPContextRef	context	= pgpenvGetContext( env );

	ASSERTELG(seckey->pkAlg);
	if (sec->locked)
		return kPGPError_KeyIsLocked;

	len = bnBytes(&sec->s.p) + bnBytes(&sec->s.g) +
	      bnBytes(&sec->s.y) + bnBytes(&sec->s.x) + 11;
	if (phrase) {
		s2k = pgpS2Kcreate(env, rc, s2ktype);
		if (!s2k)
			return kPGPError_OutOfMemory;
		cipher = pgpCipherDefaultKey(env);
		pgpAssert(cipher);
		if (!cipher) {
			pgpS2Kdestroy(s2k);
			return kPGPError_OutOfMemory;
		}
		len += cipher->blocksize;
		cfb = pgpCFBCreate( PGPGetContextMemoryMgr( context ), cipher);
		if (!cfb) {
			pgpS2Kdestroy(s2k);
			return kPGPError_OutOfMemory;
		}
		oldf = pgpS2KisOldVers(s2k);
		if (!oldf)
			len += 1 + s2k->encodelen;
	}
	if (len > sec->ckalloc) {
		PGPError err = kPGPError_NoErr;
		if( IsNull( sec->cryptkey ) ) {
			sec->cryptkey = (PGPByte *)
				pgpContextMemAlloc( sec->context, len,
					0 );
			if( IsNull( sec->cryptkey ) ) {
				err = kPGPError_OutOfMemory;
			}
		} else {
			err = pgpContextMemRealloc( context,
				(void **)&sec->cryptkey, len, 0 );
		}
		if( IsPGPError( err ) ) {
			PGPFreeCFBContext(cfb);
			pgpS2Kdestroy(s2k);
			return err;
		}
		sec->ckalloc = (size_t)len;
	}
	sec->cklen = len;
	p = sec->cryptkey;

	/* Okay, no more errors possible!   Start installing data */
	p += pgpBnPutPlain(&sec->s.p, p);
	p += pgpBnPutPlain(&sec->s.g, p);
	p += pgpBnPutPlain(&sec->s.y, p);

	/* Encryption parameters */
	if (!phrase) {
		*p++ = 0;	/* Unencrypted */
	} else {
		if (oldf) {
			*p++ = cipher->algorithm;
		} else {
			*p++ = 255;
			*p++ = cipher->algorithm;
			memcpy(p, s2k->encoding, s2k->encodelen);
			p += s2k->encodelen;
		}
		/* Create IV */
		pgpRandomGetBytes(rc, p, cipher->blocksize);
		pgpStringToKey(s2k, phrase, plen, key, cipher->keysize);
		PGPInitCFB(cfb, key, p);
		pgpS2Kdestroy(s2k);
		p += cipher->blocksize;
		/* Wipe key *immediately* */
		pgpClearMemory( key,  cipher->keysize);
	}

	/* Now install x, encrypted */
	checksum = 0;
	p += pgpBnPutNew(&sec->s.x, p, cfb, &checksum);
	pgpChecksumPutNew(checksum, p, cfb);
	p += 2;
	pgpAssert((ptrdiff_t)len == p - sec->cryptkey);

	if (cfb)
		PGPFreeCFBContext(cfb);
	return 0;	/* Success */
}

static size_t
elgSecBufferLength(PGPSecKey const *seckey)
{
	ELGsecPlus const *sec = (ELGsecPlus *)seckey->priv;

	return sec->cklen;
}

static void
elgSecToBuffer(PGPSecKey const *seckey, PGPByte *buf)
{
	ELGsecPlus const *sec = (ELGsecPlus *)seckey->priv;

	memcpy(buf, sec->cryptkey, sec->cklen);

	/* Return only algorithm-dependent portion */
}


/* Fill in secret key structure */
static void
elgFillSecKey(PGPSecKey *seckey, ELGsecPlus *sec)
{
	seckey->pkAlg	            = kPGPPublicKeyAlgorithm_ElGamal;
	seckey->priv	            = sec;
	seckey->destroy             = elgSecDestroy;
	seckey->pubkey              = elgPubkey;
	seckey->islocked            = elgIslocked;
	seckey->lockingalgorithm    = elgLockingAlgorithm;
	seckey->s2ktype             = elgS2KType;
	seckey->convertpassphrase   = elgConvertPassphrase;
	seckey->unlock              = elgUnlock;
	seckey->lock                = elgLock;
	seckey->decrypt             = elgDecrypt;
	seckey->maxdecrypted        = elgSecMaxdecrypted;
	seckey->maxesk		        = elgSecMaxesk;
	seckey->maxsig              = elgSecMaxsig;
	seckey->sign                = elgSign;
	seckey->changeLock          = elgChangeLock;
	seckey->bufferLength        = elgSecBufferLength;
	seckey->toBuffer            = elgSecToBuffer;
}


PGPSecKey *
elgSecFromBuf(
	PGPContextRef	context,
	PGPByte const *	buf,
	size_t			size,
	PGPError *		error)
{
	PGPSecKey *seckey;
	ELGsecPlus *sec;
	PGPByte *cryptk;
	PGPError	err	= kPGPError_OutOfMemory;
	PGPMemoryMgrRef		mgr	= PGPGetContextMemoryMgr( context );
	PGPEnv *			pgpEnv = pgpContextGetEnvironment( context );

	bnInit();
	cryptk = (PGPByte *)pgpContextMemAlloc( context,
		size, kPGPMemoryMgrFlags_Clear);
	if (cryptk) {
		sec = (ELGsecPlus *)PGPNewSecureData( mgr, sizeof(*sec), 0 );
		if (sec) {
			pgpClearMemory( sec, sizeof(*sec) );
			sec->context	= context;
			
			seckey = (PGPSecKey *) pgpContextMemAlloc( context,
					sizeof(*seckey), kPGPMemoryMgrFlags_Clear);
			if (seckey) {
				seckey->context	= context;
				
				memcpy(cryptk, buf, size);
				bnBegin(&sec->s.p, mgr, FALSE );
				bnBegin(&sec->s.g, mgr, FALSE );
				bnBegin(&sec->s.y, mgr, FALSE );
				bnBegin(&sec->s.x, mgr, TRUE );
				sec->cryptkey = cryptk;
				sec->cklen = sec->ckalloc = size;
				sec->locked = 1;
				/* We only need this to try unlocking... */
				seckey->pkAlg = kPGPPublicKeyAlgorithm_ElGamal;
				seckey->priv = sec;
				
				if (elgUnlock(seckey, pgpEnv, NULL, 0, FALSE) >= 0) {
					elgFillSecKey(seckey, sec);
					*error = kPGPError_NoErr;
					return seckey;	/* Success! */
				}
				else
				{
					err	= kPGPError_UnknownError;
				}

				/* Ka-boom.  Delete and free everything. */
				pgpClearMemory( cryptk,  size);
				pgpContextMemFree( context, seckey);
			}
			PGPFreeData( sec );			/* Wipes as it frees */
		}
		pgpContextMemFree( context, cryptk);
	}
	*error = err;
	return NULL;
}

/* Generate super-strong primes? (Warning: slow!) */
#ifndef ELG_GERMAIN
#define ELG_GERMAIN 0
#endif

/*
 * Generate an ELG secret key with prime of the specified number of bits.
 * Make callbacks to progress function periodically.
 * Secret key is returned in the unlocked form, with no passphrase set.
 * fastgen tells us to use canned primes if available.
 *
 * If ELG_GERMAIN is set to 1, we generate p such that (p-1)/2 is also
 * prime.  This takes long time.  (Pseudoprimality tests take time
 * cubic in the number of bits, and the number of tests needed is
 * linear in the number of bits, so it's quartic overall.  Searching
 * for Sophier Germain primes makes it quintic(!), although the constant
 * factor improves to make up for a lot of that.
 *
 * The alternative (which is really just as safe, really) is to generate
 * primes which have a large prime factor q about 10 bits shorter than
 * the requested length.  We will guarantee that 2 is a generator of a
 * subgroup with period at least q.
 *
 * If it is OK, we could speed it up more by generating multiple primes
 * qi such that p = 2*k*q1*q2*q3*...*qn + 1, and where each qi is greater
 * than 2**160 (or whatever exponent value we are using).  Again, once we
 * verify that 2's period is > 2k we know it as at least min(qi), which
 * should be long enough for prevention of discrete log attacks.
 *
 * A bit of theory: the average density of primes around n is 1/ln(n),
 * so the average gap between primes is ln(n).  However, the maximum
 * gap is ln(n)^2.  The fact that we're searching in steps other than
 * 1 doesn't matter - it'll take an average of ln(n) steps.
 *
 * So to produce a prime of the desired size, we should have p/q at
 * least ln(p) and to guarantee it, we need p/q = ln(p)^2.  This
 * means that we want
 * log2(ln(p))           < log2(p/q)         < log2(ln(p)^2)
 * log2(0.693*log2(p))   < log2(p) - log2(q) < 2 * log2(0.693 * log2(p))
 * log2(log2(p)) - 0.529 < log2(p) - log2(q) < 2 * log2(log2(p)) - 1.058
 *
 * At this point, it's safe to start getting crude, because if we're
 * only counting bits, 2^(bits(x)-1) <= x < 2^bits(x) <= 2*x, or
 * bits(x)-1 <= log2(x) < bits(x) <= log2(x)+1.  Another way of looking
 * at all this is that log2(x) is bits(x) - 0.5 +/- 0.5.
 * So let's split the difference and use 1.5 * bits(bits(p)) - 1 as the
 * difference in bits between p and q.  
 *
 * See the discussion preceding the DSA keygen routine dsaSecGenerate
 * in pgpDSAKey.c for an explanation of the rcdummy random number
 * generator below.  It serves to limit leakage of the state of the
 * randpool into the public values generated as part of the key.
 */
PGPSecKey *
elgSecGenerate(
	PGPContextRef	context,
	unsigned bits, PGPBoolean fastgen,
	PGPRandomContext const *rc,
	int progress(void *arg, int c), void *arg, PGPError *error)
{
	PGPSecKey *seckey;
	ELGsecPlus *sec;
	PGPRandomContext *rcdummy = NULL;
	unsigned bits2;
#if !ELG_GERMAIN
	unsigned lengthdiff;
	BigNum q, h, e;
	int i;
#endif
	PGPByte dummyseed[ELGDUMMYBITS/8];
	PGPMemoryMgrRef		mgr	= PGPGetContextMemoryMgr( context );
	PGPEnv *			pgpEnv = pgpContextGetEnvironment( context );

	*error = kPGPError_NoErr;

	/* Initialize local pointers (simplify cleanup below) */
	seckey = NULL;
	sec = NULL;

	/* Allocate data structures */
	seckey = (PGPSecKey *)pgpContextMemAlloc( context,
		sizeof(*seckey), kPGPMemoryMgrFlags_Clear);
	if (!seckey)
		goto memerror;
	seckey->context	= context;
	sec = (ELGsecPlus *)PGPNewSecureData( mgr, sizeof(*sec), 0 );
	sec->context	= context;
	if (!sec)
		goto memerror;
	
	bnBegin(&sec->s.p, mgr, FALSE );
	bnBegin(&sec->s.g, mgr, FALSE );
	bnBegin(&sec->s.y, mgr, FALSE );
	bnBegin(&sec->s.x, mgr, TRUE );

	/* Use a fixed prime and generator if in our table */
	if (fastgen) {
		PGPByte const *fixedp, *fixedg;
		size_t fixedplen, fixedglen;
		if (pgpElGfixed (bits, &fixedp, &fixedplen, &fixedg, &fixedglen) > 0) {
			if (progress != NULL)
				progress(arg, ' ');
			bnInsertBigBytes (&sec->s.p, fixedp, 0, fixedplen);
			if (progress != NULL)
				progress(arg, ' ');
			bnInsertBigBytes (&sec->s.g, fixedg, 0, fixedglen);
			goto choose_x;
		}
	}

	/* Set up local random number generator for p and q */
	rcdummy = pgpPseudoRandomCreate ( rc->context );
	if (!rcdummy)
		goto memerror;
	pgpRandomGetBytes (rc, dummyseed, sizeof(dummyseed));
	pgpRandomAddBytes (rcdummy, dummyseed, sizeof(dummyseed));

#if ELG_GERMAIN
	/* Strong ("sophie germain") prime search */

	/* Find p - choose a starting place */
	if (pgpBnGenRand(&sec->s.p, rcdummy, bits, 0xC0, 3, bits-4) < 0)
		goto nomem;

	/* And search for a prime */
	if (bnGermainPrimeGen(&sec->s.p, 1, progress, arg) < 0)
		goto nomem;

	/* We have chosen p so 2 is a good choice for generator */
	if (bnSetQ(&sec->s.g, 2) < 0)
		goto nomem;

	/* Choose a random x of reasonable size as secret key */
	expbits = elgExpBits(bits);
	if (pgpBnGenRand(&sec->s.x, rc, expbits, 0, 0, expbits) < 0)
		goto nomem;

	/* And calculate g**x as public key */
	if (bnTwoExpMod(&sec->s.y, &sec->s.x, &sec->s.p) < 0)
		goto nomem;
#else /* !ELG_GERMAIN - the faster version */
	bnBegin(&q, mgr, FALSE );
	bnBegin(&h, mgr, FALSE );
	bnBegin(&e, mgr, FALSE );

	/*
	 * Choose a random starting place for q, a bit less than p.
	 * (See function header comment above for the theory behind this.)
	 */
	lengthdiff = 0;
	for (bits2 = bits; bits2; bits2 >>= 1)
		lengthdiff++;
	lengthdiff += (lengthdiff+1)/2;
	bits2 = bits - lengthdiff;

	if (pgpBnGenRand(&q, rcdummy, bits2, 0x80, 1, bits2-2) < 0)
		goto nomem;
	/* And search for a prime */
	i = bnPrimeGen(&q, NULL, progress, arg, 0);
	if (i < 0)
		goto nomem;
	if (progress != NULL)
		progress(arg, ' ');

	/* ...and now a random start for p */
	(void)bnSetQ(&sec->s.p, 0);
	if (pgpBnGenRand(&sec->s.p, rcdummy, bits, 0xC0, 1, bits-bits2-3) < 0)
		goto nomem;

	/* Double q to make it a suitable stride */
	if (bnLShift(&q, 1) < 0)
		goto nomem;

	/* Set p = p - (p mod 2q) + 1, i.e. congruent to 1 mod 2q */
	if (bnMod(&h, &sec->s.p, &q) < 0)
		goto nomem;
	if (bnSub(&sec->s.p, &h) < 0 || bnAddQ(&sec->s.p, 1) < 0)
		goto nomem;

	/* This loop is very rarely executed */
retry:
	/* And search for a prime, 1+2kq for some k */
	i = bnPrimeGenStrong(&sec->s.p, &q, progress, arg);
	if (i < 0)
		goto nomem;
	if (progress != NULL)
		progress(arg, ' ');

	/* Now check two as g: first, find (p-1)/q = 2*((p-1)/(2*q)) */
	if (bnDivMod(&e, &h, &sec->s.p, &q) < 0 || bnLShift(&e, 1) < 0)
		goto nomem;
	/* e is now (p-1)/q, and h is the remainder (one!) */
	pgpAssert (bnBits(&h) == 1);

	/*
	 * Make sure 2**((p-1)/q) mod p is not small.  This should imply
	 * that the period of 2 as a generator has at least q as a factor,
	 * meaning it is very big.
	 * With (p-1)/q as small as it is, the chances are *excellent*
	 * that it will work.  If (p-1)/q were less than a few hundred
	 * 2**((p-1)/q) would be less than p and coundn't possibly be 1.
	 */
	if (bnTwoExpMod(&h, &e, &sec->s.p) < 0)
		goto nomem;
	if (bnBits(&h) < 2) {
		if (progress != NULL)
			progress(arg, ' ');
		goto retry;
	}
	bnEnd(&e);
	bnEnd(&h);
	bnEnd(&q);
#endif
	/* We have done things so 2 is a good choice for generator */
	if (bnSetQ(&sec->s.g, 2) < 0)
		goto nomem;

	/* May get here directly from above if fixed primes are used */
choose_x:

	/* Choose a random x of reasonable size as secret key */
	bits2 = pgpDiscreteLogExponentBits(bits)*3/2;
	if (pgpBnGenRand(&sec->s.x, rc, bits2, 0, 0, bits2) < 0)
		goto nomem;

	/* And calculate g**x as public key */
	if (bnExpMod(&sec->s.y, &sec->s.g, &sec->s.x, &sec->s.p) < 0)
		goto nomem;
	

	/* And that's it... success! */

	/* Fill in structs */
	sec->cryptkey = NULL;
	sec->ckalloc = sec->cklen = 0;
	sec->locked = 0;
	elgFillSecKey(seckey, sec);

	/* Fill in cryptkey structure, unencrypted */
	elgChangeLock (seckey, pgpEnv, NULL, NULL, 0, kPGPStringToKey_Simple);

	goto done;

nomem:
#if !ELG_GERMAIN
	bnEnd(&e);
	bnEnd(&h);
	bnEnd(&q);
#endif
	bnEnd(&sec->s.p);
	bnEnd(&sec->s.g);
	bnEnd(&sec->s.y);
	bnEnd(&sec->s.x);
	/* Fall through */
memerror:
	if ( IsntNull( seckey ) )
		pgpContextMemFree( context, seckey);
	if ( IsntNull( sec ) )
		PGPFreeData( sec );			/* Wipes as it frees */
	seckey = NULL;
	*error = kPGPError_OutOfMemory;

done:
	if (rcdummy)
	{
		pgpRandomDestroy (rcdummy);
	}
		
	return seckey;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -