📄 env_dec.c
字号:
envelopeInfoPtr->bufPos <= envelopeInfoPtr->bufSize );
assert( ( envelopeInfoPtr->blockSize == 0 ) || \
( envelopeInfoPtr->blockBufferPos >= 0 && \
envelopeInfoPtr->blockBufferPos < envelopeInfoPtr->blockSize ) );
/* 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 it's unknown-length data (which can only
happen for compressed data), it ends wherever the caller tells us it
ends and we use it all */
bytesToCopy = ( envelopeInfoPtr->segmentSize == CRYPT_UNUSED ) ? \
length : ( int ) min( envelopeInfoPtr->segmentSize, length );
/* Now we check 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, 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 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
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 in */
bytesToCopy = min( bytesToCopy, \
( envelopeInfoPtr->bufSize - envelopeInfoPtr->bufPos ) - \
envelopeInfoPtr->blockBufferPos );
if( bytesToCopy < 0 || envelopeInfoPtr->blockBufferPos < 0 )
{
/* Safety check that verifies segmentSize, length, bufPos, and
blockBufferPos before we start into the following code */
assert( NOTREACHED );
return( CRYPT_ERROR_BADDATA );
}
/* If we're given a zero length, return now. This can happen if all
input is consumed in processing the headers (we're passed a zero
length) */
if( bytesToCopy <= 0 )
return( 0 );
/* 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 )
{
int bytesCopied = 0, quantizedBytesToCopy;
/* If the new data will fit into the block buffer, copy it in now and
return */
if( envelopeInfoPtr->blockBufferPos + bytesToCopy < \
envelopeInfoPtr->blockSize )
{
memcpy( envelopeInfoPtr->blockBuffer + envelopeInfoPtr->blockBufferPos,
buffer, bytesToCopy );
envelopeInfoPtr->blockBufferPos += bytesToCopy;
/* Adjust the segment size based on what we've consumed */
envelopeInfoPtr->segmentSize -= bytesToCopy;
return( bytesToCopy );
}
/* If there isn't room in the main buffer for even one more block,
exit without doing anything. 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 is still room in the block buffer */
if( envelopeInfoPtr->bufSize - envelopeInfoPtr->bufPos < \
envelopeInfoPtr->blockSize )
return( 0 ); /* No room for even one more block */
/* 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 )
{
memcpy( bufPtr, envelopeInfoPtr->blockBuffer,
envelopeInfoPtr->blockBufferPos );
bytesCopied = envelopeInfoPtr->blockBufferPos;
}
envelopeInfoPtr->blockBufferPos = 0;
/* Determine how many bytes we can copy into the buffer to fill it
to the nearest available block size */
quantizedBytesToCopy = ( bytesToCopy + bytesCopied ) & \
envelopeInfoPtr->blockSizeMask;
quantizedBytesToCopy -= bytesCopied;
if( bytesToCopy < 0 || quantizedBytesToCopy <= 0 || \
quantizedBytesToCopy > bytesToCopy )
{
/* Safety check */
assert( NOTREACHED );
return( CRYPT_ERROR_BADDATA );
}
/* 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 external
data */
memmove( bufPtr + bytesCopied, buffer, quantizedBytesToCopy );
envelopeInfoPtr->bufPos += bytesCopied + quantizedBytesToCopy;
envelopeInfoPtr->segmentSize -= bytesToCopy;
status = krnlSendMessage( envelopeInfoPtr->iCryptContext,
IMESSAGE_CTX_DECRYPT, bufPtr,
bytesCopied + quantizedBytesToCopy );
if( cryptStatusError( status ) )
return( status );
assert( envelopeInfoPtr->bufPos >=0 && \
envelopeInfoPtr->bufPos <= envelopeInfoPtr->bufSize );
assert( envelopeInfoPtr->segmentSize >= 0 );
/* 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 = processEOC( envelopeInfoPtr );
if( cryptStatusError( status ) )
return( status );
}
else
{
const int blockBufferBToC = bytesToCopy - quantizedBytesToCopy;
/* Copy any remainder (the difference between the amount to copy
and the blocksize-quantized amount) into the block buffer */
if( blockBufferBToC > 0 )
memcpy( envelopeInfoPtr->blockBuffer, buffer + quantizedBytesToCopy,
blockBufferBToC );
envelopeInfoPtr->blockBufferPos = blockBufferBToC;
}
return( bytesToCopy );
}
/* It's unencrypted or encrypted with a stream cipher, just copy over as
much of the segment as we can and decrypt it if necessary */
memcpy( envelopeInfoPtr->buffer + envelopeInfoPtr->bufPos, buffer,
bytesToCopy );
envelopeInfoPtr->bufPos += bytesToCopy;
if( envelopeInfoPtr->segmentSize != CRYPT_UNUSED )
envelopeInfoPtr->segmentSize -= bytesToCopy;
if( envelopeInfoPtr->iCryptContext != CRYPT_ERROR )
{
status = krnlSendMessage( envelopeInfoPtr->iCryptContext,
IMESSAGE_CTX_DECRYPT, bufPtr,
bytesToCopy );
if( cryptStatusError( status ) )
return( status );
}
/* 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 = processEOC( envelopeInfoPtr );
if( cryptStatusError( status ) )
return( status );
}
return( bytesToCopy );
}
/* Copy data into the de-enveloping envelope. Returns the number of bytes
copied */
static int copyToDeenvelope( ENVELOPE_INFO *envelopeInfoPtr,
const BYTE *buffer, const int length )
{
BYTE *bufPtr = ( BYTE * ) buffer;
int currentLength = length, bytesCopied;
assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
assert( length > 0 );
assert( isReadPtr( buffer, length ) );
assert( envelopeInfoPtr->bufPos >=0 && \
envelopeInfoPtr->bufPos <= envelopeInfoPtr->bufSize );
/* If we're trying to copy into a full buffer, return a count of 0 bytes
(the calling routine may convert this to an overflow error if
necessary) */
if( envelopeInfoPtr->bufPos >= envelopeInfoPtr->bufSize )
return( 0 );
/* If we're verifying a detached signature, just hash the data and exit.
We don't have to check for problems with the context at this point
since they'll be detected when we complete the hashing, and we don't
have to check whether hashing is active or not since it'll always be
active for detached data, which is hashed and discarded */
if( envelopeInfoPtr->flags & ENVELOPE_DETACHED_SIG )
{
ACTION_LIST *hashActionPtr;
assert( envelopeInfoPtr->dataFlags & ENVDATA_HASHACTIONSACTIVE );
assert( envelopeInfoPtr->actionList != NULL );
for( hashActionPtr = envelopeInfoPtr->actionList;
hashActionPtr != NULL && hashActionPtr->action == ACTION_HASH;
hashActionPtr = hashActionPtr->next )
krnlSendMessage( hashActionPtr->iCryptHandle, IMESSAGE_CTX_HASH,
( void * ) buffer, currentLength );
return( currentLength );
}
/* Keep processing data until either we run out of input or we can't copy
in any more data. The code sequence within this loop acts as a simple
FSM so that if we exit at any point then the next call to this
function will resume where we left off */
do
{
int segmentCount, status;
/* If there's no segment information currently available, we need to
process a segment header before we can handle any data. The use
of a loop is necessary to handle some broken implementations that
emit zero-length sub-segments. We limit the segment count to 10
sub-segments to make sure that we don't spend forever trying to
process extremely broken data */
for( segmentCount = 0; \
segmentCount < 10 && envelopeInfoPtr->segmentSize <= 0; \
segmentCount++ )
{
status = getNextSegment( envelopeInfoPtr, bufPtr, currentLength );
if( status == OK_SPECIAL )
/* We got the length via some other mechanism because it's a
definite-length or non-segmenting encoding, no input was
consumed and we can exit */
break;
if( cryptStatusError( status ) )
return( status );
bufPtr += status;
currentLength -= status;
/* If we've reached the EOC or consumed all of the input data,
exit */
if( ( envelopeInfoPtr->dataFlags & ENVDATA_ENDOFCONTENTS ) || \
currentLength <= 0 )
return( length - currentLength );
}
if( segmentCount >= 10 )
/* We've processed ten consecutive sub-segments in a row, there's
something wrong with the input data */
return( CRYPT_ERROR_BADDATA );
/* Copy the data into the envelope, decrypting it as we go if
necessary */
bytesCopied = copyData( envelopeInfoPtr, bufPtr, currentLength );
if( cryptStatusError( bytesCopied ) )
return( bytesCopied );
bufPtr += bytesCopied;
currentLength -= bytesCopied;
/* Sanity check to catch copying errors */
assert( envelopeInfoPtr->bufPos >= 0 && \
envelopeInfoPtr->bufPos <= envelopeInfoPtr->bufSize );
assert( currentLength >= 0 );
assert( ( envelopeInfoPtr->segmentSize >= 0 ) || \
( ( envelopeInfoPtr->dataFlags & ENVDATA_NOSEGMENT ) && \
( envelopeInfoPtr->payloadSize == CRYPT_UNUSED ) && \
( envelopeInfoPtr->segmentSize == CRYPT_UNUSED ) ) );
}
while( currentLength > 0 && bytesCopied > 0 );
return( length - currentLength );
}
/****************************************************************************
* *
* Copy from Envelope *
* *
****************************************************************************/
/* Copy data from the envelope. Returns the number of bytes copied */
static int copyFromDeenvelope( ENVELOPE_INFO *envelopeInfoPtr, BYTE *buffer,
int length )
{
BYTE *bufPtr = envelopeInfoPtr->buffer;
const BOOLEAN isLookaheadRead = ( length < 0 ) ? TRUE : FALSE;
int bytesToCopy, bytesCopied, remainder;
int oobBytesCopied = 0;
assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
assert( envelopeInfoPtr->bufPos >=0 && \
envelopeInfoPtr->bufPos <= envelopeInfoPtr->bufSize );
assert( envelopeInfoPtr->oobBufPos >= 0 && \
envelopeInfoPtr->oobBufPos <= OOB_BUFFER_SIZE );
/* Remember how much data we need to copy. A negative length specifies
that this is a speculative/lookahead read, so we turn it into a
positive value if necessary */
bytesToCopy = length = ( length < 0 ) ? -length : length;
if( bytesToCopy < 0 )
{
/* Safety checks, also covers some later operations like the OOB
copy */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -