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

📄 pgp_env.c

📁 提供了很多种加密算法和CA认证及相关服务如CMP、OCSP等的开发
💻 C
📖 第 1 页 / 共 3 页
字号:
					if( envelopeInfoPtr->contentType == CRYPT_CONTENT_DATA )
						/* If there's no inner content type, we need to 
						   explicitly write an inner data header */
						state = PGP_ENVSTATE_DATA;
					break;
	
				default:
					assert( NOTREACHED );
				}
			envelopeInfoPtr->bufPos = ( int ) stell( &stream );
			sMemDisconnect( &stream );
			if( cryptStatusError( status ) )
				return( status );

			/* Reset the segmentation state (although PGP doesn't segment the
			   payload, we still need to reset the state to synchronise 
			   things like payload hashing and encryption) and set the block 
			   size mask to all ones if we're not encrypting (since we can 
			   begin and end data segments on arbitrary boundaries) */
			envelopeInfoPtr->segmentComplete = TRUE;
			if( envelopeInfoPtr->usage != ACTION_CRYPT )
				envelopeInfoPtr->blockSizeMask = -1;
			envelopeInfoPtr->lastAction = NULL;

			/* If we're not emitting any inner header, we're done */
			if( state == PGP_ENVSTATE_HEADER )
				state = PGP_ENVSTATE_DONE;
			}
		}

	/* Keep producing output until we fill the envelope buffer or run out of
	   header information to encode */
	while( state != PGP_ENVSTATE_DONE )
		{
		/* Handle key export actions */
		if( state == PGP_ENVSTATE_KEYINFO )
			{
			ACTION_LIST *lastActionPtr = envelopeInfoPtr->lastAction;

			/* Export the session key using each of the PKC keys, or
			   write the derivation information needed to recreate the
			   session key */
			while( cryptStatusOK( status ) && lastActionPtr != NULL )
				{
				if( lastActionPtr->action == ACTION_KEYEXCHANGE_PKC )
					status = writePKEPacket( &envelopeInfoPtr->auxStream,
											 envelopeInfoPtr->iCryptContext,
											 lastActionPtr->iCryptHandle );
				else
					status = writeSKEPacket( &envelopeInfoPtr->auxStream,
											 lastActionPtr->iCryptHandle );
				if( !cryptStatusError( status ) )
					{
					lastActionPtr = lastActionPtr->next;
					if( copyFromAuxStream( envelopeInfoPtr ) )
						status = CRYPT_ERROR_OVERFLOW;
					}
				}
			envelopeInfoPtr->lastAction = lastActionPtr;

			/* If we've reached the last key exchange action, move on to the
			   next state.  Since the emission of the key exchange
			   information is interruptible, we only move on to the next
			   state if there are no errors */
			if( cryptStatusError( status ) )
				break;
			state = PGP_ENVSTATE_ENCRINFO;
			}

		/* Handle encrypted content information */
		if( state == PGP_ENVSTATE_ENCRINFO )
			{
			BYTE ivInfoBuffer[ CRYPT_MAX_IVSIZE + 2 ];

			/* Set up the PGP IV information */
			status = pgpProcessIV( envelopeInfoPtr->iCryptContext, 
								   ivInfoBuffer, PGP_IVSIZE, TRUE, TRUE );
			if( cryptStatusError( status ) )
				break;

			/* Write the encrypted content header */
			status = writePacketHeader( &envelopeInfoPtr->auxStream, 
						PGP_PACKET_ENCR, PGP_IVSIZE + 2 + \
						sizeofPacketHeader( PGP_DATA_HEADER_SIZE + \
											envelopeInfoPtr->payloadSize ) + \
						PGP_DATA_HEADER_SIZE + envelopeInfoPtr->payloadSize );
			if( cryptStatusOK( status ) )
				status = swrite( &envelopeInfoPtr->auxStream, ivInfoBuffer, 
								 PGP_IVSIZE + 2 );
			if( cryptStatusOK( status ) && \
				copyFromAuxStream( envelopeInfoPtr ) )
				status = CRYPT_ERROR_OVERFLOW;
			if( cryptStatusError( status ) )
				break;

			/* Make sure we start a new segment if we try to add any data */
			envelopeInfoPtr->segmentComplete = TRUE;

			/* Before we can finish we have to push in the inner data 
			   header */
			state = PGP_ENVSTATE_DATA;
			}

		/* Handle data payload information */
		if( state == PGP_ENVSTATE_DATA )
			{
			STREAM headerStream;
			BYTE headerBuffer[ 64 ];

			/* Write the inner data header.  This is part of the processed 
			   payload so we can't copy it to the auxiliary stream but have 
			   to use copyToEnvelope().  Since recovering from a partial copy
			   is a bit tricky, we first make sure there's enough room left
			   to copy in the header */
			if( envelopeInfoPtr->bufSize - envelopeInfoPtr->bufPos < 16 )
				{
				status = CRYPT_ERROR_OVERFLOW;
				break;
				}

			/* There's enough room for the header, copy it in */
			sMemOpen( &headerStream, headerBuffer, 64 );
			writePacketHeader( &headerStream, PGP_PACKET_DATA, 
						PGP_DATA_HEADER_SIZE + envelopeInfoPtr->payloadSize );
			swrite( &headerStream, "b\x00\x00\x00\x00\x00", 
					PGP_DATA_HEADER_SIZE );
			status = envelopeInfoPtr->copyToEnvelope( envelopeInfoPtr,
							headerBuffer, ( int ) stell( &headerStream ) );
			sMemClose( &headerStream );

			/* We've processed the header, if this is signed data we start 
			   hashing from this point (the PGP RFCs are wrong in this 
			   regard, only the payload is hashed, not the entire packet) */
			if( envelopeInfoPtr->usage == ACTION_SIGN )
				envelopeInfoPtr->hashActionsActive = TRUE;

			/* We're finished */
			state = PGP_ENVSTATE_DONE;
			}
		}

	/* Remember the state information */
	envelopeInfoPtr->pgpEnvState = state;

	return( status );
	}

