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

📄 pgpdsakey.c

📁 可以实现对邮件的加密解密以及签名
💻 C
📖 第 1 页 / 共 4 页
字号:
		goto badpass;	/* Wrong passphrase: x must be < q */

	/* Check that we ended in the right place */
	checksumSize = pgpChecksumGet( sec->cryptkey+v, NULL, alg0, checksumHash, NULL );
	pgpAssert( checksumSize <= sizeof(checksumStored) );	/* programmer's error */
	if (sec->cklen - v != checksumSize)
		goto badpass;

	pgpChecksumGet(sec->cryptkey+v, cfb, alg0, checksumHash, checksumStored);
	PGPFinalizeHash( checksumHash, checksum );
	if( !pgpMemoryEqual( checksumStored, checksum, checksumSize ) )
		goto badpass;

	validityChecked = pgpKeyDBObjIsValid( seckey->keyDBObj )
					  && pgpSecIsValidated( seckey->keyDBObj );
	if( !validityChecked )
	{
		/* Do careful checks of validity */
		if (bnCmp(&x, &sec->s.q) >= 0) {
			if( alg == kPGPCipherAlgorithm_Twofish256 && !twofishRetry )
				goto badpass;
			i = kPGPError_CorruptPrivateKey;
			goto done;
		}

		/* Calculate g^x mod p in tmp2; should be y */
		bnExpMod( &tmp2, &sec->s.g, &x, &sec->s.p );
		if( bnCmp( &tmp2, &sec->s.y ) != 0 ) {
			if( alg == kPGPCipherAlgorithm_Twofish256 && !twofishRetry )
				goto badpass;
			i = kPGPError_CorruptPrivateKey;
			goto done;
		}

		/* Calculate g^q mod p in tmp3; should be 1 */
		bnExpMod( &tmp3, &sec->s.g, &sec->s.q, &sec->s.p );
		if( bnCmpQ( &tmp3, 1 ) != 0 ) {
			if( alg == kPGPCipherAlgorithm_Twofish256 && !twofishRetry )
				goto badpass;
			i = kPGPError_CorruptPrivateKey;
			goto done;
		}
		if( pgpKeyDBObjIsValid( seckey->keyDBObj ) )
			pgpSecSetValidated( seckey->keyDBObj );
	}

	/*
	 * 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:
	if( alg == kPGPCipherAlgorithm_Twofish256 && !twofishRetry )
	{
		/* Had a mis-implementation of Twofish on bigendian machines, so for
		 * backwards compatibility we must retry unlocking failures using
		 * the old, bad algorithm
		 */
		twofishRetry = TRUE;
		v = v_copy;
		if (cfb)
			PGPFreeCFBContext(cfb);
		goto twofishRetry;
	}
badpass1:
	i = 0;	/* Incorrect passphrase */
	goto done;
done:
	bnEnd(&x);
	bnEnd(&tmp1);
	bnEnd(&tmp2);
	bnEnd(&tmp3);
	if (cfb)
		PGPFreeCFBContext(cfb);
	if( checksumHash != NULL )
		PGPFreeHashContext( checksumHash );
	return i;
}

/*
 * 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);
}

/*
 * 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
dsaDecrypt(PGPSecKey *seckey, PGPByte const *esk, PGPSize esklen,
	   PGPByte *key, PGPSize *keylen, char const *phrase, PGPSize plen,
	   PGPPublicKeyMessageFormat format)
{
	(void)seckey;
	(void)esk;
	(void)esklen;
	(void)key;
	(void)keylen;
	(void)phrase;
	(void)plen;
	(void)format;
	return kPGPError_PublicKeyUnimplemented;
}

/*
 * Return the size of the buffer needed, worst-case, for the decrypted
 * output.
 */
static PGPSize
dsaSecMaxdecrypted(PGPSecKey const *seckey, PGPPublicKeyMessageFormat format)
{
	(void)seckey;
	(void)format;
	return kPGPError_PublicKeyUnimplemented;
}

static PGPSize
dsaSecMaxesk(PGPSecKey const *seckey, PGPPublicKeyMessageFormat format)
{
	(void)seckey;
	(void)format;
	return kPGPError_PublicKeyUnimplemented;
}

static PGPSize
dsaSecMaxsig(PGPSecKey const *seckey, PGPPublicKeyMessageFormat format)
{
	DSAsecPlus const *sec = (DSAsecPlus *)seckey->priv;

	ASSERTDSA(seckey->pkAlg);
	if (format == kPGPPublicKeyMessageFormat_PGP)
		return 2*( 2 + bnBytes(&sec->s.q) );
	else if (format == kPGPPublicKeyMessageFormat_PKCS1 ||
			 format == kPGPPublicKeyMessageFormat_IKE)
		return 2*( bnBytes(&sec->s.q) );
	else if (format == kPGPPublicKeyMessageFormat_X509) {
		/* SEQUENCE, length, INT, INT */
		PGPUInt32 len;
		PGPUInt32 qbytes = bnBytes(&sec->s.q);
		len = 2*(pgpBnX509LenLen(qbytes+1) + 1 + qbytes+1);
		return 1 + pgpBnX509LenLen(len) + len;
	}

	pgpAssert(0);
	return 0;
}



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

	(void)seckey;
	(void)h;
	(void)hash;
	(void)sig;
	(void)siglen;
	(void)rc;
	(void)format;
	return kPGPError_FeatureNotAvailable;

