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

📄 pgp_misc.c

📁 提供了很多种加密算法和CA认证及相关服务如CMP、OCSP等的开发
💻 C
字号:
/****************************************************************************
*																			*
*							  PGP Support Routines							*
*						Copyright Peter Gutmann 1992-2002					*
*																			*
****************************************************************************/

#include <stdlib.h>
#include <string.h>
#if defined( INC_ALL )
  #include "crypt.h"
  #include "asn1.h"
  #include "stream.h"
  #include "pgp.h"
#elif defined( INC_CHILD )
  #include "../crypt.h"
  #include "../keymgmt/asn1.h"
  #include "../keymgmt/stream.h"
  #include "pgp.h"
#else
  #include "crypt.h"
  #include "keymgmt/asn1.h"
  #include "keymgmt/stream.h"
  #include "envelope/pgp.h"
#endif /* Compiler-specific includes */

/****************************************************************************
*																			*
*							PGP Data Packet Read Routines					*
*																			*
****************************************************************************/

/* Get the length of a packet based on the CTB length field */

static LONG readLong( STREAM *stream )
	{
	LONG value;

	value = ( ( LONG ) sgetc( stream ) ) << 24;
	value |= ( ( LONG ) sgetc( stream ) ) << 16;
	value |= ( ( LONG ) sgetc( stream ) ) << 8;
	value |= ( LONG ) sgetc( stream );
	return( value );
	}

long pgpGetLength( STREAM *stream, const int ctb )
	{
	long length;

	/* If it's an OpenPGP CTB, undo the hand-Huffman-coding */
	if( ( ctb & PGP_CTB_OPENPGP ) == PGP_CTB_OPENPGP )
		{
		length = sgetc( stream );

		if( length >= 192 )
			{
			if( length <= 223 )
				length = ( ( length - 192 ) << 8 ) + sgetc( stream );
			else
				{
				if( length != 0xFF )
					/* It's an indefinite-length encoding.  These are an
					   incredible pain to handle and don't seem to be
					   used by anything (the only data type which would need
					   them, compressed data, uses the 2.x CTB 0xA3 instead)
					   so we don't try and do anything with it */
					return( CRYPT_ERROR_BADDATA );
				length = readLong( stream );
				}
			}
		}
	else
		/* It's a PGP 2.x CTB, decode the length as a byte, word, or long */
		switch( ctb & 3 )
			{
			case 0:
				length = sgetc( stream );
				break;

			case 1:
				length = ( sgetc( stream ) << 8 ) | sgetc( stream );
				break;

			case 2:
				length = readLong( stream );
				break;

			default:
				/* A length value of 3 indicates that the data length is 
				   determined externally, this is a deprecated PGP 2.x value 
				   which we don't handle */
				return( CRYPT_ERROR_BADDATA );
			}
	return( ( length < 0 ) ? CRYPT_ERROR_BADDATA : length );
	}

/* Read/write a multiprecision integer value */

int pgpReadMPI( STREAM *stream, BYTE *data )
	{
	int bitLength, length, status;

	bitLength = ( sgetc( stream ) << 8 ) | sgetc( stream );
	length = bitsToBytes( bitLength );
	if( length < 1 || length > PGP_MAX_MPISIZE )
		return( CRYPT_ERROR_BADDATA );
	if( data == NULL )
		status = sSkip( stream, length );
	else
		status = sread( stream, data, length );
	return( cryptStatusError( status ) ? status : bitLength );
	}

int pgpWriteMPI( STREAM *stream, const BYTE *data, const int length )
	{
	const int bitLength = bytesToBits( length );

	sputc( stream, ( bitLength >> 8 ) & 0xFF );
	sputc( stream, bitLength & 0xFF );
	return( swrite( stream, data, length ) );
	}

/****************************************************************************
*																			*
*							Misc. PGP-related Routines						*
*																			*
****************************************************************************/

/* Checksum an MPI */

WORD pgpChecksumMPI( BYTE *data, int length )
	{
	WORD checkSum = ( ( BYTE ) ( length >> 8 ) ) + ( ( BYTE ) length );

	length = bitsToBytes( length );
	while( length-- )
		checkSum += *data++;
	return( checkSum );
	}

/* Create an encryption key from a password */