/* Output as much of the postamble as possible into the envelope buffer */

static int emitPostamble( ENVELOPE_INFO *envelopeInfoPtr )
	{
	STREAM *stream = &envelopeInfoPtr->auxStream;
	RESOURCE_DATA msgData;
	BYTE extraData[ 1024 ], *extraDataPtr = extraData;
	BYTE hash[ CRYPT_MAX_HASHSIZE ], signature[ CRYPT_MAX_PKCSIZE ];
	int extraDataLength = 1024, signatureLength, iAndSlength = 0, status;

	/* If there's any data left in the auxiliary buffer, try and empty that
	   first */
	if( envelopeInfoPtr->auxBufPos && copyFromAuxBuffer( envelopeInfoPtr ) )
		return( CRYPT_ERROR_OVERFLOW );

	/* The only PGP packet which has a trailer is signed data using the new
	   (post-2.x) one-pass signature packet, if we're not signing data we can
	   exit now */
	if( envelopeInfoPtr->usage != ACTION_SIGN )
		{
		/* Flush any remaining data from internal buffers into the envelope 
		   buffer if necessary */
		if( envelopeInfoPtr->envState == ENVSTATE_NONE )
			{
			status = envelopeInfoPtr->copyToEnvelope( envelopeInfoPtr, 
													  ( BYTE * ) "", 0 );
			if( cryptStatusError( status ) )
				return( status );
			}

		/* We're done */
		envelopeInfoPtr->envState = ENVSTATE_DONE;
		return( CRYPT_OK );
		}

	/* If we didn't get through flushing the signature data into the main
	   buffer the last time, we've done it now and can wrap up */
	if( envelopeInfoPtr->envState == ENVSTATE_SIGNATURE )
		{
		envelopeInfoPtr->envState = ENVSTATE_DONE;
		return( CRYPT_OK );
		}

	/* Check whether there's an issuerAndSerialNumber present and allocate a
	   larger buffer for it if necessary.  If it's too big for the auxiliary
	   buffer (which would make it a highly peculiar cert) we don't include 
	   this info, since it's usually never used (the PKCS #7/CMS/SMIME 
	   enveloping code dynamically expands the buffer, but it's of low 
	   enough importance in PGP that it's not really worth the extra 
	   complexity) */
	setResourceData( &msgData, NULL, 0 );
	status = krnlSendMessage( envelopeInfoPtr->postActionList->iCryptHandle, 
							  RESOURCE_IMESSAGE_GETATTRIBUTE_S, &msgData, 
							  CRYPT_IATTRIBUTE_ISSUERANDSERIALNUMBER );
	if( cryptStatusOK( status ) && \
		msgData.length < envelopeInfoPtr->auxBufSize - 128 )
		{
		if( msgData.length > extraDataLength - 128 )
			{
			extraDataLength = 128 + msgData.length;
			if( ( extraDataPtr = malloc( extraDataLength ) ) == NULL )
				return( CRYPT_ERROR_MEMORY );
			}
		iAndSlength = msgData.length;
		}

	/* Complete the hashing and create the signature.  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.

	   PGP processes the authenticated attributes in an odd way, first 
	   hashing part of the packet from the version number to the end of the 
	   authenticated attributes, then some more stuff, and finally signing 
	   that.  Because of this complex way of handling things, we can't write 
	   the signature packet in one go but instead have to write the part 
	   we can create now, hash the portion which is hashed (all but the last
	   16 bits, the length of the unathenticated attributes), and then go 
	   back and assemble the whole thing including the length and signature 
	   later on from the individual parts */
	status = extraDataLength = \
		writeSignaturePacketHeader( extraData, extraDataLength,
							envelopeInfoPtr->postActionList->iCryptHandle, 
							envelopeInfoPtr->actionList->iCryptHandle,
							iAndSlength );
	status = krnlSendMessage( envelopeInfoPtr->actionList->iCryptHandle,
							  RESOURCE_IMESSAGE_CTX_HASH, 
							  extraData, extraDataLength - 2 );
	if( cryptStatusOK( status ) )
		{
		BYTE buffer[ 8 ], *bufPtr = buffer + 2;

		/* Hash in even more stuff at the end */
		buffer[ 0 ] = 0x04;
		buffer[ 1 ] = 0xFF;
		mputBLong( bufPtr, extraDataLength - 2 );
		status = krnlSendMessage( envelopeInfoPtr->actionList->iCryptHandle,
								  RESOURCE_IMESSAGE_CTX_HASH, buffer, 6 );
		}
	if( cryptStatusOK( status ) )
		status = krnlSendMessage( envelopeInfoPtr->actionList->iCryptHandle,
								  RESOURCE_IMESSAGE_CTX_HASH, "", 0 );
	if( cryptStatusOK( status ) )
		{
		RESOURCE_DATA msgData;

		setResourceData( &msgData, hash, CRYPT_MAX_HASHSIZE );
		status = krnlSendMessage( envelopeInfoPtr->actionList->iCryptHandle,
								  RESOURCE_IMESSAGE_GETATTRIBUTE_S,
								  &msgData, CRYPT_CTXINFO_HASHVALUE );
		}
	if( cryptStatusOK( status ) )
		status = iCryptCreateSignatureEx( signature, &signatureLength, 
							CRYPT_FORMAT_PGP, 
							envelopeInfoPtr->postActionList->iCryptHandle, 
							envelopeInfoPtr->actionList->iCryptHandle,
							CRYPT_UNUSED, CRYPT_UNUSED );
	if( cryptStatusError( status ) )
		{
		zeroise( extraDataPtr, extraDataLength );
		if( extraDataPtr != extraData )
			free( extraDataPtr );
		return( status );
		}

	/* Write the signature packet:
	  [	signature packet header ]
		byte[2]	hash check
		mpi		signature

	  Since we've already had to write half the packet earlier on in order
	  to hash it, we copy this pre-encoded information across and add the
	  header and trailer around it */
	writePacketHeader( stream, PGP_PACKET_SIGNATURE, 
					   extraDataLength + 2 + signatureLength );
	swrite( stream, extraData, extraDataLength );
	swrite( stream, hash, 2 );			/* Hash check */
	status = swrite( stream, signature, signatureLength );
	zeroise( extraDataPtr, extraDataLength );
	zeroise( signature, CRYPT_MAX_PKCSIZE );
	if( extraDataPtr != extraData )
		free( extraDataPtr );
	if( cryptStatusError( status ) )
		return( status );

	/* Flush the data through into the main buffer */
	if( copyFromAuxStream( envelopeInfoPtr ) )
		{
		/* We couldn't flush it all through, remember that we're still in
		   the middle of the signature creation process */
		envelopeInfoPtr->envState = ENVSTATE_SIGNATURE;
		return( CRYPT_ERROR_OVERFLOW );
		}
	envelopeInfoPtr->envState = ENVSTATE_DONE;

	return( status );
	}

