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

📄 pgp_env.c

📁 提供了很多种加密算法和CA认证及相关服务如CMP、OCSP等的开发
💻 C
📖 第 1 页 / 共 3 页
字号:
		byte	sigType
		byte	sigAlgo
		byte	hashAlgo
		byte[2]	length of auth.attributes
		byte[]	authenticated attributes
		byte[2]	length of unauth.attributes = 0
	  [	byte[2]	hash check ]
	  [	mpi		signature  ]

   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 which is hashed, hash it, and 
   then go back and reassemble the whole thing from the pre-hashed data and 
   the length, hash check, and signature */

static int writeSignaturePacketHeader( void *dataBuffer, const int dataBufSize,
									   const CRYPT_CONTEXT iSignContext, 
									   const CRYPT_CONTEXT iHashContext,
									   const int iAndSlength )
	{
	CRYPT_ALGO hashAlgo, signAlgo;
	STREAM stream;
	RESOURCE_DATA msgData;
	BYTE keyID[ PGP_KEYID_SIZE ];
	BYTE iAndSHeader[ 64 ];
	BYTE buffer[ 8 ], *bufPtr = buffer;
	time_t theTime = time( NULL );
	static const char *nameString = "issuerAndSerialNumber";
	int length, iAndSHeaderLength = 0, status;

	/* Get the signature information */
	status = krnlSendMessage( iHashContext, RESOURCE_IMESSAGE_GETATTRIBUTE, 
							  &hashAlgo, CRYPT_CTXINFO_ALGO );
	if( cryptStatusOK( status ) )
		status = krnlSendMessage( iSignContext,
								  RESOURCE_IMESSAGE_GETATTRIBUTE, &signAlgo, 
								  CRYPT_CTXINFO_ALGO );
	if( cryptStatusOK( status ) )
		{
		setResourceData( &msgData, keyID, PGP_KEYID_SIZE );
		status = krnlSendMessage( iSignContext, 
								  RESOURCE_IMESSAGE_GETATTRIBUTE_S, &msgData, 
								  CRYPT_IATTRIBUTE_OPENPGP_KEYID );
		}
	if( cryptStatusError( status ) )
		return( status );

	/* Write the issuerAndSerialNumber packet header if necessary:
		byte[4]		flags = 0
		byte[2]		typeLength
		byte[2]		valueLength
		byte[]		type
		byte[]		value
	
	   Since this is a variable-length packet we need to pre-encode it 
	   before we can write the main packet data */
	if( iAndSlength )
		{
		STREAM headerStream;

		sMemOpen( &headerStream, iAndSHeader, 64 );
		writePacketHeader( &headerStream, 0, 1 + 4 + 2 + 2 + \
						   strlen( nameString ) + iAndSlength );
		sputc( &headerStream, PGP_SUBPACKET_TYPEANDVALUE );
		swrite( &headerStream, "\x00\x00\x00\x00", 4 );
		sputc( &headerStream, 0 );
		sputc( &headerStream, strlen( nameString ) );
		sputc( &headerStream, ( iAndSlength >> 8 ) & 0xFF );
		sputc( &headerStream, iAndSlength & 0xFF );
		swrite( &headerStream, nameString, strlen( nameString ) );
		iAndSHeaderLength = ( int ) stell( &headerStream );
		assert( sStatusOK( &headerStream ) );
		sMemDisconnect( &headerStream );
		}

	/* Write the general header information */
	sMemOpen( &stream, dataBuffer, dataBufSize );
	sputc( &stream, 4 );		/* Version = 4 (OpenPGP) */
	sputc( &stream, 0 );		/* Binary document sig. */
	sputc( &stream, ( signAlgo == CRYPT_ALGO_RSA ) ? \
		   PGP_ALGO_RSA : PGP_ALGO_DSA );
	writeHashAlgorithmID( &stream, hashAlgo );

	/* Write the authenticated attributes.  The signer ID is optional, but
	   if we omit it GPG fails the signature check so we always include it */
	length = 1 + 1 + 4 + 1 + 1 + PGP_KEYID_SIZE;
	if( iAndSlength )
		length += iAndSHeaderLength + iAndSlength;
	sputc( &stream, ( length >> 8 ) & 0xFF );
	sputc( &stream, length & 0xFF );
	sputc( &stream, 1 + 4 );
	sputc( &stream, PGP_SUBPACKET_TIME );
	mputBLong( bufPtr, theTime );
	swrite( &stream, buffer, 4 );
	sputc( &stream, 1 + PGP_KEYID_SIZE );
	sputc( &stream, PGP_SUBPACKET_KEYID );
	swrite( &stream, keyID, PGP_KEYID_SIZE );
	if( iAndSlength )
		{
		swrite( &stream, iAndSHeader, iAndSHeaderLength );
		setResourceData( &msgData, sMemBufPtr( &stream ), 
						 sMemDataLeft( &stream ) - 2 );
		status = krnlSendMessage( iSignContext, 
								  RESOURCE_IMESSAGE_GETATTRIBUTE_S, &msgData, 
								  CRYPT_IATTRIBUTE_ISSUERANDSERIALNUMBER );
		if( cryptStatusError( status ) )
			{
			sMemClose( &stream );
			return( status );
			}
		sSkip( &stream, msgData.length );
		}

	/* Write the unauthenticated attributes */
	sputc( &stream, 0 );
	status = sputc( &stream, 0 );

	/* Clean up */
	length = ( int ) stell( &stream );
	sMemDisconnect( &stream );
	return( cryptStatusError( status ) ? status : length );
	}

