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

📄 env_dec.c

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

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

/*			 .... NO! ...				   ... MNO! ...
		   ..... MNO!! ...................... MNNOO! ...
		 ..... MMNO! ......................... MNNOO!! .
		.... MNOONNOO!	 MMMMMMMMMMPPPOII!	 MNNO!!!! .
		 ... !O! NNO! MMMMMMMMMMMMMPPPOOOII!! NO! ....
			...... ! MMMMMMMMMMMMMPPPPOOOOIII! ! ...
		   ........ MMMMMMMMMMMMPPPPPOOOOOOII!! .....
		   ........ MMMMMOOOOOOPPPPPPPPOOOOMII! ...
			....... MMMMM..	   OPPMMP	 .,OMI! ....
			 ...... MMMM::	 o.,OPMP,.o	  ::I!! ...
				 .... NNM:::.,,OOPM!P,.::::!! ....
				  .. MMNNNNNOOOOPMO!!IIPPO!!O! .....
				 ... MMMMMNNNNOO:!!:!!IPPPPOO! ....
				   .. MMMMMNNOOMMNNIIIPPPOO!! ......
				  ...... MMMONNMMNNNIIIOO!..........
			   ....... MN MOMMMNNNIIIIIO! OO ..........
			......... MNO! IiiiiiiiiiiiI OOOO ...........
		  ...... NNN.MNO! . O!!!!!!!!!O . OONO NO! ........
		   .... MNNNNNO! ...OOOOOOOOOOO .  MMNNON!........
		   ...... MNNNNO! .. PPPPPPPPP .. MMNON!........
			  ...... OO! ................. ON! .......
				 ................................

   Be very careful when modifying this code, the data manipulation it
   performs is somewhat tricky */

/****************************************************************************
*																			*
*							Header Processing Routines						*
*																			*
****************************************************************************/

/* Handle the EOC and PKCS #5 block padding if necessary:

			   pad
	+-------+-------+-------+
	|		|		|		|
	+-------+-------+-------+
			^		^
			|		|
		 padPtr	  bPos */

static int processEOC( ENVELOPE_INFO *envelopeInfoPtr )
	{
	assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
	assert( envelopeInfoPtr->bufPos >= 0 && \
			envelopeInfoPtr->bufPos <= envelopeInfoPtr->bufSize );

	/* If we're using a block cipher, undo the PKCS #5 padding which is
	   present at the end of the block */
	if( envelopeInfoPtr->blockSize > 1 )
		{
		const BYTE *padPtr = envelopeInfoPtr->buffer + \
							 envelopeInfoPtr->bufPos - 1;
		const int padSize = *padPtr;
		int i;

		/* Make sure that the padding size is valid */
		if( padSize < 1 || padSize > envelopeInfoPtr->blockSize || \
			padSize > envelopeInfoPtr->bufPos )
			return( CRYPT_ERROR_BADDATA );

		/* Check the padding data */
		envelopeInfoPtr->bufPos -= padSize;
		padPtr -= padSize - 1;
		for( i = 0; i < padSize - 1; i++ )
			if( padPtr[ i ] != padSize )
				return( CRYPT_ERROR_BADDATA );
		assert( envelopeInfoPtr->bufPos >= 0 );
		}

	/* Remember that we've reached the end of the payload and where the
	   payload ends ("This was the end of the river all right") */
	envelopeInfoPtr->dataFlags |= ENVDATA_ENDOFCONTENTS;
	envelopeInfoPtr->dataLeft = envelopeInfoPtr->bufPos;

	return( CRYPT_OK );
	}

/* Decode the header for the next segment in the buffer.  Returns the number
   of bytes consumed, or an underflow error if more data is required */

