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

📄 dbxpgp.c

📁 老外写的加密库cryptlib(版本3.1)
💻 C
📖 第 1 页 / 共 4 页
字号:
	int i;

	/* Perform a case-insensitive match for the required substring in the
	   string */
	for( i = 0; i <= stringLength - subStringLength; i++ )
		if( ( toUpper( string[ i ] ) == firstChar ) &&
			!strCompare( subString, string + i, subStringLength ) )
				return( TRUE );

	return( FALSE );
	}

/* Check whether a key matches the required user ID */

static BOOLEAN checkKeyMatch( const PGP_INFO *pgpInfo, 
							  const PGP_KEYINFO *keyInfo,
							  const KEY_MATCH_INFO *keyMatchInfo )
	{
	int i;

	/* If there's an explicitly requested key usage type, make sure the key
	   is suitable */
	if( ( keyMatchInfo->flags & KEYMGMT_MASK_USAGEOPTIONS ) && \
		!( keyInfo->usageFlags & keyMatchInfo->flags ) )
		return( FALSE );

	/* If we're searching by key ID, check whether this is the packet we
	   want */
	if( keyMatchInfo->keyIDtype == CRYPT_IKEYID_KEYID || \
		keyMatchInfo->keyIDtype == CRYPT_IKEYID_PGPKEYID )
		return( matchKeyID( keyInfo, keyMatchInfo->keyID, 
					keyMatchInfo->keyIDlength,
					( keyMatchInfo->keyIDtype == CRYPT_IKEYID_PGPKEYID ) ? \
						TRUE : FALSE ) );

	assert( keyMatchInfo->keyIDtype == CRYPT_KEYID_NAME || \
			keyMatchInfo->keyIDtype == CRYPT_KEYID_EMAIL );

	/* We're searching by user ID, walk down the list of userIDs checking
	   for a match */
	for( i = 0; i < pgpInfo->lastUserID; i++ )
		/* Check if it's the one we want.  If it's a key with subkeys and no
		   usage type is explicitly specified, this will always return the
		   main key.  This is the best solution since the main key is always
		   a signing key, which is more likely to be what the user wants.
		   Encryption keys will typically only be accessed via envelopes,
		   and the enveloping code can specify a preference of an encryption-
		   capable key, while signing keys will be read directly and pushed
		   into the envelope */
		if( matchSubstring( ( char * ) keyMatchInfo->keyID, 
							keyMatchInfo->keyIDlength, pgpInfo->userID[ i ],
							pgpInfo->userIDlen[ i ] ) )
			return( TRUE );

	return( FALSE );
	}

/* Locate a key based on an ID.  This is complicated somewhat by the fact 
   that PGP */

static PGP_INFO *findEntry( const PGP_INFO *pgpInfo,
							const CRYPT_KEYID_TYPE keyIDtype,
							const void *keyID, const int keyIDlength,
							const int requestedUsage, PGP_KEYINFO **keyInfo )
	{
	CONST_INIT KEY_MATCH_INFO keyMatchInfo = \
						{ keyIDtype, keyID, keyIDlength, requestedUsage };
	int i;

	for( i = 0; i < MAX_PGP_OBJECTS; i++ )
		{
		if( checkKeyMatch( &pgpInfo[ i ], &pgpInfo[ i ].key,
						   &keyMatchInfo ) )
			{
			if( keyInfo != NULL )
				*keyInfo = ( PGP_KEYINFO * ) &pgpInfo->key;
			return( ( PGP_INFO * ) &pgpInfo[ i ] );
			}
		if( checkKeyMatch( &pgpInfo[ i ], &pgpInfo[ i ].subKey,
						   &keyMatchInfo ) )
			{
			if( keyInfo != NULL )
				*keyInfo = ( PGP_KEYINFO * ) &pgpInfo->subKey;
			return( ( PGP_INFO * ) &pgpInfo[ i ] );
			break;
			}
		}

	return( NULL );
	}

/****************************************************************************
*																			*
*									Read a Key								*
*																			*
****************************************************************************/

/* Read the information needed to decrypt a secret key */

