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

📄 pgp_denv.c

📁 cryptlib是功能强大的安全工具集。允许开发人员快速在自己的软件中集成加密和认证服务。
💻 C
📖 第 1 页 / 共 3 页
字号:

			/* If we're down to stripping raw header data, clean up and
			   exit */
			if( !envelopeInfoPtr->oobEventCount )
				{
				/* We've successfully stripped all the out-of-band data.  If
				   it's compressed data (which doesn't have a 1:1
				   correspondence between input and output and that has an
				   unknown-length encoding so there's no length information
				   to adjust), exit */
				envelopeInfoPtr->oobDataLeft = 0;
				if( envelopeInfoPtr->usage == ACTION_COMPRESS )
					{
					state = PGP_DEENVSTATE_DONE;
					continue;
					}

				/* Adjust the current data count by what we've removed.  If
				   we've reached the end of the data (i.e. the entire current
				   segment is contained within the data present in the
				   buffer), remember that what's left still needs to be
				   processed (e.g. hashed in the case of signed data) on the
				   way out */
				envelopeInfoPtr->segmentSize -= length;
				assert( envelopeInfoPtr->segmentSize >= 0 );
				if( envelopeInfoPtr->segmentSize <= envelopeInfoPtr->bufPos )
					{
					envelopeInfoPtr->dataLeft = envelopeInfoPtr->segmentSize;
					envelopeInfoPtr->segmentSize = 0;
					}

				/* 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->dataFlags |= ENVDATA_HASHACTIONSACTIVE;

				/* We're done */
				state = PGP_DEENVSTATE_DONE;
				continue;
				}

			/* Read the header information and see what we've got */
			sMemConnect( &headerStream, buffer, length );
			packetType = getPacketInfo( &headerStream, envelopeInfoPtr,
										&packetLength );
			if( cryptStatusError( packetType ) )
				{
				sMemClose( &headerStream );
				status = packetType;
				break;
				}

			/* Remember the total data packet size unless it's compressed
			   data, which doesn't have a 1:1 correspondence between input
			   and output */
			if( envelopeInfoPtr->usage != ACTION_COMPRESS )
				{
				/* If it's a definite-length packet, use the overall packet
				   size.  This also skips any MDC packets that may be
				   attached to the end of the plaintext */
				if( packetLength != CRYPT_UNUSED )
					envelopeInfoPtr->payloadSize = \
									envelopeInfoPtr->segmentSize = \
									stell( &headerStream ) + packetLength;
				else
					/* It's an indefinite-length packet, if we got length
					   information earlier from the outer packet use that */
					if( envelopeInfoPtr->payloadSize != CRYPT_UNUSED )
						envelopeInfoPtr->segmentSize = \
									envelopeInfoPtr->payloadSize;
					else
						{
						/* Both the outer and inner packets are indefinite-
						   length, we can't process the data because we don't
						   know its length */
						sMemClose( &headerStream );
						status = CRYPT_ERROR_BADDATA;
						break;
						}
				}

			/* If it's a literal data packet, parse it so that we can strip 
			   it from the data that we return to the caller */
			if( packetType == PGP_PACKET_DATA )
				{
				int extraLen;

				sgetc( &headerStream );		/* Skip content type */
				extraLen = sgetc( &headerStream );
				envelopeInfoPtr->oobDataLeft = stell( &headerStream ) + \
											   extraLen + 4;
				sMemDisconnect( &headerStream );

				/* We've processed enough of the header to know what to do
				   next, move on to the next stage where we just consume all
				   the input */
				envelopeInfoPtr->oobEventCount--;
				}
			else
				{
				static const struct {
					const int pgpType; const int cryptlibType;
					} typeMapTbl[] = {
					{ PGP_PACKET_COPR, CRYPT_CONTENT_COMPRESSEDDATA },
					{ PGP_PACKET_ENCR, CRYPT_CONTENT_ENCRYPTEDDATA },
					{ PGP_PACKET_ENCR_MDC, CRYPT_CONTENT_ENCRYPTEDDATA },
					{ PGP_PACKET_SKE, CRYPT_CONTENT_ENCRYPTEDDATA },
					{ PGP_PACKET_PKE, CRYPT_CONTENT_ENVELOPEDDATA },
					{ PGP_PACKET_SIGNATURE, CRYPT_CONTENT_SIGNEDDATA },
					{ PGP_PACKET_SIGNATURE_ONEPASS, CRYPT_CONTENT_SIGNEDDATA },
					{ CRYPT_ERROR, CRYPT_ERROR },
					};
				int i;

				sMemDisconnect( &headerStream );

				/* If it's a known packet type, indicate it as the nested
				   content type */
				for( i = 0; typeMapTbl[ i ].pgpType != CRYPT_ERROR; i++ )
					if( typeMapTbl[ i ].pgpType == packetType )
						{
						envelopeInfoPtr->contentType = \
											typeMapTbl[ i ].cryptlibType;
						break;
						}
				if( typeMapTbl[ i ].pgpType == CRYPT_ERROR )
					{
					status = CRYPT_ERROR_BADDATA;
					break;
					}

				/* If it's not compressed data (which doesn't have a 1:1
				   correspondence between input and output), we've reached
				   the end of the data (i.e. the entire current segment is
				   contained within the data present in the buffer), remember
				   that what's left still needs to be processed (e.g. hashed
				   in the case of signed data) on the way out */
				if( envelopeInfoPtr->usage != ACTION_COMPRESS && \
					envelopeInfoPtr->segmentSize <= envelopeInfoPtr->bufPos )
					{
					envelopeInfoPtr->dataLeft = envelopeInfoPtr->segmentSize;
					envelopeInfoPtr->segmentSize = 0;
					}

				/* Don't try and process the content any further */
				envelopeInfoPtr->oobEventCount = \
								envelopeInfoPtr->oobDataLeft = 0;
				state = PGP_DEENVSTATE_DONE;
				}
			}
		}
	if( iterationCount >= 256 )
		return( CRYPT_ERROR_FAILED );
	envelopeInfoPtr->pgpDeenvState = state;

	assert( streamPos >= 0 && envelopeInfoPtr->bufPos - streamPos >= 0 );

	/* Consume the input we've processed so far by moving everything past the
	   current position down to the start of the envelope buffer */
	length = envelopeInfoPtr->bufPos - streamPos;
	if( length > 0 && streamPos > 0 )
		memmove( envelopeInfoPtr->buffer, envelopeInfoPtr->buffer + streamPos,
				length );
	envelopeInfoPtr->bufPos = length;

	/* If all went OK but we're still not out of the header information,
	   return an underflow error */
	if( cryptStatusOK( status ) && state != PGP_DEENVSTATE_DONE )
		status = CRYPT_ERROR_UNDERFLOW;

	/* Clean up */
	sMemDisconnect( &stream );
	return( status );
	}

