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

📄 pgp.c

📁 cryptlib是功能强大的安全工具集。允许开发人员快速在自己的软件中集成加密和认证服务。
💻 C
📖 第 1 页 / 共 4 页
字号:
		   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 groups multiple keys around the same textual ID, so we have to 
   check both keys and subkeys for a possible match */

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_STRUCT_4( KEY_MATCH_INFO keyMatchInfo, \
						 keyIDtype, keyID, keyIDlength, requestedUsage );
	int i;

	CONST_SET_STRUCT( keyMatchInfo.keyIDtype = keyIDtype; \
					  keyMatchInfo.keyID = keyID; \
					  keyMatchInfo.keyIDlength = keyIDlength; \
					  keyMatchInfo.flags = requestedUsage );

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

	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 ivSize = PGP_IVSIZE, 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 that 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 */
		value = sgetc( stream );
		if( ( keyInfo->cryptAlgo = \
				pgpToCryptlibAlgo( value,
								   PGP_ALGOCLASS_PWCRYPT ) ) == CRYPT_ALGO_NONE )
			/* Unknown algorithm type, skip this packet */
			return( OK_SPECIAL );
		if( keyInfo->cryptAlgo == CRYPT_ALGO_AES )
			{
			/* PGP uses three different algorithm IDs to identify AES with
			   different key sizes (ugh), so we have to remember the key size
			   alongside the algorithm type for this algorithm type */
			keyInfo->aesKeySize = ( value == PGP_ALGO_AES_128 ) ? 16 : \
								  ( value == PGP_ALGO_AES_192 ) ? 24 : 32;
			ivSize = 16;
			}
		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, 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 ) )
		{
		int type;

		/* Skip keyring trust packets, signature packets, and any private
		   packets (GPG uses packet type 61, which might be a DSA self-
		   signature).

		   PGP has two ways of indicating key usage, either directly via the
		   key type (e.g. PGP_ALGO_RSA_ENCRYPT vs. PGP_ALGO_RSA_SIGN) or in a
		   rather schizophrenic manner in signature packets by allowing the 
		   signer to specify an X.509-style key usage.  Since it can appear 
		   in both self-sigs and certification sigs, the exact usage for a 
		   key is somewhat complex to determine as a certification signer 
		   could indicate that they trust the key when it's used for signing 
		   while a self-signer could indicate that the key should be used 
		   for encryption.  This appears to be a preference indication 
		   rather than a hard limit like the X.509 keyUsage, and contains 
		   other odds and ends as well such as key splitting indicators.  
		   For now we don't make use of these flags as it's a bit difficult 
		   to figure out what's what, and in any case DSA vs. Elgamal 
		   doesn't need any further constraints since there's only one usage 
		   possible */
		while( cryptStatusOK( status ) )
			{
			/* See what we've got.  If we've run out of input or it's a non-
			   key-related packet, we're done */
			ctb = status = sPeek( stream );
			type = getCTB( ctb );
			if( cryptStatusError( status ) || \
				( type != PGP_PACKET_TRUST && type != PGP_PACKET_SIGNATURE && \
				  type != PGP_PACKET_USERATTR && !isPrivatePacket( type ) ) )
				break;

			/* Skip the packet.  If we get an error at this point, we don't
			   immediately bail out but try and return at least a partial
			   response */
			status = pgpReadPacketHeader( stream, &ctb, &packetLength );
			if( cryptStatusOK( status ) )
				status = sSkip( stream, packetLength );
			}

		/* If we've reached the end of the current collection of key
		   packets, exit */
		if( cryptStatusError( status ) || type != PGP_PACKET_USERID )
			{
			/* If there's no user ID present, set a generic label */
			if( pgpInfo->lastUserID == 0 )
				{
				pgpInfo->userID[ 0 ] = "PGP key (no user ID found)";
				pgpInfo->userIDlen[ 0 ] = 26;
				pgpInfo->lastUserID = 1;
				}

			return( CRYPT_OK );
			}

		/* Record the userID */
		status = pgpReadPacketHeader( stream, &ctb, &packetLength );
		if( cryptStatusError( status ) )
			return( status );
		pgpInfo->userID[ pgpInfo->lastUserID ] = sMemBufPtr( stream );
		pgpInfo->userIDlen[ pgpInfo->lastUserID++ ] = ( int ) packetLength;

⌨️ 快捷键说明

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