static int readSecretKeyDecryptionInfo( STREAM *stream, PGP_KEYINFO *keyInfo )
	{
	const int ctb = sgetc( stream );
	int status;

	/* Clear return value */
	keyInfo->cryptAlgo = keyInfo->hashAlgo = CRYPT_ALGO_NONE;
	keyInfo->saltSize = keyInfo->keySetupIterations = 0;

	/* If no encryption is being used, we mark the key as unusable.  This 
	   isn't exactly the correct thing to do, but storing plaintext private 
	   keys on disk is extremely dangerous and we probably shouldn't be
	   using them, and an attempt to import an unencrypted key will trigger
	   so many security check failures in the key unwrap code it's not even
	   worth trying */
	if( !ctb )
		return( OK_SPECIAL );

	/* If it's a direct algorithm specifier, it's a PGP 2.x packet with
	   raw IDEA encryption */
	if( ctb == PGP_ALGO_IDEA )
		{
		keyInfo->cryptAlgo = CRYPT_ALGO_IDEA;
		keyInfo->hashAlgo = CRYPT_ALGO_MD5;
		}
	else
		{
		int value;

		/* Must be an S2K specifier */
		if( ctb != PGP_S2K && ctb != PGP_S2K_HASHED )
			return( CRYPT_ERROR_BADDATA );

		/* Get the key wrap algorithm and S2K information */
		if( ( keyInfo->cryptAlgo = \
				pgpToCryptlibAlgo( sgetc( stream ),
								   PGP_ALGOCLASS_PWCRYPT ) ) == CRYPT_ALGO_NONE )
			/* Unknown algorithm type, skip this packet */
			return( OK_SPECIAL );
		value = sgetc( stream );
		if( value != 0 && value != 1 && value != 3 )
			return( cryptStatusError( value ) ? value : OK_SPECIAL );
		if( ( keyInfo->hashAlgo = \
				pgpToCryptlibAlgo( sgetc( stream ),
								   PGP_ALGOCLASS_HASH ) ) == CRYPT_ALGO_NONE )
			/* Unknown algorithm type, skip this packet */
			return( OK_SPECIAL );
		if( value != 0 )
			{
			/* It's a salted hash */
			status = sread( stream, keyInfo->salt, PGP_SALTSIZE );
			if( cryptStatusError( status ) )
				return( status );
			keyInfo->saltSize = PGP_SALTSIZE;
			}
		if( value == 3 )
			{
			/* Salted iterated hash, get the iteration count, limited to a
			   sane value.  The "iteration count" is actually a count of how
			   many bytes are hashed, this is because the "iterated hashing"
			   treats the salt + password as an infinitely-repeated sequence
			   of values and hashes the resulting string for PGP-iteration-
			   count bytes worth.  The value we calculate here (to prevent
			   overflow on 16-bit machines) is the count without the
			   base * 64 scaling, this also puts the range within the value
			   of the standard sanity check */
			value = sgetc( stream );
			if( cryptStatusError( value ) )
				return( value );
			keyInfo->keySetupIterations = \
					( 16 + ( ( long ) value & 0x0F ) ) << ( value >> 4 );
			if( keyInfo->keySetupIterations <= 0 || \
				keyInfo->keySetupIterations > MAX_KEYSETUP_ITERATIONS )
				return( CRYPT_ERROR_BADDATA );
			}
		}
	status = sread( stream, keyInfo->iv, PGP_IVSIZE );
	return( cryptStatusError( status ) ? status : CRYPT_OK );
	}

/* Read a single key in a group of key packets */

