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

📄 pgprsakey.c

📁 vc环境下的pgp源码
💻 C
📖 第 1 页 / 共 3 页
字号:
 * the secret key.
 */
static PGPError
rsaLockingAlgorithm(
	PGPSecKey const *seckey,
	PGPCipherAlgorithm *pAlg,
	PGPSize *pAlgKeySize
	)
{
	RSAsecPlus *sec = (RSAsecPlus *)seckey->priv;
	PGPCipherVTBL const *cipher;
	PGPByte alg;
	int i;

	ASSERTRSA(seckey->pkAlg);

	if( IsntNull( pAlg ) )
		*pAlg = (PGPCipherAlgorithm) 0;
	if( IsntNull( pAlgKeySize ) )
		*pAlgKeySize = (PGPSize) 0;

	/* Check packet for basic consistency */
	i = pgpBnParse(sec->cryptkey, sec->cklen, 2, NULL, NULL);
	if (i < 0)
		return (PGPError)i;

	/* Get the encryption algorithm (cipher number).  0 == no encryption */
	alg = sec->cryptkey[i] & 255;

	/* New style has 255 then algorithm value */
	if (alg == 255)
		alg = sec->cryptkey[i+1] & 255;

	cipher = pgpCipherGetVTBL( (PGPCipherAlgorithm)alg);
	if (!cipher)
		return kPGPError_BadCipherNumber;

	/* Success */
	if( IsntNull( pAlg ) )
		*pAlg = (PGPCipherAlgorithm) alg;
	if( IsntNull( pAlgKeySize ) )
		*pAlgKeySize = cipher->keysize;

	return kPGPError_NoErr;
}


/*
 * Return the StringToKey type for unlocking the given key.  We use
 * kPGPStringToKey_Literal to flag a secret split unlocking buffer.
 * Returns kPGPStringToKey_Simple if key has no passphrase.
 */
static PGPError
rsaS2KType(
	PGPSecKey const *seckey,
	PGPStringToKeyType *s2kType
	)
{
	RSAsecPlus *sec = (RSAsecPlus *)seckey->priv;
	PGPByte alg;
	int i;

	ASSERTRSA(seckey->pkAlg);

	/* note that 0 is a valid type, but use it as default anyway */
	if( IsntNull( s2kType ) )
		*s2kType = (PGPStringToKeyType) 0;

	/* Check packet for basic consistency */
	i = pgpBnParse(sec->cryptkey, sec->cklen, 2, NULL, NULL);
	if (i < 0)
		return (PGPError)i;

	/* Get the encryption algorithm (cipher number).  0 == no encryption */
	alg = sec->cryptkey[i] & 255;

	if (alg == 255) {
		/* New style has 255 then algorithm value then S2K */
		*s2kType = (PGPStringToKeyType) sec->cryptkey[i+2];
	} else {
		/* Unencrypted or old-style simple encryption */
		*s2kType = kPGPStringToKey_Simple;
	}

	return kPGPError_NoErr;
}


/*
 * Convert a passphrase into a s2k literal buffer for the key.
 * Returns error code.  Output buffer will be size of the *pAlgKeySize
 * parameter from pgpSecKeyLockingalgorithm.
 */
static PGPError
rsaConvertPassphrase(PGPSecKey *seckey, PGPEnv const *env,
	  char const *phrase, PGPSize plen, PGPByte *outbuf)
{
	RSAsecPlus *sec = (RSAsecPlus *)seckey->priv;
	PGPStringToKey *s2k;
	PGPByte alg;
	PGPBoolean hasS2K;
	PGPCipherVTBL const *cipher;
	int i;

	ASSERTRSA(seckey->pkAlg);
	pgpAssert (IsntNull( outbuf ) );

	/* Check packet for basic consistency */
	i = pgpBnParse(sec->cryptkey, sec->cklen, 2, NULL, NULL, NULL, NULL);
	if (i < 0)
		return (PGPError)i;

	/* Get the encryption algorithm (cipher number).  0 == no encryption */
	alg = sec->cryptkey[i++] & 255;

	hasS2K = (alg == 255);

	/* New style has 255 then algorithm value */
	if (hasS2K)
		alg = sec->cryptkey[i++] & 255;

	/* Now we are looking at the s2k object if there is one. */
	if (alg == 0) {
		/* Key is not locked */
		return kPGPError_BadParams;
	}
	cipher = pgpCipherGetVTBL( (PGPCipherAlgorithm)alg);
	if( IsNull( cipher ) )
		return kPGPError_BadCipherNumber;

	if (hasS2K) {
		pgpS2Kdecode(&s2k, env, sec->cryptkey+i, sec->cklen-i);
	} else {
		s2k = pgpS2Ksimple(env, pgpHashByNumber(kPGPHashAlgorithm_MD5));
	}
	if (IsNull( s2k ) )
		return kPGPError_OutOfMemory;
	pgpStringToKey(s2k, phrase, plen, outbuf, cipher->keysize);
	pgpS2Kdestroy (s2k);

	return kPGPError_NoErr;
}


