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

📄 denv_pgp.c

📁 老外写的加密库cryptlib(版本3.1)
💻 C
📖 第 1 页 / 共 3 页
字号:
/****************************************************************************
*																			*
*					 cryptlib PGP De-enveloping Routines					*
*					 Copyright Peter Gutmann 1996-2002						*
*																			*
****************************************************************************/

#include <stdlib.h>
#include <string.h>
#if defined( INC_ALL )
  #include "envelope.h"
  #include "pgp.h"
  #include "misc_rw.h"
  #include "objinfo.h"
#elif defined( INC_CHILD )
  #include "envelope.h"
  #include "pgp.h"
  #include "../misc/misc_rw.h"
  #include "../misc/objinfo.h"
#else
  #include "envelope/envelope.h"
  #include "envelope/pgp.h"
  #include "misc/misc_rw.h"
  #include "misc/objinfo.h"
#endif /* Compiler-specific includes */

#ifdef USE_PGP

/****************************************************************************
*																			*
*								Utility Routines							*
*																			*
****************************************************************************/

/* Get information on a PGP data packet */

static int getPacketInfo( STREAM *stream, ENVELOPE_INFO *envelopeInfoPtr,
						  long *length )
	{
	int ctb, status;

	/* Read the packet header and extract information from the CTB.  Note 
	   that the assignment of version numbers is speculative only, since 
	   it's possible to use PGP 2.x packet headers to wrap up OpenPGP 
	   packets */
	status = pgpReadPacketHeader( stream, &ctb, length );
	if( cryptStatusError( status ) )
		return( status );
	if( ( ctb & PGP_CTB_OPENPGP ) == PGP_CTB_OPENPGP )
		envelopeInfoPtr->version = PGP_VERSION_OPENPGP;
	else
		envelopeInfoPtr->version = PGP_VERSION_2;

	/* Extract and return the packet type */
	return( ( ( ctb & PGP_CTB_OPENPGP ) == PGP_CTB_OPENPGP ) ? \
			( ctb & 0x3F ) : ( ( ctb >> 2 ) & 0x0F ) );
	}

/****************************************************************************
*																			*
*						Read Key Exchange/Signature Packets					*
*																			*
****************************************************************************/

/* Add information about an object to an envelope's content information list */