#else /* PGP_SIGN_DISABLE */  /* ]  [ */

	DSAsecPlus *sec = (DSAsecPlus *)seckey->priv;
	BigNum r, s, bn, k;
	unsigned t;
	unsigned qbits;
	unsigned qbytes;
	int i;
	PGPRandomContext *rc2;
	PGPMemoryMgrRef		mgr	= NULL;
	PGPCipherAlgorithm	cipherAlg;
	
	mgr	= PGPPeekContextMemoryMgr( seckey->context );

	(void)h;
	/* We don't need this argument, although other algorithms may... */
	(void)format;

	ASSERTDSA(seckey->pkAlg);
	/* Allow generalizations of SHA as long as they are big enough */
#if 0
	pgpAssert(h->algorithm == kPGPHashAlgorithm_SHA);
#else
	pgpAssert(h->hashsize*8 >= bnBits(&sec->s.q));
	/* Make sure that q is the right size of we are using regular SHA hash */
	pgpAssert( ! (h->algorithm == kPGPHashAlgorithm_SHA
				&& bnBits(&sec->s.q) != h->hashsize*8) );
#endif

	if (sec->locked)
		return kPGPError_KeyIsLocked;

	/*
	 * DSA requires a secret k.  This k is *very* important
	 * to keep secret.  Consider, the DSA signing equations are:
	 * r = (g^k mod p) mod q, and
	 * s = k^-1 * (H(m) + x*r) mod q,
	 * so if you know k (and, the signature r, s and H), then
	 * x = r^-1 * (k*s - H(m))
	 * If we ever pick two k values the same, then
	 * r = (g^k mod p) mod q is the same for both signatures, and
	 * s1 = k^-1 * (H1 + x * r) 
	 * s2 = k^-1 * (H2 + x * r) 
	 * k = (H1-H2) / (s1-s2)
	 * and proceed from there.
	 *
	 * So we need to make *very* sure there's no problem.  To make
	 * sure, we add a layer on top of the passed-in RNG.  We assume
	 * the passed-in RNG is good enough to never repeat (not a
	 * difficult task), and apply an additional X9.17 generator on
	 * top of that, seeded with the secret x, which is destroyed
	 * before leaving this function.
	 *
	 * In addition, we add entropy from the hash to the original RNG.
	 * This will prevent us from using the same k value twice if the
	 * messages are different.
	 */
	pgpRandomAddBytes(rc, hash, bnBytes(&sec->s.q));
	
	if( pgpFIPSModeEnabled() )
	{
		cipherAlg = kPGPCipherAlgorithm_3DES;
	}
	else
	{
		cipherAlg = kPGPCipherAlgorithm_CAST5;
	}
	
	rc2 = pgpRandomCreateX9_17( rc->context, cipherAlg, rc);
	if (!rc2)
		return kPGPError_OutOfMemory;
	pgpRandomBnSeed(rc2, &sec->s.x);

	/*
	 * Of these values, only k is inherently sensitive, but others may
	 * hold some intermediate results we would prefer not to have leaked.
	 * So mark all as sensitive.
	 */
	bnBegin(&r, mgr, TRUE );
	bnBegin(&s, mgr, TRUE );
	bnBegin(&bn, mgr, TRUE );
	bnBegin(&k, mgr, TRUE );

	/*
	 * Choose the random k value to be used for this signature.
	 * Make it a bit bigger than q so it is fairly uniform mod q.
	 */
	qbits = bnBits(&sec->s.q);
	qbytes = bnBytes(&sec->s.q);
	if (pgpBnGenRand(&k, rc2, qbits+8, 0, 1, qbits) < 0 ||
	    bnMod(&k, &k, &sec->s.q) < 0)
		goto nomem;
	
	/* Raise g to k power mod p then mod q to get r */
	if (bnExpMod(&r, &sec->s.g, &k, &sec->s.p) < 0 ||
	    bnMod(&r, &r, &sec->s.q) < 0)
		goto nomem;
	      
	/* r*x mod q into s */
	if (bnMul(&s, &r, &sec->s.x) < 0 ||
	    bnMod(&s, &s, &sec->s.q) < 0)
		goto nomem;

	/* Pack message hash M into buffer bn */
	if (bnInsertBigBytes(&bn, hash, 0, bnBytes(&sec->s.q)) < 0)
		goto nomem;
	if (bnMod(&bn, &bn, &sec->s.q) < 0)
		goto nomem;

	/* Add into s */
	if (bnAdd(&s, &bn) < 0 ||
	    bnMod(&s, &s, &sec->s.q) < 0)
		goto nomem;

	/* Divide by k, mod q (k inverse held in bn) */
	if (bnInv(&bn, &k, &sec->s.q) < 0 ||
	    bnMul(&s, &s, &bn) < 0 ||
	    bnMod(&s, &s, &sec->s.q) < 0)
		goto nomem;

	/* That's it, now to pack r and then s into the buffer */
	t = 0;
	if (format == kPGPPublicKeyMessageFormat_X509) {
		/* Put in SEQUENCE header for 509 sig data */
		PGPUInt32 len_seq, lenlen_seq;
		/* Count size of sequence, counting a 0 byte if hi bit is set */
		if (8*qbytes == bnBits(&r))
			len_seq = pgpBnX509LenLen(qbytes+1) + 1 + qbytes+1;
		else
			len_seq = pgpBnX509LenLen(qbytes) + 1 + qbytes;
		if (8*qbytes == bnBits(&s))
			len_seq += pgpBnX509LenLen(qbytes+1) + 1 + qbytes+1;
		else
			len_seq += pgpBnX509LenLen(qbytes) + 1 + qbytes;
		lenlen_seq = pgpBnX509LenLen(len_seq);
		sig[t++] = X509_TAG_SEQUENCE | X509_TAG_CONSTRUCTED;
		if (--lenlen_seq == 0) {
			sig[t++] = len_seq;
		} else {
			sig[t++] = 0x80 | lenlen_seq;
			len_seq <<= 8 * (4-lenlen_seq);
			while (lenlen_seq--) {
				sig[t++] = (PGPByte)(len_seq >> 24);
				len_seq <<= 8;
			}
		}
	}
	t += pgpBnPutFormatted(&r, sig+t, qbytes, format);
	t += pgpBnPutFormatted(&s, sig+t, qbytes, format);
	if (siglen)
		*siglen = (PGPSize)t;

	i = 0;
	goto done;