/****************************************************************************
*																			*
*					Envelope Pre/Post-processing Functions					*
*																			*
****************************************************************************/

/* The following functions take care of pre/post-processing of envelope data
   during the enveloping process */

static int preEnvelopeEncrypt( ENVELOPE_INFO *envelopeInfoPtr )
	{
	CRYPT_DEVICE iCryptDevice = CRYPT_ERROR;
	ACTION_LIST *actionListPtr;
	int status;

	/* Create the session key if necessary */
	if( envelopeInfoPtr->actionList == NULL )
		{
		MESSAGE_CREATEOBJECT_INFO createInfo;
		int status;

		/* Create a default encryption action and add it to the action
		   list */
		setMessageCreateObjectInfo( &createInfo, 
									envelopeInfoPtr->defaultAlgo );
		status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
								  RESOURCE_IMESSAGE_DEV_CREATEOBJECT,
								  &createInfo, OBJECT_TYPE_CONTEXT );
		if( cryptStatusOK( status ) )
			{
			static const CRYPT_MODE mode = CRYPT_MODE_CFB;

			krnlSendMessage( createInfo.cryptHandle, 
							 RESOURCE_IMESSAGE_SETATTRIBUTE, 
							 ( void * ) &mode, CRYPT_CTXINFO_MODE );
			status = krnlSendMessage( createInfo.cryptHandle, 
									  RESOURCE_IMESSAGE_CTX_GENKEY, 
									  NULL, FALSE );
			if( cryptStatusOK( status ) && \
				addAction( &envelopeInfoPtr->actionList, ACTION_CRYPT, 
						   createInfo.cryptHandle ) == NULL )
				status = CRYPT_ERROR_MEMORY;
			if( cryptStatusError( status ) )
				krnlSendNotifier( createInfo.cryptHandle, 
								  RESOURCE_IMESSAGE_DECREFCOUNT );
			}
		if( cryptStatusError( status ) )
			return( status );
		}
	else
		{
		/* If the session key context is tied to a device, get its handle so 
		   we can check that all key exchange objects are also in the same 
		   device */
		status = krnlSendMessage( envelopeInfoPtr->actionList->iCryptHandle, 
								  RESOURCE_MESSAGE_GETDEPENDENT, 
								  &iCryptDevice, OBJECT_TYPE_DEVICE );
		if( cryptStatusError( status ) )
			iCryptDevice = CRYPT_ERROR;
		}

	/* Notify the kernel that the session key context is attached to the 
	   envelope.  This is an internal object used only by the envelope so we
	   tell the kernel not to increment its reference count when it attaches
	   it */
	krnlSendMessage( envelopeInfoPtr->objectHandle, 
					 RESOURCE_IMESSAGE_SETDEPENDENT, 
					 &envelopeInfoPtr->actionList->iCryptHandle, 
					 SETDEP_OPTION_NOINCREF );

	/* Now walk down the list of key exchange actions connecting each one to 
	   the session key action */
	for( actionListPtr = findAction( envelopeInfoPtr->preActionList,
									 ACTION_KEYEXCHANGE_PKC );
		 actionListPtr != NULL && \
			actionListPtr->action == ACTION_KEYEXCHANGE_PKC;
		actionListPtr = actionListPtr->next )
		{
		/* If the session key context is tied to a device, make sure the key 
		   exchange object is in the same device */
		if( iCryptDevice != CRYPT_ERROR )
			{
			CRYPT_DEVICE iKeyexDevice;

			status = krnlSendMessage( actionListPtr->iCryptHandle, 
									  RESOURCE_MESSAGE_GETDEPENDENT, 
									  &iKeyexDevice, OBJECT_TYPE_DEVICE );
			if( cryptStatusError( status ) || iCryptDevice != iKeyexDevice )
				return( CRYPT_ERROR_INVALID );
			}

		/* Remember that we now have a controlling action and connect the
		   controller to the subject */
		envelopeInfoPtr->actionList->needsController = FALSE;
		actionListPtr->associatedAction = envelopeInfoPtr->actionList;
		}

	return( CRYPT_OK );	
	}

