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

📄 octetstr.c

📁 提供了很多种加密算法和CA认证及相关服务如CMP、OCSP等的开发
💻 C
📖 第 1 页 / 共 4 页
字号:
/****************************************************************************
*																			*
*					cryptlib OCTET STRING En/Decoding Routines				*
*					   Copyright Peter Gutmann 1996-2001					*
*																			*
****************************************************************************/

#include <string.h>
#if defined( INC_ALL )
  #include "asn1.h"
  #include "envelope.h"
#elif defined( INC_CHILD )
  #include "../keymgmt/asn1.h"
  #include "envelope.h"
#else
  #include "keymgmt/asn1.h"
  #include "envelope/envelope.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 */

/****************************************************************************
*																			*
*						OCTET STRING Encoding Routines						*
*																			*
****************************************************************************/

/* Determine the quantization level and length threshold for the length
   encoding of 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 */

#if INT_MAX > 32767

#define lengthOfLength( length )	( ( length < 128 ) ? 1 : \
									  ( length < 256 ) ? 2 : \
									  ( length < 65536 ) ? 3 : 4 )

#define findThreshold( length )		( ( length < 128 ) ? 127 : \
									  ( length < 256 ) ? 255 : \
									  ( length < 65536 ) ? 65535 : INT_MAX )
#else

#define lengthOfLength( length )	( ( length < 128 ) ? 1 : \
									  ( length < 256 ) ? 2 : 3 )

#define findThreshold( length )		( ( length < 128 ) ? 127 : \
									  ( length < 256 ) ? 255 : INT_MAX )
#endif /* 32-bit ints */

/* Begin a new segment in the buffer */

