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

📄 encode.c

📁 cryptlib安全工具包
💻 C
📖 第 1 页 / 共 3 页
字号:
/****************************************************************************
*																			*
*					  cryptlib Datagram Encoding Routines					*
*						Copyright Peter Gutmann 1996-2008					*
*																			*
****************************************************************************/

#if defined( INC_ALL )
  #include "envelope.h"
  #include "asn1.h"
#else
  #include "envelope/envelope.h"
  #include "misc/asn1.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 that it
   performs is somewhat tricky */

#ifdef USE_ENVELOPES

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

/* Sanity-check the envelope state */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static BOOLEAN sanityCheck( const ENVELOPE_INFO *envelopeInfoPtr )
	{
	assert( isReadPtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );

	/* Make sure that the buffer position is within bounds */
	if( envelopeInfoPtr->buffer == NULL || \
		envelopeInfoPtr->bufPos < 0 || \
		envelopeInfoPtr->bufPos > envelopeInfoPtr->bufSize || \
		envelopeInfoPtr->bufSize < MIN_BUFFER_SIZE || \
		envelopeInfoPtr->bufSize >= MAX_INTLENGTH )
		return( FALSE );

	/* Make sure that the block buffer position is within bounds */
	if( envelopeInfoPtr->blockSize > 0 && \
		( envelopeInfoPtr->blockBufferPos < 0 || \
		  envelopeInfoPtr->blockBufferPos >= envelopeInfoPtr->blockSize || \
		  envelopeInfoPtr->blockSize > CRYPT_MAX_IVSIZE ) )
		return( FALSE );

	/* If we're drained the envelope buffer, we're done */
	if( envelopeInfoPtr->segmentStart == 0 && \
		envelopeInfoPtr->segmentDataStart == 0 && \
		envelopeInfoPtr->bufPos == 0 )
		return( TRUE );

	/* Make sure that the buffer internal bookeeping is OK.  First we apply 
	   the general one-size-fits-all checks, then we apply further 
	   situation-specific checks */
	if( envelopeInfoPtr->segmentStart < 0 || \
		envelopeInfoPtr->segmentStart > envelopeInfoPtr->segmentDataStart || \
		envelopeInfoPtr->segmentStart > MAX_INTLENGTH )
		return( FALSE );
	if( envelopeInfoPtr->segmentDataStart < 0 || \
		envelopeInfoPtr->segmentDataStart > envelopeInfoPtr->bufPos || \
		envelopeInfoPtr->segmentDataStart > MAX_INTLENGTH )
		return( FALSE );
	
	/* The sitaution-specific checks get a bit complicated because we have 
	   to distinguish between definite- and indefinite-length encodings.  
	   For the definite length segmentStart == segmentDataStart since there 
	   are no intermediate segment headers, for the indefinite length 
	   segmentStart < segmentDataStart to accomodate the intervening header.

	   In some rare cases segmentDataStart can be the same as bufPos if 
	   we're using compression and all input data was absorbed by the 
	   zStream buffer so we check for segmentDataStart > bufPos rather than 
	   segmentDataStart >= bufPos */
	if( envelopeInfoPtr->payloadSize != CRYPT_UNUSED )
		{
		/* It's a non-segmenting encoding so segmentStart must track 
		   segmentDataStart */
		if( envelopeInfoPtr->segmentStart != \
						envelopeInfoPtr->segmentDataStart )
			return( FALSE );

		return( TRUE );
		}
	if( envelopeInfoPtr->segmentStart >= envelopeInfoPtr->bufPos )
		return( FALSE );
	if( envelopeInfoPtr->dataFlags & ENVDATA_SEGMENTCOMPLETE )
		{
		/* If we're just started a new segment and there's no data left in 
		   the envelope buffer, segmentStart may be the same as 
		   segmentDataStart */
		if( envelopeInfoPtr->segmentStart == 0 && \
			envelopeInfoPtr->segmentDataStart == 0 )
			return( TRUE );
		}
	if( envelopeInfoPtr->segmentStart >= envelopeInfoPtr->segmentDataStart )
		return( FALSE );

	return( TRUE );
	}