static int readKey( STREAM *stream, PGP_INFO *pgpInfo )
	{
	PGP_KEYINFO *keyInfo = &pgpInfo->key;
	HASHFUNCTION hashFunction;
	HASHINFO hashInfo;
	BYTE hash[ CRYPT_MAX_HASHSIZE ], packetHeader[ 64 ];
	BOOLEAN isPublicKey = TRUE;
	void *pubKeyPayload;
	long packetLength;
	int startPos, endPos, ctb, length, pubKeyPayloadLen;
	int value, hashSize, status;

	/* Skip CTB, packet length, and version byte */
	ctb = sPeek( stream );
	switch( getCTB( ctb ) )
		{
		case PGP_PACKET_SECKEY_SUB:
			keyInfo = &pgpInfo->subKey;
			/* Fall through */

		case PGP_PACKET_SECKEY:
			isPublicKey = FALSE;
			break;

		case PGP_PACKET_PUBKEY_SUB:
			keyInfo = &pgpInfo->subKey;
			/* Fall through */

		case PGP_PACKET_PUBKEY:
			break;

		default:
			return( cryptStatusError( ctb ) ? \
					CRYPT_ERROR_NOTFOUND : CRYPT_ERROR_BADDATA );
		}
	status = pgpReadPacketHeader( stream, NULL, &packetLength );
	if( cryptStatusError( status ) )
		return( status );
	if( packetLength < 64 || sMemDataLeft( stream ) < packetLength )
		return( CRYPT_ERROR_BADDATA );
	length = ( int ) packetLength;
	keyInfo->pubKeyData = sMemBufPtr( stream );
	startPos = stell( stream );
	endPos = startPos + length;
	value = sgetc( stream );
	if( value != PGP_VERSION_2 && value != PGP_VERSION_3 && \
		value != PGP_VERSION_OPENPGP )
		/* Unknown version number, skip this packet */
		return( OK_SPECIAL );
	pgpInfo->isOpenPGP = ( value == PGP_VERSION_OPENPGP ) ? TRUE : FALSE;

	/* Build the packet header, which is hashed along with the key components
	   to get the OpenPGP keyID.  This is generated anyway when the context
	   is created, but we need to generate it here as well in order to locate
	   the key in the first place:
		byte		ctb = 0x99
		byte[2]		length
		byte		version = 4
		byte[4]		key generation time
		byte[]		key data

	   We can't add the length or key data yet since we have to parse the
	   key data to know how long it is, so we can only build the static part
	   of the header at this point */
	packetHeader[ 0 ] = 0x99;
	packetHeader[ 3 ] = PGP_VERSION_OPENPGP;

	/* Read the timestamp and validity period (for PGP 2.x keys) */
	sread( stream, packetHeader + 4, 4 );
	if( !pgpInfo->isOpenPGP )
		sSkip( stream, 2 );

	/* Read the public key components */
	pubKeyPayload = sMemBufPtr( stream );
	pubKeyPayloadLen = stell( stream );
	value = sgetc( stream );
	if( value == PGP_ALGO_RSA || value == PGP_ALGO_RSA_ENCRYPT || \
		value == PGP_ALGO_RSA_SIGN )
		{
		/* RSA: n + e.  The LSBs of n serve as the PGP 2.x key ID, so we
		   copy the data out before continuing */
		keyInfo->pkcAlgo = CRYPT_ALGO_RSA;
		if( value != PGP_ALGO_RSA_SIGN )
			keyInfo->usageFlags = KEYMGMT_FLAG_USAGE_CRYPT;
		if( value != PGP_ALGO_RSA_ENCRYPT )
			keyInfo->usageFlags |= KEYMGMT_FLAG_USAGE_SIGN;
		length = 1 + getMPIsize( stream );
		if( sStatusOK( stream ) && \
			stell( stream ) - startPos > PGP_KEYID_SIZE )
			memcpy( keyInfo->pgpKeyID, sMemBufPtr( stream ) - PGP_KEYID_SIZE,
					PGP_KEYID_SIZE );
		length += getMPIsize( stream );
		}
	else
		{
		/* If it's an unknown algorithm, skip this key */
		if( value != PGP_ALGO_DSA && value != PGP_ALGO_ELGAMAL )
			return( cryptStatusError( value ) ? value: OK_SPECIAL );

		/* DSA/Elgamal: p + g + y */
		if( value == PGP_ALGO_DSA )
			{
			keyInfo->pkcAlgo = CRYPT_ALGO_DSA;
			keyInfo->usageFlags = KEYMGMT_FLAG_USAGE_SIGN;
			}
		else
			{
			keyInfo->pkcAlgo = CRYPT_ALGO_ELGAMAL;
			keyInfo->usageFlags = KEYMGMT_FLAG_USAGE_CRYPT;
			}
		length = 1 + getMPIsize( stream ) + getMPIsize( stream ) + \
				 getMPIsize( stream );
		if( value == PGP_ALGO_DSA )
			/* DSA has q as well */
			length += getMPIsize( stream );
		}
	status = sGetStatus( stream );
	if( cryptStatusError( status ) )
		return( status );
	keyInfo->pubKeyDataLen = stell( stream ) - startPos;
	pubKeyPayloadLen = stell( stream ) - pubKeyPayloadLen;

	/* Complete the packet header that we read earlier on by adding the
	   length information */
	packetHeader[ 1 ] = ( ( 1 + 4 + length ) >> 8 ) & 0xFF;
	packetHeader[ 2 ] = ( 1 + 4 + length ) & 0xFF;

	/* Hash the data needed to generate the OpenPGP keyID */
	getHashParameters( CRYPT_ALGO_SHA, &hashFunction, &hashSize );
	hashFunction( hashInfo, NULL, packetHeader, 1 + 2 + 1 + 4, HASH_START );
	hashFunction( hashInfo, hash, pubKeyPayload, pubKeyPayloadLen, HASH_END );
	memcpy( keyInfo->openPGPkeyID, hash + hashSize - PGP_KEYID_SIZE,
			PGP_KEYID_SIZE );

	/* If it's a private keyring, process the private key components */
	if( !isPublicKey )
		{
		/* Handle decryption info for secret components if necessary */
		status = readSecretKeyDecryptionInfo( stream, keyInfo );
		if( cryptStatusError( status ) )
			return( status );

		/* What's left is the private-key data */
		keyInfo->privKeyData = sMemBufPtr( stream );
		keyInfo->privKeyDataLen = endPos - stell( stream );
		status = sSkip( stream, keyInfo->privKeyDataLen );
		}

	/* Read the userID packet(s) */
	while( cryptStatusOK( status ) )
		{

⌨️ 快捷键说明

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