/*
 * Try to decrypt the secret key wih the given passphrase.  Returns >0
 * if it was the correct passphrase. =0 if it was not, and <0 on error.
 * Does not alter the key even if it's the wrong passphrase and already
 * unlocked.  A NULL passphrae will work if the key is unencrypted.
 * 
 * A (secret) key's RSA-specific part is:
 *
 *  0                2+u  MPI for modulus
 *  2+u              2+v  MPI for exponent
 *  4+u+v            1    Encryption algorithm (0 for none, 1 for IDEA)
 *  5+u+v            t    Encryption IV: 0 or 8 bytes
 *  5+t+u+v          2+w  MPI for d
 *  7+t+u+v+w        2+x  MPI for p
 *  9+t+u+v+w+x      2+y  MPI for q
 * 11+t+u+v+w+x+y    2+z  MPI for u
 * 13+t+u+v+w+x+y+z  2    Checksum
 * 15+t+u+v+w+x+y+z
 *
 * Actually, that's the old-style, if pgpS2KoldVers is true.
 * If it's false, the algoruthm is 255, and is followed by the
 * algorithm, then the (varaible-length, self-delimiting)
 * string-to-key descriptor.
 */

static int
rsaUnlock(PGPSecKey *seckey, PGPEnv const *env,
	  char const *phrase, size_t plen, PGPBoolean hashedPhrase)
{
	RSAsecPlus *sec = (RSAsecPlus *)seckey->priv;
	BigNum d, p, q, u, bn;
	PGPCFBContext *cfb = NULL;	/* Necessary */
	unsigned v, t;
	unsigned alg;
	unsigned checksum;
	int i;
	PGPMemoryMgrRef		mgr	= NULL;

	mgr	= PGPGetContextMemoryMgr( seckey->context );

	ASSERTRSA(seckey->pkAlg);
	bnInit();

	if (sec->cklen < 5)
		return kPGPError_KeyPacketTruncated;
	v = ((unsigned)sec->cryptkey[0] << 8) + sec->cryptkey[1];
	v = (v+7)/8;
	if (sec->cklen < 5+v)
		return kPGPError_KeyPacketTruncated;
	if (bnInsertBigBytes(&sec->s.n, sec->cryptkey+2, 0, v) < 0)
		return kPGPError_OutOfMemory;
	t = ((unsigned)sec->cryptkey[2+v] << 8) + sec->cryptkey[3+v];
	t = (t+7)/8;
	if (sec->cklen < 4+v+t)
		return kPGPError_KeyPacketTruncated;
	if (bnInsertBigBytes(&sec->s.e, sec->cryptkey+4+v, 0, t) < 0)
		return kPGPError_OutOfMemory;
	v += t + 4;
	if (sec->cklen < v+1)
		return kPGPError_KeyPacketTruncated;

	/* 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 != !alg)
		return 0;

	i = pgpCipherSetup(sec->cryptkey + v, sec->cklen - v, phrase, plen,
					   hashedPhrase, env, &cfb);
	if (i < 0)
		return i;
	v += i;

	checksum = 0;
	bnBegin(&d, mgr, TRUE);
	bnBegin(&p, mgr, TRUE);
	bnBegin(&q, mgr, TRUE);
	bnBegin(&u, mgr, TRUE);
	bnBegin(&bn, mgr, TRUE);

	i = pgpBnGet(&d, sec->cryptkey + v, sec->cklen - v, cfb, &checksum,
				 sec->v3);
	if (i <= 0)
		goto fail;
	v += i;
	if (bnCmp(&d, &sec->s.n) >= 0)
		goto badpass;	/* Wrong passphrase: d must be < n */
	i = pgpBnGet(&p, sec->cryptkey + v, sec->cklen - v, cfb, &checksum,
				 sec->v3);
	if (i <= 0)
		goto fail;
	if ((bnLSWord(&p) & 1) == 0)
		goto badpass;
	v += i;
	i = pgpBnGet(&q, sec->cryptkey + v, sec->cklen - v, cfb, &checksum,
				 sec->v3);
	if (i <= 0)
		goto fail;
	if ((bnLSWord(&q) & 1) == 0)
		goto badpass;
	v += i;

	/* Extremely high-powered check.  Verify that p*q == n */
	if (bnMul(&bn, &p, &q) < 0)
		goto nomem;
	if (bnCmp(&bn, &sec->s.n) != 0)
		goto badpass;

	/* Verify that d*e == 1 mod p-1 */
	(void)bnSubQ(&p, 1);
	if (bnMul(&bn, &d, &sec->s.e) < 0 || bnMod(&bn, &bn, &p) < 0)
		goto nomem;
	if (bnCmpQ(&bn, 1) != 0)
		goto badpass;
	(void)bnAddQ(&p, 1);

	/* Verify that d*e == 1 mod q-1 */
	(void)bnSubQ(&q, 1);
	if (bnMul(&bn, &d, &sec->s.e) < 0 || bnMod(&bn, &bn, &q) < 0)
		goto nomem;
	if (bnCmpQ(&bn, 1) != 0)
		goto badpass;
	(void)bnAddQ(&q, 1);

	i = pgpBnGet(&u, sec->cryptkey + v, sec->cklen - v, cfb, &checksum,
				 sec->v3);
	if (i <= 0)
		goto fail;
	v += i;

	/* Check that we ended in the right place */
	if (sec->cklen - v != 2) {
		i = kPGPError_KEY_LONG;
		goto fail;
	}
	checksum &= 0xffff;
	if (checksum != ((unsigned)sec->cryptkey[v]<<8) + sec->cryptkey[1+v])
		goto badpass;

	/* Verify that u = p^-1 mod q is less than q */
	if (bnCmp(&u, &q) >= 0)
		goto badpass;
	/* Verify that u * p == 1 mod q */
	if (bnMul(&bn, &p, &u) < 0 || bnMod(&bn, &bn, &q) < 0)
		goto nomem;
	if (bnCmpQ(&bn, 1) != 0)
		goto badpass;

	/*
	 * Okay, we've verified every single value in the secret key,
	 * against the public key, so it is *definitely* the right
	 * secret key.  Note that the "nomem" case calls bnEnd()
	 * more than once, but this is guaranteed harmless.
 	 */
	bnEnd(&bn);
	if (bnCopy(&sec->s.d, &d) < 0)
		goto nomem;
	bnEnd(&d);
	if (bnCopy(&sec->s.p, &p) < 0)
		goto nomem;
	bnEnd(&p);
	if (bnCopy(&sec->s.q, &q) < 0)
		goto nomem;
	bnEnd(&q);
	if (bnCopy(&sec->s.u, &u) < 0)
		goto nomem;
	bnEnd(&u);

	i = 1;	/* Decrypted! */
	sec->locked = 0;
	if (cfb)
		PGPFreeCFBContext (cfb);
	return 1;	/* Decrypted */

nomem:
	i = kPGPError_OutOfMemory;
	goto done;
badpass:
	i = 0;	/* Incorrect passphrase */
	goto done;
fail:
	if (!i)
		i = kPGPError_KeyPacketTruncated;
	goto done;
done:
	if (cfb)
		PGPFreeCFBContext (cfb);
	bnEnd(&bn);
	bnEnd(&u);
	bnEnd(&q);
	bnEnd(&p);
	bnEnd(&d);
	return i;
}

