📄 env_enc.c
字号:
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->dataFlags |= ENVDATA_SEGMENTCOMPLETE;
return( CRYPT_OK );
}
/****************************************************************************
* *
* Copy to Envelope *
* *
****************************************************************************/
/* Copy data into the envelope. Returns the number of bytes copied, or an
overflow error if we're trying to flush data and there isn't room to
perform the flush (this somewhat peculiar case is because the caller
expects to have 0 bytes copied in this case) */
static int copyToEnvelope( ENVELOPE_INFO *envelopeInfoPtr,
const BYTE *buffer, const int length )
{
ACTION_LIST *hashActionPtr;
BOOLEAN needCompleteSegment = FALSE;
BYTE *bufPtr;
int bytesToCopy, status;
assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
assert( length >= 0 );
assert( isReadPtr( buffer, length ) );
/* Perform a safety check of the envelope state */
if( envelopeInfoPtr->bufPos < 0 || \
envelopeInfoPtr->bufPos > envelopeInfoPtr->bufSize )
{
assert( NOTREACHED );
return( CRYPT_ERROR_OVERFLOW );
}
/* If we're trying to copy into a full buffer, return a count of 0 bytes
unless we're trying to flush the buffer (the calling routine may
convert this to an overflow error if necessary) */
if( envelopeInfoPtr->bufPos >= envelopeInfoPtr->bufSize )
return( length > 0 ? 0 : CRYPT_ERROR_OVERFLOW );
/* If we're generating a detached signature, just hash the data and
exit */
if( envelopeInfoPtr->flags & ENVELOPE_DETACHED_SIG )
{
/* Unlike CMS, PGP handles authenticated attributes by extending the
hashing of the payload data to cover the additional attributes,
so if this is a flush and we're using the PGP format we can't
wrap up the hashing yet */
if( length <= 0 && envelopeInfoPtr->type == CRYPT_FORMAT_PGP )
return( 0 );
assert( envelopeInfoPtr->actionList != NULL );
for( hashActionPtr = envelopeInfoPtr->actionList;
hashActionPtr != NULL && hashActionPtr->action == ACTION_HASH;
hashActionPtr = hashActionPtr->next )
{
status = krnlSendMessage( hashActionPtr->iCryptHandle,
IMESSAGE_CTX_HASH, ( void * ) buffer,
length );
if( cryptStatusError( status ) )
return( status );
}
return( length );
}
/* If we're flushing data, wrap up the segment and exit */
if( length <= 0 )
{
BOOLEAN needNewSegment = envelopeInfoPtr->dataFlags & \
ENVDATA_NEEDSPADDING;
#ifdef USE_COMPRESSION
/* If we're using compression, flush any remaining data out of the
zStream */
if( envelopeInfoPtr->flags & ENVELOPE_ZSTREAMINITED )
{
/* 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 */
return( CRYPT_ERROR_FAILED );
/* Adjust the status information based on the data flushed out
of the zStream. We don't need 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;
assert( 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 )
{
envelopeInfoPtr->dataFlags |= ENVDATA_NEEDSPADDING;
if( envelopeInfoPtr->dataFlags & ENVDATA_SEGMENTCOMPLETE )
/* The current segment has been wrapped up, we need to begin
a new segment to contain the padding */
needNewSegment = TRUE;
}
/* If we're carrying over the padding requirement from a previous
block, we need to begin a new block before we can try and add the
padding. This can happen if there was data left after the
previous segment was completed or if the addition of padding
would have overflowed the buffer when the segment was completed,
in other words if the needPadding flag is still set from the
previous call */
if( needNewSegment )
{
status = beginSegment( envelopeInfoPtr );
if( cryptStatusError( status ) )
return( status );
if( envelopeInfoPtr->bufPos >= envelopeInfoPtr->bufSize )
return( CRYPT_ERROR_OVERFLOW );
}
/* Complete the segment if necessary */
if( !( envelopeInfoPtr->dataFlags & ENVDATA_SEGMENTCOMPLETE ) || \
( envelopeInfoPtr->dataFlags & ENVDATA_NEEDSPADDING ) )
{
status = completeSegment( envelopeInfoPtr, TRUE );
if( cryptStatusError( status ) )
return( status );
}
if( envelopeInfoPtr->dataFlags & ENVDATA_NEEDSPADDING )
return( CRYPT_ERROR_OVERFLOW );
/* If we're completed the hashing, we're done. In addition unlike
CMS, PGP handles authenticated attributes by extending the
hashing of the payload data to cover the additional attributes,
so if we're using the PGP format we can't wrap up the hashing
yet */
if( !( envelopeInfoPtr->dataFlags & ENVDATA_HASHACTIONSACTIVE ) || \
envelopeInfoPtr->type == CRYPT_FORMAT_PGP )
return( 0 );
/* We've finished processing everything, complete each hash action if
necessary */
assert( envelopeInfoPtr->actionList != NULL );
for( hashActionPtr = envelopeInfoPtr->actionList;
hashActionPtr != NULL && hashActionPtr->action == ACTION_HASH;
hashActionPtr = hashActionPtr->next )
{
status = krnlSendMessage( hashActionPtr->iCryptHandle,
IMESSAGE_CTX_HASH, "", 0 );
if( cryptStatusError( status ) )
return( status );
}
return( 0 );
}
/* If we've just completed a segment, begin a new one before we add any
data */
if( envelopeInfoPtr->dataFlags & ENVDATA_SEGMENTCOMPLETE )
{
status = beginSegment( envelopeInfoPtr );
if( cryptStatusError( status ) || \
envelopeInfoPtr->bufPos >= envelopeInfoPtr->bufSize )
return( 0 ); /* 0 bytes copied */
}
/* Copy over as much as we can fit into the buffer */
bufPtr = envelopeInfoPtr->buffer + envelopeInfoPtr->bufPos;
bytesToCopy = envelopeInfoPtr->bufSize - envelopeInfoPtr->bufPos;
if( bytesToCopy <= 0 )
{
/* Safety check */
assert( NOTREACHED );
return( CRYPT_ERROR_OVERFLOW );
}
#ifdef USE_COMPRESSION
if( envelopeInfoPtr->flags & ENVELOPE_ZSTREAMINITED )
{
/* Compress the data into the envelope buffer */
envelopeInfoPtr->zStream.next_in = ( BYTE * ) buffer;
envelopeInfoPtr->zStream.avail_in = length;
envelopeInfoPtr->zStream.next_out = bufPtr;
envelopeInfoPtr->zStream.avail_out = bytesToCopy;
status = deflate( &envelopeInfoPtr->zStream, Z_NO_FLUSH );
if( status != Z_OK )
return( CRYPT_ERROR );
/* Adjust the status information based on the data copied into the
zStream and flushed from the zStream into the buffer */
envelopeInfoPtr->bufPos += bytesToCopy - \
envelopeInfoPtr->zStream.avail_out;
bytesToCopy = length - envelopeInfoPtr->zStream.avail_in;
/* If the buffer is full (there's no more room left for further
input) we need to close off the segment */
if( envelopeInfoPtr->zStream.avail_out <= 0 )
needCompleteSegment = TRUE;
}
else
#endif /* USE_COMPRESSION */
{
/* We're not using compression */
if( bytesToCopy > length )
bytesToCopy = length;
memcpy( bufPtr, buffer, bytesToCopy );
envelopeInfoPtr->bufPos += bytesToCopy;
/* Hash the data if necessary. We don't have to check for problems
with the context at this point since they'll be detected when we
complete the hashing */
if( envelopeInfoPtr->dataFlags & ENVDATA_HASHACTIONSACTIVE )
for( hashActionPtr = envelopeInfoPtr->actionList;
hashActionPtr != NULL && hashActionPtr->action == ACTION_HASH;
hashActionPtr = hashActionPtr->next )
krnlSendMessage( hashActionPtr->iCryptHandle,
IMESSAGE_CTX_HASH, bufPtr, bytesToCopy );
/* If the buffer is full (i.e. we've been fed more input data than we
could copy into the buffer) we need to close off the segment */
if( bytesToCopy < length )
needCompleteSegment = TRUE;
}
assert( envelopeInfoPtr->bufPos >= 0 );
/* Close off the segment if necessary */
if( needCompleteSegment )
{
status = completeSegment( envelopeInfoPtr, FALSE );
if( cryptStatusError( status ) )
return( status );
}
return( bytesToCopy );
}
/****************************************************************************
* *
* Copy from Envelope *
* *
****************************************************************************/
/* Copy data from the envelope and begin a new segment in the newly-created
room. If called with a zero length value this will create a new segment
without moving any data. Returns the number of bytes copied */
static int copyFromEnvelope( ENVELOPE_INFO *envelopeInfoPtr, BYTE *buffer,
int length )
{
BYTE *bufPtr = envelopeInfoPtr->buffer;
int remainder;
assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
assert( length >= 0 );
assert( isWritePtr( buffer, length ) );
/* Perform a safety check of the envelope state */
if( envelopeInfoPtr->bufPos < 0 || \
envelopeInfoPtr->bufPos > envelopeInfoPtr->bufSize )
{
assert( NOTREACHED );
return( CRYPT_ERROR_OVERFLOW );
}
/* If the caller wants more data than there is available in the set of
completed segments, try to wrap up the next segment to make more data
available */
if( length > envelopeInfoPtr->segmentDataEnd )
{
/* Try and complete the segment if necessary. This may not be
possible if we're using a block encryption mode and there isn't
enough room at the end of the buffer to encrypt a full block. If
we're generating a detached sig, the data is communicated out-of-
band, so there's no segmenting */
if( !( envelopeInfoPtr->flags & ENVELOPE_DETACHED_SIG ) && \
!( envelopeInfoPtr->dataFlags & ENVDATA_SEGMENTCOMPLETE ) )
{
int status = completeSegment( envelopeInfoPtr, FALSE );
if( cryptStatusError( status ) )
return( status );
}
/* Return all of the data that we've got */
length = min( length, envelopeInfoPtr->segmentDataEnd );
}
remainder = envelopeInfoPtr->bufPos - length;
assert( remainder >= 0 && remainder <= envelopeInfoPtr->bufPos );
/* Copy the data out and move any remaining data down to the start of the
buffer */
if( length > 0 )
{
memcpy( buffer, bufPtr, length );
/* Move any remaining data down in the buffer */
if( remainder > 0 )
memmove( envelopeInfoPtr->buffer, envelopeInfoPtr->buffer + length,
remainder );
envelopeInfoPtr->bufPos = remainder;
/* Update the segment location information. Note that the segment
start values track the start position of the last completed segment
and aren't updated until we begin a new segment, so they may go
negative at this point when the data from the last completed
segment is moved past the start of the buffer */
envelopeInfoPtr->segmentStart -= length;
envelopeInfoPtr->segmentDataStart -= length;
envelopeInfoPtr->segmentDataEnd -= length;
assert( envelopeInfoPtr->segmentDataEnd >= 0 );
}
return( length );
}
/****************************************************************************
* *
* Envelope Access Routines *
* *
****************************************************************************/
void initEnvelopeStreaming( ENVELOPE_INFO *envelopeInfoPtr )
{
/* Set the access method pointers */
envelopeInfoPtr->copyToEnvelopeFunction = copyToEnvelope;
envelopeInfoPtr->copyFromEnvelopeFunction = copyFromEnvelope;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -