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

📄 decode.c

📁 cryptlib安全工具包
💻 C
📖 第 1 页 / 共 4 页
字号:
	   doesn't segment data the length is implicitly defined as "until we 
	   run out of input".  This odd situation is encountered in some cases
	   when working with PGP data such as compressed data for which there's
	   no length stored or when we're synchronising the envelope data prior 
	   to processing and there are abitrary further packets (typically PGP 
	   signature packets, where we want to process the packets in a 
	   connected series rather than stopping at the end of the first packet
	   in the series) following the current one.  In both cases we don't 
	   know the overall length because we'd need to be able to look ahead
	   an arbitrary distance in the stream to figure out where the 
	   compressed data or any further packets end */
	if( envelopeInfoPtr->dataFlags & ENVDATA_NOLENGTHINFO )
		{
		REQUIRES( envelopeInfoPtr->segmentSize <= 0 );

		*segmentStatus = SEGMENT_FIXEDLENGTH;
		return( OK_SPECIAL );
		}

	/* If there's not enough data left to contain the header for a
	   reasonable-sized segment, tell the caller to try again with more data 
	   (the bytesConsumed value has already been set to zero earlier).  For 
	   a PGP envelope a partial header is a single byte, for a PKCS #7/CMS 
	   envelope it's two bytes (tag + length) but most segments will be 
	   longer than 256 bytes, requiring at least three bytes of tag + length 
	   data.  A reasonable tradeoff seems to be to require three bytes 
	   before trying to decode the length */
	if( length < 3 )
		{
		*segmentStatus = SEGMENT_INSUFFICIENTDATA;
		return( CRYPT_OK );
		}

	/* Get the sub-segment info */
	sMemConnect( &stream, buffer, length );
#ifdef USE_PGP
	if( envelopeInfoPtr->type == CRYPT_FORMAT_PGP )
		{
		status = processPgpSegment( envelopeInfoPtr, &stream, 
									&segmentLength );
		}
	else
#endif /* USE_PGP */
		{
		status = processSegment( envelopeInfoPtr, &stream, 
								 &segmentLength );
		}
	if( cryptStatusOK( status ) )
		*bytesConsumed = stell( &stream );
	sMemDisconnect( &stream );
	if( cryptStatusError( status ) )
		{
		/* If we got an underflow error this isn't fatal since we can 
		   continue when the user pushes more data, so we return normally
		   with bytesConsumed set to zero */
		if( status == CRYPT_ERROR_UNDERFLOW )
			{
			*segmentStatus = SEGMENT_INSUFFICIENTDATA;
			return( CRYPT_OK );
			}
		return( status );
		}
	ENSURES( *bytesConsumed > 0 && *bytesConsumed <= length );

	/* We got the length, return the information to the caller */
	envelopeInfoPtr->segmentSize = segmentLength;

	ENSURES( sanityCheck( envelopeInfoPtr ) );

	return( CRYPT_OK );
	}

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

/* Copy encrypted data blocks into the envelope buffer with any overflow 
   held in the block buffer.  Only complete blocks are copied into the main
   envelope buffer, if there's not enough data present for a complete block
   it's temporarily held in the block buffer:

			 bytesFromBB			  bytesToBB
		bufPos--+ |						  |
				v<+>|<-- qBytesToCopy ->|<+>|
	+-----------+-----------------------+	|
	|			|///|	|		|		|	|		Main buffer
	+-----------+-----------------------+-------+
				  ^			 ^			|///|	|	Overflow block buffer
				  |			 |			+-------+
			 Prev.bBuf	  New data		  ^	
			 contents					  |
									New data remaining */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 4 ) ) \
static int copyEncryptedDataBlocks( INOUT ENVELOPE_INFO *envelopeInfoPtr,
									IN_BUFFER( length ) const BYTE *buffer, 
									IN_LENGTH const int length,
									OUT_LENGTH_Z int *bytesCopied )
	{
	BYTE *bufPtr = envelopeInfoPtr->buffer + envelopeInfoPtr->bufPos;
	int bytesFromBB = 0, quantizedBytesToCopy, bytesToBB, status;

	assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
	assert( isReadPtr( buffer, length ) );
	assert( isWritePtr( bytesCopied, sizeof( int ) ) );

	REQUIRES( sanityCheck( envelopeInfoPtr ) );
	REQUIRES( length > 0 && length < MAX_INTLENGTH && \
			  envelopeInfoPtr->bufPos + \
				envelopeInfoPtr->blockBufferPos + \
				length <= envelopeInfoPtr->bufSize + \
						  envelopeInfoPtr->blockSize );
	REQUIRES( !( envelopeInfoPtr->dataFlags & ENVDATA_NOLENGTHINFO ) );

	/* Clear return value */
	*bytesCopied = 0;

	/* If the new data will fit entirely into the block buffer, copy it in
	   now and return */
	if( envelopeInfoPtr->blockBufferPos + length < envelopeInfoPtr->blockSize )
		{
		memcpy( envelopeInfoPtr->blockBuffer + envelopeInfoPtr->blockBufferPos, 
				buffer, length );
		envelopeInfoPtr->blockBufferPos += length;

		/* Adjust the segment size based on what we've consumed */
		envelopeInfoPtr->segmentSize -= length;
		*bytesCopied = length;

		ENSURES( sanityCheck( envelopeInfoPtr ) );

		return( CRYPT_OK );
		}

	/* If there isn't room in the main buffer for even one more block, exit
	   without doing anything (bytesCopied is still set to zero from the 
	   earlier code).  This leads to slightly anomalous behaviour where, 
	   with no room for a complete block in the main buffer, copying in a 
	   data length smaller than the block buffer will lead to the data being 
	   absorbed by the block buffer due to the previous section of code, but 
	   copying in a length larger than the block buffer will result in no 
	   data at all being absorbed even if there's still room in the block 
	   buffer, see the long comment in copyData() for a full discussion of 
	   this process */
	if( envelopeInfoPtr->bufPos + \
			envelopeInfoPtr->blockSize > envelopeInfoPtr->bufSize )
		{
		/* There's no room for even one more block */
		return( CRYPT_OK );	
		}

	/* There's room for at least one more block in the buffer.  First, if
	   there are leftover bytes in the block buffer, move them into the main
	   buffer */
	if( envelopeInfoPtr->blockBufferPos > 0 )
		{
		bytesFromBB = envelopeInfoPtr->blockBufferPos;
		memcpy( bufPtr, envelopeInfoPtr->blockBuffer, bytesFromBB );
		}
	envelopeInfoPtr->blockBufferPos = 0;

	/* Determine how many bytes we can copy into the buffer to fill it to
	   the nearest available block size */
	quantizedBytesToCopy = ( length + bytesFromBB ) & \
						   envelopeInfoPtr->blockSizeMask;
	quantizedBytesToCopy -= bytesFromBB;
	ENSURES( quantizedBytesToCopy > 0 && quantizedBytesToCopy <= length && \
			 envelopeInfoPtr->bufPos + bytesFromBB + \
					quantizedBytesToCopy <= envelopeInfoPtr->bufSize );
	ENSURES( ( ( bytesFromBB + quantizedBytesToCopy ) & \
			   ( envelopeInfoPtr->blockSize - 1 ) ) == 0 );

	/* Now copy across a number of bytes which is a multiple of the block
	   size and decrypt them.  Note that we have to use memmove() rather
	   than memcpy() because if we're sync'ing data in the buffer we're
	   doing a copy within the buffer rather than copying in data from
	   an external source */
	memmove( bufPtr + bytesFromBB, buffer, quantizedBytesToCopy );
	status = krnlSendMessage( envelopeInfoPtr->iCryptContext,
							  IMESSAGE_CTX_DECRYPT, bufPtr,
							  bytesFromBB + quantizedBytesToCopy );
	if( cryptStatusError( status ) )
		return( status );
	envelopeInfoPtr->bufPos += bytesFromBB + quantizedBytesToCopy;
	envelopeInfoPtr->segmentSize -= length;
	ENSURES( envelopeInfoPtr->bufPos >= 0 && \
			envelopeInfoPtr->bufPos <= envelopeInfoPtr->bufSize );
	ENSURES( envelopeInfoPtr->segmentSize >= 0 && \
			 envelopeInfoPtr->segmentSize < MAX_INTLENGTH );

	/* If the payload has a definite length and we've reached its end, set
	   the EOC flag to make sure that we don't go any further */
	if( envelopeInfoPtr->payloadSize != CRYPT_UNUSED && \
		envelopeInfoPtr->segmentSize <= 0 )
		{
		status = processDataEnd( envelopeInfoPtr );
		if( cryptStatusError( status ) )
			return( status );

		ENSURES( sanityCheck( envelopeInfoPtr ) );

		*bytesCopied = length;
		return( CRYPT_OK );
		}

	/* Copy any remainder (the difference between the amount to copy and the
	   blocksize-quantized amount) into the block buffer */
	bytesToBB = length - quantizedBytesToCopy;
	REQUIRES( bytesToBB >= 0 && bytesToBB <= envelopeInfoPtr->blockSize );
	if( bytesToBB > 0 )
		{
		memcpy( envelopeInfoPtr->blockBuffer, buffer + quantizedBytesToCopy,
				bytesToBB );
		}
	envelopeInfoPtr->blockBufferPos = bytesToBB;

	ENSURES( sanityCheck( envelopeInfoPtr ) );

	*bytesCopied = length;
	return( CRYPT_OK );
	}

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

						  bPos			  bSize
							|				|
							v				v
	+-----------------------+---------------+
	|		|		|		|		|		|	Main buffer
	+-----------------------+---------------+

							+-------+
							|///|	|			Overflow block buffer
							+-------+
								^	^
								|blBufSize
							 blBufPos

    The main buffer only contains data amounts quantised to the encryption
	block size.  Any additional data is copied into the block buffer, a
	staging buffer used to accumulate data until it can be transferred to
	the main buffer for decryption */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 4 ) ) \