/****************************************************************************
*																			*
*							Emit Envelope Preamble/Postamble				*
*																			*
****************************************************************************/

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

static int emitPreamble( ENVELOPE_INFO *envelopeInfoPtr )
	{
	PGP_ENV_STATE state = envelopeInfoPtr->pgpEnvState;
	int status = CRYPT_OK;

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

	/* If we've finished processing the header information, don't do
	   anything */
	if( state == PGP_ENVSTATE_DONE )
		return( CRYPT_OK );

	/* If we haven't started doing anything yet, perform various final
	   initialisations */
	if( state == PGP_ENVSTATE_NONE )
		{
		/* If there's no nested content type set, default to plain data */
		if( envelopeInfoPtr->contentType == CRYPT_CONTENT_NONE )
			envelopeInfoPtr->contentType = CRYPT_CONTENT_DATA;

		/* Perform any remaining initialisation.  Since PGP derives the 
		   session key directly from the user password, we only perform this
		   initialisation if there are PKC key exchange actions present */
		if( envelopeInfoPtr->usage == ACTION_CRYPT && \
			findAction( envelopeInfoPtr->preActionList,
						ACTION_KEYEXCHANGE_PKC ) != NULL )
			status = preEnvelopeEncrypt( envelopeInfoPtr );
		if( cryptStatusError( status ) )
			return( status );

		/* Delete any orphaned actions (for example automatically added
		   hash actions which were overridden with user-supplied alternate
		   actions) */
		deleteUnusedActions( envelopeInfoPtr );

		/* We're ready to go, connect a write stream to the auxBuffer and
		   prepare to emit the outer header */
		sMemOpen( &envelopeInfoPtr->auxStream, envelopeInfoPtr->auxBuffer,
				  envelopeInfoPtr->auxBufSize );
		state = PGP_ENVSTATE_HEADER;
		assert( actionsOK( envelopeInfoPtr ) );
		}

	/* Emit the outer header */
	if( state == PGP_ENVSTATE_HEADER )
		{
		STREAM stream;

		/* If we're encrypting, set up the encryption-related information.
		   Since PGP doesn't perform a key exchange of a session key when 
		   conventionally-encrypting data, the encryption information could 
		   be coming from either an encryption action (derived from a 
		   password) or a conventional key exchange action which results in 
		   the direct creation of a session encryption key */
		if( envelopeInfoPtr->usage == ACTION_CRYPT )
			{
			status = initEnvelopeEncryption( envelopeInfoPtr,
								envelopeInfoPtr->actionList->iCryptHandle, 
								CRYPT_UNUSED, CRYPT_UNUSED, NULL, 0, FALSE );
			if( cryptStatusError( status ) )
				return( status );

			/* Prepare to start emitting the key exchange (PKC-encrypted) or 
			   session key (conventionally encrypted) actions */
			envelopeInfoPtr->lastAction = \
								findAction( envelopeInfoPtr->preActionList,
											ACTION_KEYEXCHANGE_PKC );
			if( envelopeInfoPtr->lastAction == NULL )
				envelopeInfoPtr->lastAction = envelopeInfoPtr->actionList;
			state = PGP_ENVSTATE_KEYINFO;
			}
		else
			{
			/* If we're not encrypting data (ie there's only a single packet
			   present) write the appropriate PGP header based on the 
			   envelope usage.  Since this is the first data written, we can 
			   write it directly to the envelope buffer without having to go 
			   via the auxBuffer */
			sMemOpen( &stream, envelopeInfoPtr->buffer, envelopeInfoPtr->bufSize );
			switch( envelopeInfoPtr->usage )
				{
				case ACTION_SIGN:
					status = writeSignatureInfoPacket( &stream, 
								envelopeInfoPtr->postActionList->iCryptHandle,
								envelopeInfoPtr->actionList->iCryptHandle );
					if( cryptStatusError( status ) )
						break;

					/* Since we can only sign literal data, we need to 
					   explicitly write an inner data header */
					assert( envelopeInfoPtr->contentType == CRYPT_CONTENT_DATA );
					state = PGP_ENVSTATE_DATA;
					break;

				case ACTION_NONE:
					/* Write the header followed by an indicator that we're 
					   using opaque content, a zero-length filename, and no 
					   date */
					writePacketHeader( &stream, PGP_PACKET_DATA, 
						envelopeInfoPtr->payloadSize + PGP_DATA_HEADER_SIZE );
					swrite( &stream, "b\x00\x00\x00\x00\x00", 
							PGP_DATA_HEADER_SIZE );
					break;

				case ACTION_COMPRESS:
					writePacketHeader( &stream, PGP_PACKET_COPR, 
									   envelopeInfoPtr->payloadSize );
					sputc( &stream, PGP_ALGO_ZLIB );

⌨️ 快捷键说明

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