nomem:
	i = kPGPError_OutOfMemory;
	/* fall through */
done:
	pgpRandomDestroy(rc2);
	bnEnd(&k);
	bnEnd(&bn);
	bnEnd(&s);
	bnEnd(&r);
	return i;

#endif /* PGP_SIGN_DISABLE */ /* ] */
}


/*
 * Re-encrypt a PGPSecKey with a new urn a PGPSecKey into a secret key.
 * A secret key is, after a non-specific prefix:
 *  0       1    Version (= 2 or 3)
 *  1       4    Timestamp
 *  5       2    Validity (=0 at present)
 *  7       1    Algorithm (=kPGPPublicKeyAlgorithm_DSA for DSA)
 * The following:
 *  0                2+u  MPI for prime p
 *  2+u              2+v  MPI for order q
 *  4+u+v            2+w  MPI for generator g
 *  6+u+v+w	     2+x  MPI for public key y
 *  8+u+v+w+x        1    Encryption algorithm (0 for none, 1 for IDEA)
 *  9+u+v+w+x        t    Encryption IV: 0 or 8 bytes
 *  9+t+u+v+w+x      2+y  MPI for x (discrete log of public key)
 * 11+t+u+v+w+x+y    2    Checksum
 * 13+t+u+v+w+x+y
 *
 * The Encryption algorithm is the cipher algorithm for the old-style
 * string-to-key conversion.  For the new type, it's 255, then a cipher
 * algorithm, then a string-to-key algorithm (variable-length),
 * then the encryption IV.  That's 16 bytes plus the string-to-key
 * conversion length.
 */
#if PGP_MACINTOSH
#pragma global_optimizer on
#endif

static int
dsaChangeLock(PGPSecKey *seckey, PGPEnv const *env, 
	PGPRandomContext const *rc, char const *ophrase, PGPSize oplen,
	PGPBoolean oHashedPhrase, char const *phrase, PGPSize plen,
	PGPStringToKeyType s2ktype)
{
	DSAsecPlus *sec = (DSAsecPlus *)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;

	ASSERTDSA(seckey->pkAlg);
	if (sec->locked)
		if( IsPGPError(dsaUnlock( seckey, ophrase, oplen, oHashedPhrase )) )
			return kPGPError_KeyIsLocked;

	len = bnBytes(&sec->s.p) + bnBytes(&sec->s.q) + bnBytes(&sec->s.g) +
	      bnBytes(&sec->s.y) + bnBytes(&sec->s.x) + 13;
	if (phrase) {
		s2k = pgpS2Kcreate(pgpenvGetContext( 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(
				PGPPeekContextMemoryMgr( pgpenvGetContext( env ) ), 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 ) ) {

⌨️ 快捷键说明

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