/*
 * Relock the key.
 */
static void
rsaLock(PGPSecKey *seckey)
{
	RSAsecPlus *sec = (RSAsecPlus *)seckey->priv;

	ASSERTRSA(seckey->pkAlg);
	sec->locked = 1;
	/* bnEnd is documented as also doing a bnBegin */
	bnEnd(&sec->s.d);
	bnEnd(&sec->s.p);
	bnEnd(&sec->s.q);
	bnEnd(&sec->s.u);
}

static size_t
rsaSecMaxdecrypted(PGPSecKey const *seckey, PGPPublicKeyMessageFormat format);


/*
 * Try to decrypt the given esk.  If the key is locked, try the given
 * passphrase.  It may or may not leave the key unlocked in such a case.
 * (Some hardware implementations may insist on a password per usage.)
 */
static int
rsaDecrypt(PGPSecKey *seckey, PGPEnv const *env,
		   PGPByte const *esk, size_t esklen,
		   PGPByte *key, size_t *keylen,
		   char const *phrase, size_t plen,
		   PGPPublicKeyMessageFormat format)
{
#if PGP_DECRYPT_DISABLE /* [ */

	(void)seckey;
	(void)env;
	(void)esk;
	(void)esklen;
	(void)key;
	(void)keylen;
	(void)phrase;
	(void)plen;
	(void)format;
	return kPGPError_FeatureNotAvailable;

#else /* PGP_DECRYPT_DISABLE */  /* ]  [ */

	RSAsecPlus *sec = (RSAsecPlus *)seckey->priv;
	BigNum bn;
	int i, j;
	unsigned t;
	size_t max;
	PGPMemoryMgrRef		mgr	= NULL;

	mgr	= PGPGetContextMemoryMgr( seckey->context );

	ASSERTRSAENC(seckey->pkAlg);
	if (sec->locked) {
		i = rsaUnlock(seckey, env, phrase, plen, FALSE);
		if (i <= 0)
			return i ? i : kPGPError_KeyIsLocked;
		pgpAssert(!sec->locked);
	}

	if (esklen < 2)
		return kPGPError_BadSessionKeySize;
	
	bnBegin(&bn, mgr, TRUE);
	i = pgpBnGetFormatted(&bn, esk, esklen, bnBytes(&sec->s.n), format);
	if (i <= 0)
		return kPGPError_BadSessionKeySize;

	max = rsaSecMaxdecrypted(seckey, format);
	i = rsaPrivateDecrypt(key, max, &bn, &sec->s);
	bnEnd(&bn);
	if (i < 0)
		return i;
	if ((size_t)i > max || i < 3)
		return kPGPError_CorruptData;

	if (format == kPGPPublicKeyMessageFormat_PGP) {
		/* Check checksum (should this be here?) */
		t = 0;
		for (j = 1; j < i-2; j++)
			t += key[j];
		if (t != ((unsigned)key[i-2]<<8) + key[i-1])
			return kPGPError_CorruptData;
		pgpClearMemory(key+i-2, 2);

		/* The actual key */
		if (keylen)
			*keylen = (size_t)i-2;
	} else {
		/* The actual key */
		if (keylen)
			*keylen = (size_t)i;
	}

	return 0;

#endif /* PGP_DECRYPT_DISABLE */ /* ] */
}