static int getNextSegment( ENVELOPE_INFO *envelopeInfoPtr, const BYTE *buffer,
						   const int length )
	{
	SEGHDR_STATE state = envelopeInfoPtr->segHdrState;
	long segmentLength = envelopeInfoPtr->segHdrSegLength;
	int count = envelopeInfoPtr->segHdrCount, bufPos;

	assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
	assert( length > 0 );
	assert( isReadPtr( buffer, length ) );

	/* If we've already processed the entire payload, don't do anything.  
	   This can happen when we're using the definite encoding form, since
	   the EOC flag is set elsewhere as soon as the entire payload has been
	   copied to the buffer */
	if( envelopeInfoPtr->dataFlags & ENVDATA_ENDOFCONTENTS )
		return( OK_SPECIAL );

	/* If we're using the definite encoding form, there's a single segment
	   equal in length to the entire payload */
	if( envelopeInfoPtr->payloadSize != CRYPT_UNUSED )
		{
		envelopeInfoPtr->segmentSize = envelopeInfoPtr->payloadSize;
		return( OK_SPECIAL );
		}

	/* If we're using the indefinite form but it's an envelope type that 
	   doesn't segment data, the length is implicitly defined as "until we 
	   run out of input" */
	if( envelopeInfoPtr->dataFlags & ENVDATA_NOSEGMENT )
		{
		envelopeInfoPtr->segmentSize = CRYPT_UNUSED;
		return( OK_SPECIAL );
		}

	/* If we're starting a new sub-segment read and there's enough data 
	   present that we can try and use the ASN.1 read routines, try and get
	   the sub-segment info using the ASN.1 routines */
	if( state == SEGHDRSTATE_NONE && length >= 2 )
		{
		STREAM stream;
		int bytesRead, status;

		assert( envelopeInfoPtr->segHdrSegLength == 0L && \
				envelopeInfoPtr->segHdrCount == 0 );

		/* Get the sub-segment info */
		sMemConnect( &stream, buffer, length );
		status = checkEOC( &stream );
		if( status == FALSE )
			{
			/* It's a new sub-segment, get its length */
			status = readLongGenericHole( &stream, &segmentLength, 
										  BER_OCTETSTRING );
			if( cryptStatusOK( status ) && segmentLength == CRYPT_UNUSED )
				/* If it's an (invalid) indefinite-length encoding, we can't 
				   do anything with it */
				status = CRYPT_ERROR_BADDATA;
			}
		else
			/* If we've seen the EOC, wrap up the processing */
			if( status == TRUE )
				{
				status = processEOC( envelopeInfoPtr );
				segmentLength = 0;
				}
		bytesRead = stell( &stream );
		sMemDisconnect( &stream );

		/* If the read was successful (i.e. we didn't run out of input), 
		   return the info to the caller */
		if( status != CRYPT_ERROR_UNDERFLOW )
			{
			if( cryptStatusError( status ) )
				return( status );
			envelopeInfoPtr->segmentSize = segmentLength;
			return( bytesRead );
			}
		}

	/* We couldn't read the current sub-segment info using the ASN.1 
	   routines due to lack of input data, fall back to the FSM-based read, 
	   which is interruptible.  This read processes each data byte until 
	   we've either parsed the entire header or run out of input. It is
	   however not quite as tolerant as the ASN.1 code in terms of accepting
	   odd non-DER encodings */
	for( bufPos = 0; bufPos < length && state != SEGHDRSTATE_DONE; bufPos++ )
		{
		SEGHDR_STATE oldState = state;

		switch( state )
			{
			case SEGHDRSTATE_NONE:
				/* Check for OCTET STRING or start or end-of-contents
				   octets */
				segmentLength = 0;
				if( buffer[ bufPos ] == BER_OCTETSTRING )
					state = SEGHDRSTATE_LEN_OF_LEN;
				else
					if( buffer[ bufPos ] == BER_EOC )
						state = SEGHDRSTATE_END;
					else
						return( CRYPT_ERROR_BADDATA );
				break;

			case SEGHDRSTATE_LEN_OF_LEN:
				/* We've seen the OCTET STRING header, check for a short
				   length or length-of-length value */
				count = buffer[ bufPos ];
				if( !( count & 0x80 ) )
					{
					/* It's a short/indefinite length */
					segmentLength = count;
					state = SEGHDRSTATE_DONE;
					}
				else
					{
					/* It's a long segment, get the length-of-length
					   information */
					count &= 0x7F;
					if( count < 1 || count > 4 )
						/* "Nobody will ever need more than 640K" */
						return( CRYPT_ERROR_BADDATA );
					state = SEGHDRSTATE_LEN;
					}
				break;

			case SEGHDRSTATE_LEN:
				/* We're processing a long-format length field, get the next
				   part of the length */
				segmentLength = ( segmentLength << 8 ) | buffer[ bufPos ];
				count--;

				/* If we've got all the data, make sure that the segment 
				   length is valid and return to the initial state */
				if( count <= 0 )
					{
					if( segmentLength < 0x80 )
						/* Probably a bit pedantic, but it helps catch 
						   garbled data */
						return( CRYPT_ERROR_BADDATA );
					state = SEGHDRSTATE_DONE;
					}
				break;

			case SEGHDRSTATE_END:
				{
				int status;

				/* We've seen the first EOC octet, check for the second 
				   one */
				if( buffer[ bufPos ] )
					return( CRYPT_ERROR_BADDATA );

				/* Process the EOC octets */
				status = processEOC( envelopeInfoPtr );
				if( cryptStatusError( status ) )
					return( status );
				state = SEGHDRSTATE_DONE;
				break;
				}

			default:
				assert( NOTREACHED );
			}

		/* If the state hasn't changed when it should have, there's a
		   problem */
		if( state == oldState && state != SEGHDRSTATE_LEN )
			return( CRYPT_ERROR_BADDATA );
		}

	/* Make sure that the length we got is valid.  These checks just 
	   duplicate the checks normally performed by the ASN.1-level code */
	if( length < 0 )
		return( CRYPT_ERROR_BADDATA );
	if( ( length & 0x80000000UL ) || length > MAX_INTLENGTH )
		return( CRYPT_ERROR_OVERFLOW );

	/* If we got the final length, update the appropriate segment length
	   value */
	if( state == SEGHDRSTATE_DONE )
		{
		envelopeInfoPtr->segmentSize = segmentLength;
		envelopeInfoPtr->segHdrSegLength = 0L;
		envelopeInfoPtr->segHdrCount = 0;
		envelopeInfoPtr->segHdrState = SEGHDRSTATE_NONE;
		}
	else
		{
		/* Copy the local state information back into the envelope
		   structure */
		envelopeInfoPtr->segHdrSegLength = segmentLength;
		envelopeInfoPtr->segHdrCount = count;
		envelopeInfoPtr->segHdrState = state;
		}

	return( bufPos );
	}

/****************************************************************************
*																			*
*								Copy to Envelope							*
*																			*
****************************************************************************/

/* Copy possibly encrypted data into the envelope with special handling for
   block encryption modes.  Returns the number of bytes copied */

static int copyData( ENVELOPE_INFO *envelopeInfoPtr, const BYTE *buffer,
					 const int length )
	{
	BYTE *bufPtr = envelopeInfoPtr->buffer + envelopeInfoPtr->bufPos;
	int bytesToCopy, status;

	assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
	assert( length > 0 );
	assert( isReadPtr( buffer, length ) );
	assert( envelopeInfoPtr->bufPos >= 0 && \

⌨️ 快捷键说明

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