static int copyData( INOUT ENVELOPE_INFO *envelopeInfoPtr, 
					 IN_BUFFER( length ) const BYTE *buffer, 
					 IN_LENGTH const int length,
					 OUT_LENGTH_Z int *bytesCopied )
	{
	BYTE *bufPtr = envelopeInfoPtr->buffer + envelopeInfoPtr->bufPos;
	int bytesToCopy = length, bytesLeft, status;

	assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
	assert( isReadPtr( buffer, length ) );
	assert( isWritePtr( bytesCopied, sizeof( int ) ) );

	REQUIRES( sanityCheck( envelopeInfoPtr ) );
	REQUIRES( length > 0 && length < MAX_INTLENGTH );

	/* Clear return value */
	*bytesCopied = 0;

	/* Figure out how much we can copy across.  First we calculate the
	   minimum of the amount of data passed in and the amount remaining in
	   the current segment */
	if( !( envelopeInfoPtr->dataFlags & ENVDATA_NOLENGTHINFO ) && \
		bytesToCopy > envelopeInfoPtr->segmentSize )
		bytesToCopy = envelopeInfoPtr->segmentSize;

	/* Now we check to see if this is affected by the total free space
	   remaining in the buffer.  If we're processing data blocks we can have
	   two cases, one in which the limit is the amount of buffer space
	   available and the other in which the limit is the amount of data
	   available.  If the limit is set by the available data then we don't 
	   have to worry about flushing extra data out of the block buffer into 
	   the main buffer but if the limit is set by the available buffer space 
	   we have to reduce the amount that we can copy in based on any extra 
	   data that will be flushed out of the block buffer.

	   There are two possible approaches that can be used when the block
	   buffer is involved.  The first one copies as much as we can into the
	   buffer and, if that isn't enough, maxes out the block buffer with as
	   much remaining data as possible.  The second only copies in as much as
	   can fit into the buffer, even if there's room in the block buffer for
	   a few more bytes.  The second approach is preferable because although
	   either will give the impression of a not-quite-full buffer into which
	   no more data can be copied, the second minimizes the amount of data
	   which is moved into and out of the block buffer.

	   The first approach may seem slightly more logical, but will only
	   cause confusion in the long run.  Consider copying (say) 43 bytes to
	   a 43-byte buffer.  The first time this will succeed, after which there
	   will be 40 bytes in the buffer (reported to the caller) and 3 in the
	   block buffer.  If the caller tries to copy in 3 more bytes to "fill"
	   the main buffer, they'll again vanish into the block buffer.  A second
	   call with three more bytes will copy 2 bytes and return with 1 byte
	   uncopied.  In effect this method of using the block buffer extends the
	   blocksize-quantized main buffer by the size of the block buffer, which
	   will only cause confusion when data appears to vanish when copied into
	   it.

	   In the following length calculation the block buffer content is 
	   counted as part of the total content in order to implement the second
	   buffer-filling strategy */
	bytesLeft = envelopeInfoPtr->bufSize - \
				( envelopeInfoPtr->bufPos + envelopeInfoPtr->blockBufferPos );
	if( bytesLeft <= 0 )
		{
		/* There's no room left to copy anything in, return now (bytesCopied 
		   is still set to zero from the earlier code).  We can't check this 
		   in the calling code because it doesn't know about the internal 
		   buffer-handling strategy that we use so we perform an explicit 
		   check here */
		return( CRYPT_OK );
		}
	if( bytesLeft < bytesToCopy )
		bytesToCopy = bytesLeft;
	ENSURES( bytesToCopy > 0 && bytesToCopy <= length );

	/* If its a block encryption mode we need to provide special handling for
	   odd data lengths that don't match the block size */
	if( envelopeInfoPtr->blockSize > 1 )
		{
		return( copyEncryptedDataBlocks( envelopeInfoPtr, buffer,
										 bytesToCopy, bytesCopied ) );
		}

	/* It's unencrypted data or data that's encrypted with a stream cipher, 
	   just copy over as much of the segment as we can and decrypt it if 
	   necessary.  We use memmove() for the same reason as given above */
	memmove( bufPtr, buffer, bytesToCopy );

⌨️ 快捷键说明

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