/*
 * Return the size of the buffer needed, worst-case, for the decrypted
 * output.  A trivially padded key (random padding length = 0)
 * can just be 0 2 0 <key>.
 */
static size_t
rsaSecMaxdecrypted(PGPSecKey const *seckey, PGPPublicKeyMessageFormat format)
{
	RSAsecPlus const *sec = (RSAsecPlus *)seckey->priv;
	size_t size;

	(void) format;
	ASSERTRSAENC(seckey->pkAlg);

	size = bnBytes(&sec->s.n);
	return size < 3 ? 0 : size-3;
}

/* Return the largest possible PGPESK size for a given key */
static size_t
rsaSecMaxesk(PGPSecKey const *seckey, PGPPublicKeyMessageFormat format)
{
	RSAsecPlus const *sec = (RSAsecPlus *)seckey->priv;

	ASSERTRSAENC(seckey->pkAlg);
	if (format == kPGPPublicKeyMessageFormat_PGP)
		return 2 + bnBytes(&sec->s.n);
	else if (format == kPGPPublicKeyMessageFormat_PKCS1 ||
			 format == kPGPPublicKeyMessageFormat_X509  ||
			 format == kPGPPublicKeyMessageFormat_IKE)
		return bnBytes(&sec->s.n);

	pgpAssert(0);
	return 0;
}

static size_t
rsaSecMaxsig(PGPSecKey const *seckey, PGPPublicKeyMessageFormat format)
{
	RSAsecPlus const *sec = (RSAsecPlus *)seckey->priv;

	ASSERTRSASIG(seckey->pkAlg);
	if (format == kPGPPublicKeyMessageFormat_PGP)
		return 2 + bnBytes(&sec->s.n);
	else if (format == kPGPPublicKeyMessageFormat_PKCS1 ||
			 format == kPGPPublicKeyMessageFormat_IKE ||
			 format == kPGPPublicKeyMessageFormat_X509)
		return bnBytes(&sec->s.n);

	pgpAssert(0);
	return 0;
}

static int
rsaSign(PGPSecKey *seckey, PGPHashVTBL const *h, PGPByte const *hash,
	PGPByte *sig, size_t *siglen, PGPRandomContext const *rc,
	PGPPublicKeyMessageFormat format)
{
#if PGP_SIGN_DISABLE /* [ */

	(void)seckey;
	(void)h;
	(void)hash;
	(void)sig;
	(void)siglen;
	(void)rc;

⌨️ 快捷键说明

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