static int addContentListItem( STREAM *stream,
							   ENVELOPE_INFO *envelopeInfoPtr,
							   const BOOLEAN isContinuedSignature )
	{
	QUERY_INFO queryInfo;
	CONTENT_LIST *contentListItem;
	void *object = NULL, *originalObjectPtr;
	int status;

	/* PGP 2.x password-encrypted data is detected by the absence of any
	   other keying object rather than by finding a concrete object type, so
	   if we're passed a null stream we add a password pseudo-object */
	if( stream == NULL )
		{
		CONTENT_ENCR_INFO *encrInfo;

		contentListItem = createContentListItem( envelopeInfoPtr->memPoolState,
												 CRYPT_FORMAT_PGP, NULL, 0, 
												 FALSE );
		if( contentListItem == NULL )
			return( CRYPT_ERROR_MEMORY );
		encrInfo = &contentListItem->clEncrInfo;
		contentListItem->envInfo = CRYPT_ENVINFO_PASSWORD;
		encrInfo->cryptAlgo = CRYPT_ALGO_IDEA;
		encrInfo->cryptMode = CRYPT_MODE_CFB;
		encrInfo->keySetupAlgo = CRYPT_ALGO_MD5;
		appendContentListItem( envelopeInfoPtr, contentListItem );
		return( CRYPT_OK );
		}

	/* Find the size of the object, allocate a buffer for it if necessary,
	   and copy it across */
	originalObjectPtr = sMemBufPtr( stream );
	status = queryPgpObject( stream, &queryInfo );
	if( cryptStatusError( status ) )
		return( status );
	if( queryInfo.type == CRYPT_OBJECT_SIGNATURE && \
		queryInfo.dataStart == NULL )
		{
		/* It's a one-pass signature packet, the signature information 
		   follows in another packet that will be added later */
		sSkip( stream, ( int ) queryInfo.size );
		queryInfo.size = 0;
		}
	else
		{
		if( ( object = clAlloc( "addContentListItem", \
								( size_t ) queryInfo.size ) ) == NULL )
			return( CRYPT_ERROR_MEMORY );
		sread( stream, object, ( int ) queryInfo.size );
		}

	/* If it's the rest of the signature data from a one-pass signature,
	   locate the first half of the signature info and complete the
	   information.  In theory this could get ugly because there could be
	   multiple one-pass signature packets present, however PGP handles
	   multiple signatures by nesting them so this isn't a problem */
	if( isContinuedSignature )
		{
		for( contentListItem = envelopeInfoPtr->contentList;
			 contentListItem != NULL && \
				contentListItem->envInfo != CRYPT_ENVINFO_SIGNATURE;
			 contentListItem = contentListItem->next );
		assert( contentListItem->object == NULL && \
				contentListItem->objectSize == 0 );
		contentListItem->object = object;
		contentListItem->objectSize = ( int ) queryInfo.size;
		}
	else
		{
		/* Allocate memory for the new content list item and copy information
		   on the item across */
		contentListItem = createContentListItem( envelopeInfoPtr->memPoolState,
									CRYPT_FORMAT_PGP, object,
									( int ) queryInfo.size,
									queryInfo.type == CRYPT_OBJECT_SIGNATURE );
		if( contentListItem == NULL )
			{
			if( object != NULL )
				clFree( "addContentListItem", object );
			return( CRYPT_ERROR_MEMORY );
			}
		}
	if( queryInfo.type == CRYPT_OBJECT_PKCENCRYPTED_KEY || \
		queryInfo.type == CRYPT_OBJECT_SIGNATURE )
		{
		/* Remember details of the enveloping info that we require to 
		   continue.  Note that if we're processing a one-pass signature 
		   packet followed by signature data, the keyID and algorithm info
		   in the signature packet takes precendence in case of 
		   inconsistencies between the two */
		if( queryInfo.type == CRYPT_OBJECT_PKCENCRYPTED_KEY )
			{
			CONTENT_ENCR_INFO *encrInfo = &contentListItem->clEncrInfo;

			contentListItem->envInfo = CRYPT_ENVINFO_PRIVATEKEY;
			encrInfo->cryptAlgo = queryInfo.cryptAlgo;
			}
		else
			{
			CONTENT_SIG_INFO *sigInfo = &contentListItem->clSigInfo;

			contentListItem->envInfo = CRYPT_ENVINFO_SIGNATURE;
			sigInfo->hashAlgo = queryInfo.hashAlgo;
			if( queryInfo.attributeStart != NULL )
				{
				sigInfo->extraData = \
					( BYTE * ) contentListItem->object + \
					( ( BYTE * ) queryInfo.attributeStart - ( BYTE * ) originalObjectPtr );
				sigInfo->extraDataLength = queryInfo.attributeLength;
				}
			if( queryInfo.unauthAttributeStart != NULL )
				{
				sigInfo->extraData2 = \
					( BYTE * ) contentListItem->object + \
					( ( BYTE * ) queryInfo.unauthAttributeStart - ( BYTE * ) originalObjectPtr );
				sigInfo->extraData2Length = queryInfo.unauthAttributeLength;
				}
			}
		memcpy( contentListItem->keyID, queryInfo.keyID, 
				queryInfo.keyIDlength );
		contentListItem->keyIDsize = queryInfo.keyIDlength;
		if( queryInfo.iAndSStart != NULL )
			{
			contentListItem->issuerAndSerialNumber = \
					( BYTE * ) contentListItem->object + \
					( ( BYTE * ) queryInfo.iAndSStart - ( BYTE * ) originalObjectPtr );
			contentListItem->issuerAndSerialNumberSize = queryInfo.iAndSLength;
			}
		}
	if( queryInfo.type == CRYPT_OBJECT_ENCRYPTED_KEY )
		{
		CONTENT_ENCR_INFO *encrInfo = &contentListItem->clEncrInfo;

		/* Remember details of the enveloping info that we require to 
		   continue */
		if( queryInfo.keySetupAlgo != CRYPT_ALGO_NONE )
			{
			contentListItem->envInfo = CRYPT_ENVINFO_PASSWORD;
			encrInfo->keySetupAlgo = queryInfo.keySetupAlgo;
			encrInfo->keySetupIterations = queryInfo.keySetupIterations;
			memcpy( encrInfo->saltOrIV, queryInfo.salt, 
					queryInfo.saltLength );
			encrInfo->saltOrIVsize = queryInfo.saltLength;
			}
		else
			contentListItem->envInfo = CRYPT_ENVINFO_KEY;
		encrInfo->cryptAlgo = queryInfo.cryptAlgo;
		encrInfo->cryptMode = CRYPT_MODE_CFB;
		}
	if( queryInfo.dataStart != NULL )
		{
		contentListItem->payload = \
					( BYTE * ) contentListItem->object + \
					( ( BYTE * ) queryInfo.dataStart - ( BYTE * ) originalObjectPtr );
		contentListItem->payloadSize = queryInfo.dataLength;
		}
	if( queryInfo.version > envelopeInfoPtr->version )
		envelopeInfoPtr->version = queryInfo.version;

	/* If we're completing the read of the data in a one-pass signature
	   packet, we're done */
	if( isContinuedSignature )
		return( CRYPT_OK );

	/* If it's signed data, create a hash action to process it */
	if( queryInfo.type == CRYPT_OBJECT_SIGNATURE )
		{
		MESSAGE_CREATEOBJECT_INFO createInfo;

		/* Append a new hash action to the action list */
		setMessageCreateObjectInfo( &createInfo,
									contentListItem->clSigInfo.hashAlgo );
		status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
								  IMESSAGE_DEV_CREATEOBJECT, &createInfo, 
								  OBJECT_TYPE_CONTEXT );
		if( cryptStatusOK( status ) && \
			addAction( &envelopeInfoPtr->actionList, 
					   envelopeInfoPtr->memPoolState, ACTION_HASH,
					   createInfo.cryptHandle ) == NULL )
			{
			krnlSendNotifier( createInfo.cryptHandle, IMESSAGE_DECREFCOUNT );
			status = CRYPT_ERROR_MEMORY;
			}
		if( cryptStatusError( status ) )
			{
			deleteContentList( envelopeInfoPtr->memPoolState, 
							   contentListItem );
			return( status );
			}
		}
	appendContentListItem( envelopeInfoPtr, contentListItem );

	return( CRYPT_OK );
	}