/****************************************************************************
*																			*
*							Envelope Access Routines						*
*																			*
****************************************************************************/

void initPGPEnveloping( ENVELOPE_INFO *envelopeInfoPtr )
	{
	/* Set the access method pointers */
	envelopeInfoPtr->emitPreamble = emitPreamble;
	envelopeInfoPtr->emitPostamble = emitPostamble;
	envelopeInfoPtr->checkCryptAlgo = checkCryptAlgo;
	envelopeInfoPtr->checkHashAlgo = checkHashAlgo;

	/* Set up the processing state information */
	envelopeInfoPtr->pgpEnvState = PGP_ENVSTATE_NONE;

	/* Set the PGP default algorithms.  PGP is a bit tricky since there's no 
	   simple function we can use to check whether a particular algorithm is 
	   compatible with the underlying data format, so we have to hardcode in 
	   the allowed values here */
	krnlSendMessage( envelopeInfoPtr->ownerHandle, 
					 RESOURCE_IMESSAGE_GETATTRIBUTE, 
					 &envelopeInfoPtr->defaultHash, CRYPT_OPTION_ENCR_HASH );
	if( !isPGPHashAlgo( envelopeInfoPtr->defaultHash ) )
		envelopeInfoPtr->defaultHash = CRYPT_ALGO_SHA;
	krnlSendMessage( envelopeInfoPtr->ownerHandle, 
					 RESOURCE_IMESSAGE_GETATTRIBUTE, 
					 &envelopeInfoPtr->defaultAlgo, CRYPT_OPTION_ENCR_ALGO );
	if( isPGPCryptAlgo( envelopeInfoPtr->defaultAlgo ) )
		envelopeInfoPtr->defaultAlgo = CRYPT_ALGO_3DES;
	envelopeInfoPtr->defaultMAC = CRYPT_ERROR;

	/* Turn off segmentation of the envelope payload (PGP has a single 
	   length at the start of the data) */
	envelopeInfoPtr->flags |= ENVELOPE_NOSEGMENT;
	}

⌨️ 快捷键说明

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