int pgpPasswordToKey( CRYPT_CONTEXT iCryptContext, const char *password,
					  const int passwordLength, const CRYPT_ALGO hashAlgo,
					  const BYTE *salt, const int iterations )
	{
	CRYPT_ALGO algorithm;
	RESOURCE_DATA msgData;
	HASHFUNCTION hashFunction;
	BYTE hashedKey[ CRYPT_MAX_KEYSIZE ];
	int hashSize, keySize, status;

	/* Get various parameters needed to process the password */
	status = krnlSendMessage( iCryptContext, RESOURCE_IMESSAGE_GETATTRIBUTE, 
							  &algorithm, CRYPT_CTXINFO_ALGO );
	if( cryptStatusOK( status ) )
		status = krnlSendMessage( iCryptContext, RESOURCE_IMESSAGE_GETATTRIBUTE, 
								  &keySize, CRYPT_CTXINFO_KEYSIZE );
	if( cryptStatusError( status ) )
		return( status );
	if( algorithm == CRYPT_ALGO_BLOWFISH )
		/* PGP limits the Blowfish key size to 128 bits rather than the more
		   usual 448 bits */
		keySize = 16;
	getHashParameters( hashAlgo, &hashFunction, &hashSize );

	/* Hash the password */
	if( salt != NULL )
		{
		MECHANISM_DERIVE_INFO mechanismInfo;

		/* Turn the user key into an encryption context key */
		setMechanismDeriveInfo( &mechanismInfo, hashedKey, keySize,
								password, passwordLength, hashAlgo,
								salt, PGP_SALTSIZE, iterations );
		status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
								  RESOURCE_IMESSAGE_DEV_DERIVE,
								  &mechanismInfo, MECHANISM_PGP );
		if( cryptStatusError( status ) )
			return( status );

		/* Save the derivation info with the context */
		setResourceData( &msgData, ( void * ) salt, PGP_SALTSIZE );
		krnlSendMessage( iCryptContext, RESOURCE_IMESSAGE_SETATTRIBUTE_S,
						 &msgData, CRYPT_CTXINFO_KEYING_SALT );
		krnlSendMessage( iCryptContext, RESOURCE_IMESSAGE_SETATTRIBUTE, 
						 ( void * ) &iterations, CRYPT_CTXINFO_KEYING_ITERATIONS );
		status = krnlSendMessage( iCryptContext, RESOURCE_IMESSAGE_SETATTRIBUTE, 
								  ( void * ) &hashAlgo, CRYPT_CTXINFO_KEYING_ALGO );
		if( cryptStatusError( status ) )
			{
			zeroise( hashedKey, CRYPT_MAX_KEYSIZE );
			return( status );
			}
		}
	else
		hashFunction( NULL, hashedKey, ( BYTE * ) password, passwordLength, 
					  HASH_ALL );

	/* Load the key into the context */
	setResourceData( &msgData, hashedKey, keySize );
	status = krnlSendMessage( iCryptContext, RESOURCE_IMESSAGE_SETATTRIBUTE_S, 
							  &msgData, CRYPT_CTXINFO_KEY );
	zeroise( hashedKey, CRYPT_MAX_KEYSIZE );

	return( status );
	}

/* Process a PGP-style IV */

int pgpProcessIV( const CRYPT_CONTEXT iCryptContext, BYTE *ivInfo,
				  const int ivSize, const BOOLEAN isEncrypt,
				  const BOOLEAN resyncIV )
	{
	static const BYTE zeroIV[ CRYPT_MAX_IVSIZE ] = { 0 };
	RESOURCE_DATA msgData;
	int status;

	/* PGP uses a bizarre way of handling IV's which resyncs the data on 
	   some boundaries, and doesn't actually use an IV but instead prefixes 
	   the data with ivSize bytes of random information (which is effectively 
	   the IV) followed by two bytes of key check value after which there's a 
	   resync boundary which requires reloading the IV from the last ivSize 
	   bytes of ciphertext.  An exception is the encrypted private key, 
	   which does use an IV (although this can also be regarded as an 
	   ivSize-byte prefix), however there's no key check or resync.  First, 
	   we load the all-zero IV */
	setResourceData( &msgData, ( void * ) zeroIV, ivSize );
	status = krnlSendMessage( iCryptContext, 
							  RESOURCE_IMESSAGE_SETATTRIBUTE_S, 
							  &msgData, CRYPT_CTXINFO_IV );
	if( cryptStatusError( status ) )
		return( status );

	/* Then we encrypt or decrypt the first ivSize + 2 bytes of the IV 
	   data */
	if( isEncrypt )
		{
		/* Get some random data to serve as the IV, duplicate the last two 
		   bytes, and encrypt the lot */
		getNonce( ivInfo, ivSize );
		memcpy( ivInfo + ivSize, ivInfo + ivSize - 2, 2 );
		status = krnlSendMessage( iCryptContext,
								  RESOURCE_IMESSAGE_CTX_ENCRYPT, 
								  ivInfo, ivSize + 2 );
		}
	else
		{
		BYTE ivInfoBuffer[ CRYPT_MAX_IVSIZE + 2 ];

		/* Decrypt the first ivSize bytes (the effective IV) and following
		   2-byte check value */
		memcpy( ivInfoBuffer, ivInfo, ivSize + 2 );
		status = krnlSendMessage( iCryptContext,
								  RESOURCE_IMESSAGE_CTX_DECRYPT, 
								  ivInfoBuffer, ivSize + 2 );
		if( cryptStatusOK( status ) && \
			( ivInfoBuffer[ ivSize - 2 ] != ivInfoBuffer[ ivSize ] || \
			  ivInfoBuffer[ ivSize - 1 ] != ivInfoBuffer[ ivSize + 1 ] ) )
			status = CRYPT_ERROR_WRONGKEY;
		}
	if( cryptStatusError( status ) || !resyncIV )
		return( status );

	/* Finally we've got the data the way we want it, resync the IV by 
	   setting it to the last ivSize bytes of data processed unless we've
	   been told not to */
	setResourceData( &msgData, ivInfo + 2, ivSize );
	return( krnlSendMessage( iCryptContext, RESOURCE_IMESSAGE_SETATTRIBUTE_S, 
							 &msgData, CRYPT_CTXINFO_IV ) );
	}

⌨️ 快捷键说明

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