static int beginSegment( ENVELOPE_INFO *envelopeInfoPtr )
	{
	const int lLen = lengthOfLength( envelopeInfoPtr->bufSize );
	const int headerLen = lLen + 1;
	int offset = envelopeInfoPtr->bufPos;

	/* Make sure there's enough room in the buffer to accomodate the start of
	   a new segment.  In the worst case this is 4 bytes (outer OCTET STRING)
	   + 7 bytes (blockBuffer contents).  Although in practice we could
	   eliminate this condition, it would require tracking a lot of state
	   information which records 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->bufSize - offset < headerLen + envelopeInfoPtr->blockBufferPos )
		return( CRYPT_ERROR_OVERFLOW );

	/* If we're encoding data with a definite length, there's no real segment
	   boundary apart from the artificial ones created by encryption
	   blocking */
	if( envelopeInfoPtr->payloadSize != CRYPT_UNUSED )
		envelopeInfoPtr->segmentStart = envelopeInfoPtr->segmentDataStart = offset;
	else
		{
		/* 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 the
		   completeSegment() code to get the length right and move any data
		   down as required */
		envelopeInfoPtr->buffer[ offset ] = BER_OCTETSTRING;
		envelopeInfoPtr->bufPos += 1 + lLen;
		offset = envelopeInfoPtr->bufPos;
		envelopeInfoPtr->segmentStart = offset - lLen;
		envelopeInfoPtr->segmentDataStart = offset;
		}

	/* Now copy anything left in the block buffer to the start of the new
	   segment.  We know everything will fit because we've checked earlier on
	   that the header and blockbuffer contents will fit into the remaining
	   space */
	if( envelopeInfoPtr->blockBufferPos )
		{
		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->segmentComplete = FALSE;

	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 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 */

static BOOLEAN encodeSegmentHeader( ENVELOPE_INFO *envelopeInfoPtr,
									const BOOLEAN isEncrypted )
	{
	BYTE *bufPtr = envelopeInfoPtr->buffer;
	const int segmentDataStart = envelopeInfoPtr->segmentDataStart;
	int segmentStart = envelopeInfoPtr->segmentStart;
	int dLen = envelopeInfoPtr->bufPos - segmentDataStart;
	int lLen, oldLLen = 1 + ( segmentDataStart - segmentStart ), qTot;
	int threshold, remainder = 0;
	BOOLEAN needsPadding = envelopeInfoPtr->needsPadding;

	/* If we're adding PKCS #5 padding, try and add one blocks 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
		   check isn't completely accurate since the length encoding might
		   shrink by one or two bytes and allow a little extra data to be
		   squeezed in, however the extra data could cause the length
		   encoding to expand again, requiring a complex adjustment process.
		   To make things easier we ignore this possibility at the expense of
		   emitting one more segment than is necessary in a few very rare
		   cases */
		if( envelopeInfoPtr->segmentDataStart + dLen + \
			envelopeInfoPtr->blockSize < envelopeInfoPtr->bufSize )
			dLen += envelopeInfoPtr->blockSize;
		else
			needsPadding = FALSE;
		}

	/* Now that we've made any necessary adjustments to the data length,
	   determine the length of the length encoding (which may have grown or
	   shrunk since we initially calculated it when we began the segment) and
	   any combined data lengths based on it */
	if( envelopeInfoPtr->payloadSize != CRYPT_UNUSED )
		lLen = oldLLen = 0;	/* No header between segments */
	else
		lLen = 1 + lengthOfLength( dLen );
	qTot = lLen + dLen;

	/* Quantize and adjust the length if we're encrypting in a block mode */
	if( isEncrypted )
		{
		qTot = dLen & envelopeInfoPtr->blockSizeMask;
		threshold = findThreshold( qTot );
		if( qTot <= threshold && dLen > threshold )
			lLen--;
		remainder = dLen - qTot;
		dLen = qTot;	/* Data length has now shrunk to quantised size */
		}
	assert( lLen >= 0 );
	assert( remainder >= 0 && \
			( envelopeInfoPtr->blockSize == 0 || \
			  remainder < envelopeInfoPtr->blockSize ) );

	/* If there's not enough data present to do anything, tell the caller we
	   couldn't do anything */
	if( !qTot )
		return( FALSE );
	assert( dLen >= 0 );

	/* If the length encoding has shrunk (either due to the cipher block size
	   quantization shrinking the segment or because we've wrapped up a
	   segment at less than the original projected length), move the data
	   down.  The complete segment starts at ( segmentStart - 1 ), in the
	   worst case the shrinking can cover several bytes if we go from a > 255
	   byte segment to a <= 127 byte one */
	if( lLen < oldLLen )
		{
		int delta = oldLLen - lLen;

		memmove( bufPtr + segmentStart - 1 + lLen,
				 bufPtr + segmentDataStart,
				 envelopeInfoPtr->bufPos - segmentDataStart );
		envelopeInfoPtr->bufPos -= delta;
		envelopeInfoPtr->segmentDataStart -= delta;
		}
	assert( envelopeInfoPtr->bufPos >= 0 );
	assert( envelopeInfoPtr->segmentDataStart + dLen <= envelopeInfoPtr->bufSize );

	/* If we need to add PKCS #5 block padding, try and do so now.  Since the
	   extension of the data length to allow for padding data is performed by
	   adding one block of pseudo-data and letting the block quantisation
	   system take care of any discrepancies, we can calculate the padding
	   amount as the difference between any remainder after quantisation and
	   the block size */
	if( needsPadding )
		{
		const int padSize = envelopeInfoPtr->blockSize - remainder;
		int i;

		/* Add the block padding and set the remainder to zero, since we're
		   now at an even block boundary */
		for( i = 0; i < padSize; i++ )
			envelopeInfoPtr->buffer[ envelopeInfoPtr->bufPos + i ] = padSize;
		envelopeInfoPtr->bufPos += padSize;
		envelopeInfoPtr->needsPadding = FALSE;
		remainder = 0;
		}

	/* Move any leftover bytes into the block buffer */
	if( remainder )
		{
		memcpy( envelopeInfoPtr->blockBuffer,
				bufPtr + envelopeInfoPtr->bufPos - remainder, remainder );
		envelopeInfoPtr->blockBufferPos = remainder;
		envelopeInfoPtr->bufPos -= remainder;
		}

	/* If we're using the definite length form, exit */
	if( envelopeInfoPtr->payloadSize != CRYPT_UNUSED )
		return( TRUE );

	/* Encode the length at the start of the data */
	if( dLen < 128 )
		bufPtr[ segmentStart ] = dLen;
	else
		{
		lLen -= 2;	/* Tag + length of length */
		bufPtr[ segmentStart++ ] = 0x80 | lLen;
#if INT_MAX > 32767
		if( lLen > 3 )
			{
			bufPtr[ segmentStart++ ] = dLen >> 24;
			dLen &= 0xFFFFFFL;
			}
		if( lLen > 2 )
			{
			bufPtr[ segmentStart++ ] = dLen >> 16;
			dLen &= 0xFFFFL;
			}
#endif /* 32-bit ints */
		if( lLen > 1 )
			{
			bufPtr[ segmentStart++ ] = dLen >> 8;
			dLen &= 0xFF;
			}
		bufPtr[ segmentStart ] = dLen;
		}

	return( TRUE );
	}

static int completeSegment( ENVELOPE_INFO *envelopeInfoPtr,
							const BOOLEAN forceCompletion )
	{
	/* If we're enveloping data using indefinite encoding and we're not at
	   the end of the data, don't emit a subsegment containing less then 10
	   bytes of data.  This is to protect against users who write code which
	   performs byte-at-a-time enveloping, at least we can quantize the data
	   amount to make it slightly more efficient.  As a side-effect, it
	   avoids occasional inefficiencies at boundaries where one or two bytes
	   may still be hanging around from a previous data block, since they'll
	   be coalesced into the following block */
	if( !forceCompletion && \
		!( envelopeInfoPtr->flags & ENVELOPE_ISDEENVELOPE ) && \
		envelopeInfoPtr->payloadSize == CRYPT_UNUSED && \
		( envelopeInfoPtr->bufPos - envelopeInfoPtr->segmentDataStart ) < 10 )
		{
		/* We can't emit any of the small subsegment, however there may be
		   (non-)data preceding this which we can hand over so we set the
		   segment data end value to the start of the segment (the complete
		   segment starts at ( segmentStart - 1 )) */
		envelopeInfoPtr->segmentDataEnd = envelopeInfoPtr->segmentStart - 1;
		return( CRYPT_OK );
		}

	/* Wrap up the segment */
	if( !( envelopeInfoPtr->flags & ENVELOPE_NOSEGMENT ) && \
		!encodeSegmentHeader( envelopeInfoPtr, ( BOOLEAN )	/* VC++ fix */
					( envelopeInfoPtr->iCryptContext != CRYPT_ERROR ) ? \
					TRUE : FALSE ) )
		/* Not enough data to complete segment */
		return( CRYPT_ERROR_UNDERFLOW );
	if( envelopeInfoPtr->iCryptContext != CRYPT_ERROR )
		{
		int status;

		status = krnlSendMessage( envelopeInfoPtr->iCryptContext,
						RESOURCE_IMESSAGE_CTX_ENCRYPT,
						envelopeInfoPtr->buffer + \
								envelopeInfoPtr->segmentDataStart,
						envelopeInfoPtr->bufPos - \
								envelopeInfoPtr->segmentDataStart );
		if( cryptStatusError( status ) )
			return( status );
		}

	/* Remember how much data is now available to be read out */
	envelopeInfoPtr->segmentDataEnd = envelopeInfoPtr->bufPos;

	/* Mark this segment as being completed */
	envelopeInfoPtr->segmentComplete = TRUE;

⌨️ 快捷键说明

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