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

📄 pgpdsakey.c

📁 可以实现对邮件的加密解密以及签名
💻 C
📖 第 1 页 / 共 4 页
字号:
	}
	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;
}

/*
 * Return the size of the public portion of a key buffer.
 */
int
dsaPubKeyPrefixSize(PGPByte const *buf, PGPSize size)
{
	return pgpBnParse(buf, size, 4, NULL, NULL, NULL, NULL);
}


/** Secret key functions **/

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

/*
 * 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	= PGPPeekContextMemoryMgr( 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;
}

/*
 * Set keyid
 */
static void
dsaSecSetKeyID(PGPSecKey *seckey, PGPByte *keyid)
{
	pgpCopyMemory(keyid, seckey->keyID, sizeof(seckey->keyID));
}

/*
 * Yes, there *is* a reason that this is a function and not a variable.
 * On a hardware device with an automatic timeout,
 * it actually might need to do some work to find out.
 */
static int
dsaIslocked(PGPSecKey const *seckey)
{
	DSAsecPlus const *sec = (DSAsecPlus *)seckey->priv;

	ASSERTDSA(seckey->pkAlg);
	return sec->locked;
}

/*
 * Return the algorithm and (symmetric) key size used for locking/unlocking
 * the secret key.
 */
static PGPError
dsaLockingAlgorithm(
	PGPSecKey const *seckey,
	PGPCipherAlgorithm *pAlg,
	PGPSize *pAlgKeySize
	)
{
	DSAsecPlus *sec = (DSAsecPlus *)seckey->priv;
	PGPCipherVTBL const *cipher;
	PGPByte alg;
	int i;

	ASSERTDSA(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, 4, NULL, NULL, 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 0xff or 0xfe then algorithm value */
	if (alg == 0xff || alg == 0xfe)
		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
dsaS2KType(
	PGPSecKey const *seckey,
	PGPStringToKeyType *s2kType
	)
{
	DSAsecPlus *sec = (DSAsecPlus *)seckey->priv;
	PGPByte alg;
	int i;

	ASSERTDSA(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, 4, NULL, NULL, NULL, NULL);
	if (i < 0)
		return (PGPError)i;

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

	if (alg == 0xff || alg == 0xfe) {
		/* New style has 0xff or 0xfe 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
dsaConvertPassphrase(PGPSecKey *seckey, PGPEnv const *env,
	  char const *phrase, PGPSize plen, PGPByte *outbuf)
{
	DSAsecPlus *sec = (DSAsecPlus *)seckey->priv;
	PGPStringToKey *s2k;
	PGPByte alg;
	PGPBoolean hasS2K;
	PGPCipherVTBL const *cipher;
	int i;

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

	/* Check packet for basic consistency */
	i = pgpBnParse(sec->cryptkey, sec->cklen, 4, 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 == 0xff || alg == 0xfe);

	/* 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, pgpenvGetContext( env ), sec->cryptkey+i, sec->cklen-i);
	} else {
		s2k = pgpS2Ksimple(pgpenvGetContext( 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 DSA-specific part is:
 *
 *  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
 *
 * Actually, that's the old-style, if pgpS2KoldVers is true.
 * If it's false, the algorithm ('alg0') is 0xff or 0xfe, and is followed by the
 * algorithm, then the (varaible-length, self-delimiting)
 * string-to-key descriptor.
 */

static int
dsaUnlock( PGPSecKey *seckey,
		   char const *phrase, PGPSize plen, PGPBoolean hashedPhrase)
{
	DSAsecPlus *sec = (DSAsecPlus *)seckey->priv;
	BigNum x;
	BigNum tmp1, tmp2, tmp3;
	PGPCFBContext *cfb = NULL;
	unsigned v, v_copy;
	unsigned alg /* actual algorithm */, alg0 /* first algorithm descriptor */;
	PGPHashContextRef checksumHash = NULL;
	PGPHashVTBL const *hashEntry = NULL;
	PGPByte checksumStored[20], checksum[20];	/* size no less then the max return value from pgpChecksumGetEx */
	unsigned checksumSize;
	int i;
	PGPBoolean validityChecked;
	PGPBoolean twofishRetry = FALSE;
	PGPMemoryMgrRef		mgr	= NULL;
	
	if( pgpFIPSModeEnabled() )
	{
		/* FIPS does not allow using keys with NULL passphrases */
		if( IsNull( phrase ) || plen == 0 )
			return( 0 );
	}

	mgr	= PGPPeekContextMemoryMgr( seckey->context );

	bnBegin(&x, mgr, TRUE);
	bnBegin( &tmp1, mgr, TRUE );
	bnBegin( &tmp2, mgr, TRUE );
	bnBegin( &tmp3, 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;

	/* Fast consistency checks (more below) */
	if (bnCmp(&sec->s.y, &sec->s.p) >= 0) {
		i = kPGPError_CorruptPrivateKey;
		goto done;
	}
	/* Calculate p-1 mod q in tmp1; should be 0 */
	bnCopy( &tmp1, &sec->s.p );
	bnSubQ( &tmp1, 1 );
	bnMod( &tmp1, &tmp1, &sec->s.q );
	if( bnCmpQ( &tmp1, 0 ) != 0 ) {
		i = kPGPError_CorruptPrivateKey;
		goto done;
	}

	/* Check for reasonable size; g and y checks are somewhat arbitrary */
	if( bnBits(&sec->s.q) < 160 || bnBits(&sec->s.p) < 512
		|| bnBits(&sec->s.g) < 100 || bnBits(&sec->s.y) < 100 ) {
		i = kPGPError_CorruptPrivateKey;
		goto done;
	}

	/* Get the encryption algorithm (cipher number).  0 == no encryption */
	alg0 = alg = sec->cryptkey[v];
	if( alg0 == 0xff || alg0 == 0xfe )
		alg = sec->cryptkey[v+1];

	/* 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 != !alg0)
		goto badpass1;

	hashEntry = pgpHashByNumberWithMask( alg0!=0xfe ? kPGPHashAlgorithm_Checksum16 : kPGPHashAlgorithm_SHA, 0xffffffff );
	checksumHash = pgpHashCreate( mgr, hashEntry );
	if( checksumHash == NULL )  {
		i = kPGPError_BadHashNumber;
		goto done;	
	}
 
	v_copy = v;
twofishRetry:
	i = pgpCipherSetup(sec->cryptkey + v, sec->cklen - v, phrase, plen,
					   hashedPhrase, twofishRetry, seckey->context, &cfb);
	if (i < 0)
		goto done;
	v += i;

	PGPResetHash( checksumHash );
	i = pgpBnGet(&x, sec->cryptkey + v, sec->cklen - v, cfb, alg0, FALSE/*old*/, checksumHash);
	if (i <= 0)
		goto badpass;
	v += i;
	if (bnCmp(&x, &sec->s.q) >= 0)

⌨️ 快捷键说明

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