static int processPostamble( ENVELOPE_INFO *envelopeInfoPtr )
	{
	CONTENT_LIST *contentListPtr;
	const BOOLEAN hasMDC = \
			( envelopeInfoPtr->usage == ACTION_CRYPT && \
			  ( envelopeInfoPtr->dataFlags & ENVDATA_HASHACTIONSACTIVE ) ) ? \
			TRUE : FALSE;
	int status = CRYPT_OK;

	/* If that's all there is, return */
	if( envelopeInfoPtr->usage != ACTION_SIGN && !hasMDC )
		return( CRYPT_OK );

	/* If there's an MDC packet present, complete the hashing and make sure
	   the integrity check matches */
	if( hasMDC )
		{
		/* Make sure that there's enough data left in the stream to obtain 
		   the MDC info, and get the MDC packet */
		if( envelopeInfoPtr->bufPos - envelopeInfoPtr->dataLeft < \
			PGP_MDC_PACKET_SIZE )
			return( CRYPT_ERROR_UNDERFLOW );

		/* Processing beyond this point gets rather complex because we have
		   to defer reading the MDC packet until all the remaining data has
		   been popped, while processing reaches this point when data is 
		   pushed.  Conventionally signed/hashed data hashes the plaintext, 
		   so once we reach this point we can wrap up the hashing ready for 
		   the (user-initiated) sig check.  The MDC packet however is still
		   encrypted at this point, along with some or all of the data to be 
		   hashed, which means that we can't do anything yet.  In order to 
		   handle this special-case situation, we'd have to add extra 
		   capabilities to the data-popping code to tell it that after a 
		   certain amount of data has been popped, what's still left is MDC
		   data.  This severely screws up the layering, since the 
		   functionality is neither at the cryptenv.c level nor at the 
		   env_dec.c level, and represents an approach that was abandoned in
		   cryptlib 2.1 when it proved impossible to get it working reliably
		   under all circumstances (it's provably impossible to do with ASN.1
		   variable-length length encoding where changing data by one byte
		   can result in a variable change of length for inner lengths, 
		   making it impossible to encode some data lengths to the fixed size 
		   required by a CBC-mode cipher).  This is why cryptlib uses 
		   separate passes for each processing layer rather than trying to 
		   combine encryption and signing into a single pass.

		   Because of this, handling of MDC packets is only done if all the
		   data in the envelope has been popped (but see the note below), 
		   fully general handling won't be added unless there is sufficient 
		   user demand to justify messing up the architectural layering of 
		   the enveloping code.  Note that this situation can never occur 
		   (since we're being called when data is pushed, so bufPos will 
		   never be zero), the following code is present only as a 
		   representative example */
		if( envelopeInfoPtr->dataLeft == PGP_MDC_PACKET_SIZE )
			{
			BYTE buffer[ PGP_MDC_PACKET_SIZE ];

			envelopeInfoPtr->copyFromEnvelopeFunction( envelopeInfoPtr, 
											buffer, PGP_MDC_PACKET_SIZE );
			if( buffer[ 0 ] != 0xD0 || buffer[ 1 ] != 0x14 )
				return( CRYPT_ERROR_BADDATA );

			/* Hash the trailer bytes (the start of the MDC packet) and wrap 
			   up the hashing */
			envelopeInfoPtr->processExtraData( envelopeInfoPtr, buffer + 2,
											   PGP_MDC_PACKET_SIZE - 2 );
			status = envelopeInfoPtr->processExtraData( envelopeInfoPtr, 
														"", 0 );
			if( cryptStatusError( status ) )
				return( status );
			}
		return( CRYPT_OK );
		}

	/* Find the signature information in the content list.  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 */
	for( contentListPtr = envelopeInfoPtr->contentList;
		 contentListPtr != NULL && \
			contentListPtr->envInfo != CRYPT_ENVINFO_SIGNATURE;
		 contentListPtr = contentListPtr->next );

	/* PGP 2.x prepended (!!) signatures to the signed data, OpenPGP fixed 
	   this by splitting the signature into a header with signature info and 
	   a trailer with the actual signature.  If we're processing a PGP 2.x
	   signature, we'll already have the signature data present, so we only
	   check for signature data if it's not already available */
	if( contentListPtr->object == NULL )
		{
		STREAM stream;
		long packetLength;
		int packetType;

		/* Make sure that there's enough data left in the stream to do 
		   something with.  This isn't strictly necessary for the following 
		   code to work but is required to avoid triggering the zero-length 
		   stream check */
		if( envelopeInfoPtr->bufPos - envelopeInfoPtr->dataLeft < \
			PGP_MAX_HEADER_SIZE )
			return( CRYPT_ERROR_UNDERFLOW );

		/* Read the signature packet at the end of the payload */
		sMemConnect( &stream, envelopeInfoPtr->buffer + envelopeInfoPtr->dataLeft,
					 envelopeInfoPtr->bufPos - envelopeInfoPtr->dataLeft );
		packetType = getPacketInfo( &stream, envelopeInfoPtr, &packetLength );
		if( !cryptStatusError( packetType ) && \
			packetType != PGP_PACKET_SIGNATURE )
			packetType = CRYPT_ERROR_BADDATA;
		if( cryptStatusError( packetType ) )
			{
			sMemDisconnect( &stream );
			return( packetType );
			}
		sseek( &stream, 0 );
		status = addContentListItem( &stream, envelopeInfoPtr, TRUE );
		sMemDisconnect( &stream );
		if( cryptStatusError( status ) )
			return( status );
		}

	/* When we reach this point there may still be unhashed data left in the 
	   buffer (it won't have been hashed yet because the hashing is performed 
	   when the data is copied out, after unwrapping and whatnot) so we hash 
	   it before we exit.  Since we don't wrap up the hashing as we do with
	   any other format (PGP hashes in all sorts of odds and ends after 
	   hashing the message body), we have to manually turn off hashing here */
	if( envelopeInfoPtr->dataLeft > 0 )
		status = envelopeInfoPtr->processExtraData( envelopeInfoPtr,
						envelopeInfoPtr->buffer, envelopeInfoPtr->dataLeft );
	envelopeInfoPtr->dataFlags &= ~ENVDATA_HASHACTIONSACTIVE;
	return( status );
	}

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

void initPGPDeenveloping( ENVELOPE_INFO *envelopeInfoPtr )
	{
	/* Set the access method pointers */
	envelopeInfoPtr->processPreambleFunction = processPreamble;
	envelopeInfoPtr->processPostambleFunction = processPostamble;

	/* Set up the processing state information */
	envelopeInfoPtr->pgpDeenvState = PGP_DEENVSTATE_NONE;
	}
#endif /* USE_PGP */

⌨️ 快捷键说明

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