/****************************************************************************
*																			*
*						Process Envelope Preamble/Postamble					*
*																			*
****************************************************************************/

/* Process the non-data portions of a PGP message.  This is a complex event-
   driven state machine, but instead of reading along a (hypothetical
   Turing-machine) tape, someone has taken the tape and cut it into bits and
   keeps feeding them to us and saying "See what you can do with this" (and
   occasionally "Where's the bloody spoons?").  Since PGP uses sequential
   discrete packets rather than the nested objects encountered in the ASN.1-
   encoded data format, the parsing code is made somewhat simpler because
   (for example) the PKC info is just an unconnected sequence of packets
   rather than a SEQUENCE or SET OF as for cryptlib and PKCS #7.  OTOH since
   there's no indication of what's next we have to perform a complex
   lookahead to see what actions we have to take once we get to the payload */

static int processPreamble( ENVELOPE_INFO *envelopeInfoPtr )
	{
	PGP_DEENV_STATE state = envelopeInfoPtr->pgpDeenvState;
	STREAM stream;
	int packetType, length, streamPos = 0, status = CRYPT_OK;
	long packetLength;

	/* If we've finished processing the start of the message, header, don't
	   do anything */
	if( state == PGP_DEENVSTATE_DONE )
		return( CRYPT_OK );

	sMemConnect( &stream, envelopeInfoPtr->buffer, envelopeInfoPtr->bufPos );

	/* Keep consuming information until we run out of input or reach the
	   plaintext data packet */
	while( state != PGP_DEENVSTATE_DONE )
		{
		/* Read the PGP packet type and figure out what we've got */
		if( state == PGP_DEENVSTATE_NONE )
			{
			int value;

			streamPos = stell( &stream );
			packetType = getPacketInfo( &stream, envelopeInfoPtr, &packetLength );
			if( cryptStatusError( packetType ) )
				return( packetType );

			/* Process as much of the header as we can and move on to the next
			   state.  Since PGP uses sequential discrete packets, for any
			   of the non-payload packet types we stay in the "none" state
			   because we don't know what's next */
			switch( packetType )
				{
				case PGP_PACKET_DATA:
					/* Skip the content-type, filename, and date */
					sSkip( &stream, 1 );
					length = sgetc( &stream );
					if( !cryptStatusError( length ) )
						sSkip( &stream, length + 4 );
					status = sGetStatus( &stream );
					if( cryptStatusError( status ) )
						break;

					/* Remember where we are and move on to the next state */
					envelopeInfoPtr->payloadSize = packetLength - \
												   ( 1 + 1 + length + 4 );
					if( envelopeInfoPtr->payloadSize < 1 )
						{
						status = CRYPT_ERROR_BADDATA;
						break;

⌨️ 快捷键说明

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