/* Apply the hash/MAC actions in the action list to data.  This function is 
   shared with decode.c */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
int hashEnvelopeData( const ACTION_LIST *hashActionPtr,
					  IN_BUFFER( dataLength ) const void *data, 
					  IN_LENGTH const int dataLength )
	{
	int iterationCount, status;

	assert( isReadPtr( hashActionPtr, sizeof( ACTION_LIST ) ) );
	assert( dataLength == 0 || isReadPtr( data, dataLength ) );

	REQUIRES( data != NULL );
	REQUIRES( dataLength >= 0 && dataLength < MAX_INTLENGTH );

	for( iterationCount = 0;
		 hashActionPtr != NULL && \
			( hashActionPtr->action == ACTION_HASH || \
			  hashActionPtr->action == ACTION_MAC ) && \
			iterationCount < FAILSAFE_ITERATIONS_MED;
		 hashActionPtr = hashActionPtr->next, iterationCount++ )
		{
		status = krnlSendMessage( hashActionPtr->iCryptHandle,
								  IMESSAGE_CTX_HASH, ( void * ) data, 
								  dataLength );
		if( cryptStatusError( status ) )
			return( status );
		}
	ENSURES( iterationCount < FAILSAFE_ITERATIONS_MED );

	return( CRYPT_OK );
	}

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

/* Determine the length of the encoded length value and the threshold at which the
   length encoding changes for constructed indefinite-length strings.  The
   length encoding is the actual length if <= 127, or a one-byte length-of-
   length followed by the length if > 127 */

#define TAG_SIZE					1	/* Useful symbolic define */

#if INT_MAX > 32767

#define lengthOfLength( length )	( ( length < 0x80 ) ? 1 : \
									  ( length < 0x100 ) ? 2 : \
									  ( length < 0x10000 ) ? 3 : \
									  ( length < 0x1000000 ) ? 4 : 5 )

#define findThreshold( length )		( ( length < 0x80 ) ? 0x7F : \
									  ( length < 0x100 ) ? 0xFF : \
									  ( length < 0x10000 ) ? 0xFFFF : \
									  ( length < 0x1000000 ) ? 0xFFFFFF : INT_MAX )
#else

#define lengthOfLength( length )	( ( length < 0x80 ) ? 1 : \
									  ( length < 0x100 ) ? 2 : 3 )

#define findThreshold( length )		( ( length < 0x80 ) ? 127 : \
									  ( length < 0x100 ) ? 0xFF : INT_MAX )
#endif /* 32-bit ints */

