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

📄 encode.c

📁 cryptlib安全工具包
💻 C
📖 第 1 页 / 共 3 页
字号:
		   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 + dataLen + \
			envelopeInfoPtr->blockSize < envelopeInfoPtr->bufSize )
			dataLen += envelopeInfoPtr->blockSize;
		else
			needsPadding = FALSE;
		}
	ENSURES( dataLen > 0 && envelopeInfoPtr->segmentDataStart + \
									dataLen <= envelopeInfoPtr->bufSize );

	/* 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) */
	hdrLen = ( envelopeInfoPtr->payloadSize == CRYPT_UNUSED ) ? \
			 TAG_SIZE + lengthOfLength( dataLen ) : 0;

	/* Quantize and adjust the length if we're encrypting in a block mode:

			   segDataStart					  bufPos
		segStart	|							|
			v		v<--------- dLen ---------->v
		----+-------+---------------------------+
			|  hdr	|///////////////////////|	|
		----+-------+---------------------------+
					|<------ qTotLen ------>|<+>|
											  |
										  remainder */
	if( isEncrypted )
		{
		int quantisedTotalLen, threshold;

		/* Determine the length due to cipher block-size quantisation */
		quantisedTotalLen = dataLen & envelopeInfoPtr->blockSizeMask;

		/* If the block-size quantisation has moved the quantised length
		   across a length-of-length encoding boundary, adjust hdrLen to
		   account for this */
		threshold = findThreshold( quantisedTotalLen );
		if( quantisedTotalLen <= threshold && dataLen > threshold )
			hdrLen--;

		/* Remember how many bytes we can't fit into the current block
		   (these will be copied into the block buffer for later use), and
		   the new size of the data due to quantisation */
		remainder = dataLen - quantisedTotalLen;
		dataLen = quantisedTotalLen;
		}
	ENSURES( ( envelopeInfoPtr->payloadSize != CRYPT_UNUSED && hdrLen == 0 ) || \
			 ( envelopeInfoPtr->payloadSize == CRYPT_UNUSED && \
			   hdrLen > 0 && hdrLen <= TAG_SIZE + 5 ) );
	ENSURES( ( envelopeInfoPtr->blockSize == 0 && remainder == 0 ) || \
			 ( envelopeInfoPtr->blockSize > 0 && \
			   remainder >= 0 && remainder < envelopeInfoPtr->blockSize && \
			   remainder <= CRYPT_MAX_IVSIZE  ) );

	/* If there's not enough data present to do anything, tell the caller */
	if( dataLen <= 0 )
		return( CRYPT_ERROR_UNDERFLOW );
	ENSURES( dataLen > 0 && dataLen < MAX_INTLENGTH );

	/* If there's a header between segments and the header 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.  In the
	   worst case the shrinking can cover several bytes if we go from a
	   > 255 byte segment to a <= 127 byte one:

			   segDataStart					  bufPos
		segStart	|							|
			v		v							v
		----+-------+---------------------------+
			|  hdr	|///////////////////////////|	Before
		----+-------+---------------------------+
			|<--+-->|
				|
			oldHdrLen

		   segDataStart'				 bufPos'
		segStart|							|
			v	v							v
		----+-------+-----------------------+---+
			|hdr|///////////////////////////|	|	After
		----+-------+-----------------------+---+
			|<+>|<+>|						|<+>|
			  |	  |							  |
			  | delta						delta
			hdrLen */
	if( hdrLen > 0 && hdrLen < oldHdrLen )
		{
		BYTE *segmentDataPtr = envelopeInfoPtr->buffer + \
							   envelopeInfoPtr->segmentStart;
		const int delta = oldHdrLen - hdrLen;

		memmove( segmentDataPtr + hdrLen, segmentDataPtr + oldHdrLen,
				 envelopeInfoPtr->bufPos - envelopeInfoPtr->segmentDataStart );
		envelopeInfoPtr->bufPos -= delta;
		envelopeInfoPtr->segmentDataStart -= delta;
		}
	ENSURES( sanityCheck( envelopeInfoPtr ) );
	ENSURES( envelopeInfoPtr->segmentDataStart + \
						dataLen <= envelopeInfoPtr->bufSize );

	/* If we need to add PKCS #5 block padding, do so now (we know from the
	   needsPadding and quantisedTotalLen check above that there's enough 
	   room for this).  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;

		ENSURES( padSize > 0 && padSize <= envelopeInfoPtr->blockSize && \
				 envelopeInfoPtr->bufPos + \
						padSize <= envelopeInfoPtr->bufSize );

		/* 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->dataFlags &= ~ENVDATA_NEEDSPADDING;
		ENSURES( envelopeInfoPtr->bufPos >= 0 && \
				 envelopeInfoPtr->bufPos <= envelopeInfoPtr->bufSize );
		}
	else
		{
		/* If there are any bytes left over move them across into the block 
		   buffer */
		if( remainder > 0 )
			{
			REQUIRES( envelopeInfoPtr->bufPos > remainder );
			memcpy( envelopeInfoPtr->blockBuffer,
					envelopeInfoPtr->buffer + envelopeInfoPtr->bufPos - \
											  remainder, remainder );
			envelopeInfoPtr->blockBufferPos = remainder;
			envelopeInfoPtr->bufPos -= remainder;
			}
		}

	ENSURES( sanityCheck( envelopeInfoPtr ) );

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

	/* Insert the OCTET STRING header into the data stream */
	sMemOpen( &stream, envelopeInfoPtr->buffer + \
					   envelopeInfoPtr->segmentStart, hdrLen );
	status = writeOctetStringHole( &stream, dataLen, DEFAULT_TAG );
	ENSURES( cryptStatusOK( status ) && stell( &stream ) == hdrLen );
	sMemDisconnect( &stream );

	return( CRYPT_OK );
	}

CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int completeSegment( INOUT ENVELOPE_INFO *envelopeInfoPtr,
							const BOOLEAN forceCompletion )
	{
	int status;

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

	REQUIRES( sanityCheck( envelopeInfoPtr ) );

	/* If we're enveloping data using indefinite encoding and we're not at
	   the end of the data, don't emit a sub-segment containing less then 10
	   bytes of data.  This is to protect against users who write code that
	   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->payloadSize == CRYPT_UNUSED && \
		( envelopeInfoPtr->bufPos - envelopeInfoPtr->segmentDataStart ) < 10 )
		{
		/* We can't emit any of the small sub-segment, however there may be
		   (non-)data preceding this that we can hand over so we set the
		   segment data end value to the start of the segment */
		envelopeInfoPtr->segmentDataEnd = envelopeInfoPtr->segmentStart;
		return( CRYPT_OK );
		}

	/* Wrap up the segment */
	if( !( envelopeInfoPtr->dataFlags & ENVDATA_NOSEGMENT ) )
		{
		status = encodeSegmentHeader( envelopeInfoPtr );
		if( cryptStatusError( status ) )
			return( status );
		}
	if( envelopeInfoPtr->iCryptContext != CRYPT_ERROR )
		{
		status = krnlSendMessage( envelopeInfoPtr->iCryptContext,
						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 complete */
	envelopeInfoPtr->dataFlags |= ENVDATA_SEGMENTCOMPLETE;

	return( CRYPT_OK );
	}

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

/* Flush any remaining data through into the envelope buffer */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int flushEnvelopeData( INOUT ENVELOPE_INFO *envelopeInfoPtr )
	{
	BOOLEAN needNewSegment = \
				( envelopeInfoPtr->dataFlags & ENVDATA_NEEDSPADDING ) ? \
				TRUE : FALSE;
	int status;

	REQUIRES( sanityCheck( envelopeInfoPtr ) );

	/* If we're using an explicit payload length make sure that we copied in 
	   as much data as was explicitly declared */
	if( envelopeInfoPtr->payloadSize != CRYPT_UNUSED && \
		envelopeInfoPtr->segmentSize != 0 )
		return( CRYPT_ERROR_UNDERFLOW );

#ifdef USE_COMPRESSION
	/* If we're using compression, flush any remaining data out of the
	   zStream */
	if( envelopeInfoPtr->flags & ENVELOPE_ZSTREAMINITED )
		{
		int bytesToCopy;

		/* If we've just completed a segment, begin a new one.  This action
		   is slightly anomalous in that normally a flush can't add more
		   data to the envelope and so we'd never need to start a new
		   segment during a flush, however since we can have arbitrarily
		   large amounts of data trapped in subspace via zlib we need to be
		   able to handle starting new segments at this point */
		if( envelopeInfoPtr->dataFlags & ENVDATA_SEGMENTCOMPLETE )
			{
			status = beginSegment( envelopeInfoPtr );
			if( cryptStatusError( status ) )
				return( status );
			if( envelopeInfoPtr->bufPos >= envelopeInfoPtr->bufSize )
				return( CRYPT_ERROR_OVERFLOW );
			}

		/* Flush any remaining compressed data into the envelope buffer */
		bytesToCopy = envelopeInfoPtr->bufSize - envelopeInfoPtr->bufPos;
		envelopeInfoPtr->zStream.next_in = NULL;
		envelopeInfoPtr->zStream.avail_in = 0;
		envelopeInfoPtr->zStream.next_out = envelopeInfoPtr->buffer + \
											envelopeInfoPtr->bufPos;
		envelopeInfoPtr->zStream.avail_out = bytesToCopy;
		status = deflate( &envelopeInfoPtr->zStream, Z_FINISH );
		if( status != Z_STREAM_END && status != Z_OK )
			{
			/* There was some problem other than the output buffer being
			   full */
			retIntError();
			}

		/* Adjust the status information based on the data flushed out of
		   the zStream.  We don't have to check for the output buffer being
		   full because this case is already handled by the check of the
		   deflate() return value */
		envelopeInfoPtr->bufPos += bytesToCopy - \
								   envelopeInfoPtr->zStream.avail_out;
		ENSURES( envelopeInfoPtr->bufPos >= 0 && \
				 envelopeInfoPtr->bufPos <= envelopeInfoPtr->bufSize );

		/* If we didn't finish flushing data because the output buffer is
		   full, complete the segment and tell the caller that they need to
		   pop some data */
		if( status == Z_OK )
			{
			status = completeSegment( envelopeInfoPtr, TRUE );
			return( cryptStatusError( status ) ? \
					status : CRYPT_ERROR_OVERFLOW );
			}
		}
#endif /* USE_COMPRESSION */

	/* If we're encrypting data with a block cipher we need to add PKCS #5
	   padding at the end of the last block */
	if( envelopeInfoPtr->blockSize > 1 )
		{

⌨️ 快捷键说明

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