/* Begin a new segment in the buffer.  The layout is:

		  bufPos
			v
			tag	len		 payload
	+-------+-+---+---------------------+-------+
	|		| |	  |						|		|
	+-------+-+---+---------------------+-------+
			^	  ^						^
			|	  |						|
		 sStart sDataStart			sDataEnd 

   If we're using a definite-length encoding then 
   segmentStart == segmentDataStart = bufPos */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int beginSegment( INOUT ENVELOPE_INFO *envelopeInfoPtr )
	{
	int segHeaderSize = 0;

	assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );

	REQUIRES( sanityCheck( envelopeInfoPtr ) );

	/* If we're using an indefinite-length encoding we have to factor in the 
	   length of the segment header.  Since we can't determine the overall
	   segment data size at this point we use a worst-case estimate in which
	   the segment fills the entire buffer */
	if( envelopeInfoPtr->payloadSize == CRYPT_UNUSED )
		{
		segHeaderSize = TAG_SIZE + \
						lengthOfLength( envelopeInfoPtr->bufSize );
		}

	/* Make sure that there's enough room in the buffer to accommodate the
	   start of a new segment.  In the worst case this is 6 bytes (OCTET
	   STRING tag + 5-byte length) + 15 bytes (blockBuffer contents for a
	   128-bit block cipher).  Although in practice we could eliminate this
	   condition, it would require tracking a lot of state information to
	   record which data had been encoded into the buffer and whether the
	   blockBuffer data had been copied into the buffer, so to keep it
	   simple we require enough room to do everything at once */
	if( envelopeInfoPtr->bufPos + segHeaderSize + \
			envelopeInfoPtr->blockBufferPos >= envelopeInfoPtr->bufSize )
		return( CRYPT_ERROR_OVERFLOW );

	/* Adjust the buffer position indicators to handle potential
	   intermediate headers */
	envelopeInfoPtr->segmentStart = envelopeInfoPtr->bufPos;
	if( envelopeInfoPtr->payloadSize == CRYPT_UNUSED )
		{
		/* Begin a new segment after the end of the current segment.  We
		   always leave enough room for the largest allowable length field
		   because we may have a short segment at the end of the buffer which
		   is moved to the start of the buffer after data is copied out,
		   turning it into a longer segment.  For this reason we rely on
		   completeSegment() to get the length right and move any data down
		   as required */
		envelopeInfoPtr->bufPos += segHeaderSize;
		}
	envelopeInfoPtr->segmentDataStart = envelopeInfoPtr->bufPos;
	ENSURES( envelopeInfoPtr->bufPos + \
			 envelopeInfoPtr->blockBufferPos <= envelopeInfoPtr->bufSize );

	/* Now copy anything left in the block buffer to the start of the new
	   segment.  We know that everything will fit because we've checked
	   earlier on that the header and blockbuffer contents will fit into
	   the remaining space */
	if( envelopeInfoPtr->blockBufferPos > 0 )
		{
		memcpy( envelopeInfoPtr->buffer + envelopeInfoPtr->bufPos,
				envelopeInfoPtr->blockBuffer, envelopeInfoPtr->blockBufferPos );
		envelopeInfoPtr->bufPos += envelopeInfoPtr->blockBufferPos;
		}
	envelopeInfoPtr->blockBufferPos = 0;

	/* We've started the new segment, mark it as incomplete */
	envelopeInfoPtr->dataFlags &= ~ENVDATA_SEGMENTCOMPLETE;

	ENSURES( sanityCheck( envelopeInfoPtr ) );
	return( CRYPT_OK );
	}

/* Complete a segment of data in the buffer.  This is incredibly complicated
   because we need to take into account the indefinite-length encoding (which
   has a variable-size length field) and the quantization to the cipher block
   size.  In particular the indefinite-length encoding means that we can
   never encode a block with a size of 130 bytes (we get tag + length + 127 =
   129, then tag + length-of-length + length + 128 = 131), and the same for
   the next boundary at 256 bytes */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int encodeSegmentHeader( INOUT ENVELOPE_INFO *envelopeInfoPtr )
	{
	STREAM stream;
	const BOOLEAN isEncrypted = \
			( envelopeInfoPtr->iCryptContext != CRYPT_ERROR ) ? TRUE : FALSE;
	const int oldHdrLen = envelopeInfoPtr->segmentDataStart - \
						  envelopeInfoPtr->segmentStart;
	BOOLEAN needsPadding = \
			( envelopeInfoPtr->dataFlags & ENVDATA_NEEDSPADDING ) ? TRUE : FALSE;
	int dataLen = envelopeInfoPtr->bufPos - envelopeInfoPtr->segmentDataStart;
	int hdrLen, remainder = 0, status;

	REQUIRES( sanityCheck( envelopeInfoPtr ) );

	/* If we're adding PKCS #5 padding try and add one block's worth of
	   pseudo-data.  This adjusted data length is then fed into the block
	   size quantisation process, after which any odd-sized remainder is
	   ignored, and the necessary padding bytes are added to account for the
	   difference between the actual and padded size */
	if( needsPadding )
		{
		/* Check whether the padding will fit onto the end of the data.  This

⌨️ 快捷键说明

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