📄 pgp_env.c
字号:
/* There's no key exchange action, we're using a raw session
key derived from a password */
envelopeInfoPtr->lastAction = envelopeInfoPtr->actionList;
envelopeInfoPtr->envState = ENVSTATE_KEYINFO;
}
else
{
STREAM stream;
int length;
/* If we're not encrypting data (i.e. there's only a single
packet present rather than a packet preceded by a pile of key
exchange actions), write the appropriate PGP header based on
the envelope usage */
sMemOpen( &stream, envelopeInfoPtr->buffer,
envelopeInfoPtr->bufSize );
switch( envelopeInfoPtr->usage )
{
case ACTION_SIGN:
if( !( envelopeInfoPtr->flags & ENVELOPE_DETACHED_SIG ) )
{
status = writeSignatureInfoPacket( &stream,
envelopeInfoPtr->postActionList->iCryptHandle,
envelopeInfoPtr->actionList->iCryptHandle );
if( cryptStatusError( status ) )
break;
}
/* Since we can only sign literal data, we need to
explicitly write an inner data header */
assert( envelopeInfoPtr->contentType == CRYPT_CONTENT_DATA );
envelopeInfoPtr->envState = ENVSTATE_DATA;
break;
case ACTION_NONE:
/* Write the header followed by an indicator that we're
using opaque content, a zero-length filename, and no
date */
pgpWritePacketHeader( &stream, PGP_PACKET_DATA,
envelopeInfoPtr->payloadSize + PGP_DATA_HEADER_SIZE );
swrite( &stream, PGP_DATA_HEADER, PGP_DATA_HEADER_SIZE );
break;
case ACTION_COMPRESS:
/* Compressed data packets use a special unkown-length
encoding that doesn't work like any other PGP packet
type, so we can't use pgpWritePacketHeader() for this
packet type but have to hand-assemble the header
ourselves */
sputc( &stream, PGP_CTB_COMPRESSED );
sputc( &stream, PGP_ALGO_ZLIB );
if( envelopeInfoPtr->contentType == CRYPT_CONTENT_DATA )
/* If there's no inner content type, we need to
explicitly write an inner data header */
envelopeInfoPtr->envState = ENVSTATE_DATA;
break;
default:
assert( NOTREACHED );
}
length = stell( &stream );
sMemDisconnect( &stream );
if( cryptStatusError( status ) )
return( status );
envelopeInfoPtr->bufPos = length;
/* Reset the segmentation state. Although PGP doesn't segment
the payload, we still have to reset the state to synchronise
things like payload hashing and encryption. We also set the
block size mask to all ones if we're not encrypting, since we
can begin and end data segments on arbitrary boundaries */
envelopeInfoPtr->dataFlags |= ENVDATA_SEGMENTCOMPLETE;
if( envelopeInfoPtr->usage != ACTION_CRYPT )
envelopeInfoPtr->blockSizeMask = -1;
envelopeInfoPtr->lastAction = NULL;
/* If we're not emitting any inner header, we're done */
if( envelopeInfoPtr->envState == ENVSTATE_HEADER || \
( envelopeInfoPtr->flags & ENVELOPE_DETACHED_SIG ) )
{
envelopeInfoPtr->envState = ENVSTATE_DONE;
return( CRYPT_OK );
}
}
}
/* Handle key export actions */
if( envelopeInfoPtr->envState == ENVSTATE_KEYINFO )
{
ACTION_LIST *lastActionPtr;
/* Export the session key using each of the PKC keys, or write the
derivation information needed to recreate the session key */
for( lastActionPtr = envelopeInfoPtr->lastAction;
lastActionPtr != NULL; lastActionPtr = lastActionPtr->next )
{
void *bufPtr = envelopeInfoPtr->buffer + envelopeInfoPtr->bufPos;
const int dataLeft = min( envelopeInfoPtr->bufSize - \
envelopeInfoPtr->bufPos, 8192 );
int keyexSize;
/* Make sure that there's enough room to emit this key exchange
action */
if( lastActionPtr->encodedSize + 128 > dataLeft )
{
status = CRYPT_ERROR_OVERFLOW;
break;
}
/* Emit the key exchange action */
if( lastActionPtr->action == ACTION_KEYEXCHANGE_PKC )
status = iCryptExportKeyEx( bufPtr, &keyexSize, dataLeft,
CRYPT_FORMAT_PGP, envelopeInfoPtr->iCryptContext,
lastActionPtr->iCryptHandle, CRYPT_UNUSED );
else
status = iCryptExportKeyEx( bufPtr, &keyexSize, dataLeft,
CRYPT_FORMAT_PGP, CRYPT_UNUSED,
envelopeInfoPtr->iCryptContext, CRYPT_UNUSED );
if( cryptStatusError( status ) )
break;
envelopeInfoPtr->bufPos += keyexSize;
}
envelopeInfoPtr->lastAction = lastActionPtr;
if( cryptStatusError( status ) )
return( status );
/* Move on to the next state */
envelopeInfoPtr->envState = ENVSTATE_ENCRINFO;
}
/* Handle encrypted content information */
if( envelopeInfoPtr->envState == ENVSTATE_ENCRINFO )
{
STREAM stream;
BYTE ivInfoBuffer[ CRYPT_MAX_IVSIZE + 2 ];
const int dataLeft = min( envelopeInfoPtr->bufSize - \
envelopeInfoPtr->bufPos, 8192 );
int length;
/* Make sure that there's enough room to emit the encrypted content
header (+4 for slop space) */
if( dataLeft < PGP_MAX_HEADER_SIZE + PGP_IVSIZE + 2 + 4 )
return( CRYPT_ERROR_OVERFLOW );
/* Set up the PGP IV information */
status = pgpProcessIV( envelopeInfoPtr->iCryptContext,
ivInfoBuffer, PGP_IVSIZE, TRUE, TRUE );
if( cryptStatusError( status ) )
return( status );
/* Write the encrypted content header */
sMemOpen( &stream, envelopeInfoPtr->buffer + \
envelopeInfoPtr->bufPos, dataLeft );
pgpWritePacketHeader( &stream, PGP_PACKET_ENCR,
PGP_IVSIZE + 2 + 1 + \
pgpSizeofLength( PGP_DATA_HEADER_SIZE + \
envelopeInfoPtr->payloadSize ) + \
PGP_DATA_HEADER_SIZE + \
envelopeInfoPtr->payloadSize );
status = swrite( &stream, ivInfoBuffer, PGP_IVSIZE + 2 );
length = stell( &stream );
sMemDisconnect( &stream );
if( cryptStatusError( status ) )
return( status );
envelopeInfoPtr->bufPos += length;
/* Make sure that we start a new segment if we try to add any data */
envelopeInfoPtr->dataFlags |= ENVDATA_SEGMENTCOMPLETE;
/* Before we can finish we have to push in the inner data header */
envelopeInfoPtr->envState = ENVSTATE_DATA;
}
/* Handle data payload information */
if( envelopeInfoPtr->envState == ENVSTATE_DATA )
{
STREAM stream;
BYTE headerBuffer[ 64 ];
/* Make sure that there's enough room to emit the data header (+4
for slop space) */
if( envelopeInfoPtr->bufSize - envelopeInfoPtr->bufPos < \
PGP_MAX_HEADER_SIZE + PGP_DATA_HEADER_SIZE + 4 )
return( CRYPT_ERROR_OVERFLOW );
/* Write the payload header. Since this may be encrypted, we have to
do it indirectly via copyToEnvelope() */
sMemOpen( &stream, headerBuffer, 64 );
pgpWritePacketHeader( &stream, PGP_PACKET_DATA,
PGP_DATA_HEADER_SIZE + envelopeInfoPtr->payloadSize );
swrite( &stream, PGP_DATA_HEADER, PGP_DATA_HEADER_SIZE );
if( envelopeInfoPtr->payloadSize != CRYPT_UNUSED )
/* There's an absolute data length set, adjust the running total
count by the size of the additional header that's been
prepended */
envelopeInfoPtr->segmentSize += stell( &stream );
status = envelopeInfoPtr->copyToEnvelopeFunction( envelopeInfoPtr,
headerBuffer, stell( &stream ) );
sMemClose( &stream );
if( cryptStatusError( status ) )
return( status );
/* We've processed the header, if this is signed data we start
hashing from this point. The PGP RFCs are wrong in this regard,
only the payload is hashed, not the entire packet */
if( envelopeInfoPtr->usage == ACTION_SIGN )
envelopeInfoPtr->dataFlags |= ENVDATA_HASHACTIONSACTIVE;
/* We're finished */
envelopeInfoPtr->envState = ENVSTATE_DONE;
}
return( CRYPT_OK );
}
/* Output as much of the postamble as possible into the envelope buffer */
static int emitPostamble( ENVELOPE_INFO *envelopeInfoPtr )
{
int sigBufSize, sigSize, status;
/* Before we can emit the trailer we need to flush any remaining data
from internal buffers */
if( envelopeInfoPtr->envState == ENVSTATE_NONE )
{
status = envelopeInfoPtr->copyToEnvelopeFunction( envelopeInfoPtr,
( BYTE * ) "", 0 );
if( cryptStatusError( status ) )
return( status );
envelopeInfoPtr->envState = ENVSTATE_FLUSHED;
}
/* The only PGP packet that has a trailer is signed data using the new
(post-2.x) one-pass signature packet, if we're not signing data we can
exit now */
if( envelopeInfoPtr->usage != ACTION_SIGN )
{
/* We're done */
envelopeInfoPtr->envState = ENVSTATE_DONE;
return( CRYPT_OK );
}
/* Check whether there's enough room left in the buffer to emit the
signature directly into it. Since sigs are fairly small (a few
hundred bytes), we always require enough room in the buffer and don't
bother with any overflow handling via the auxBuffer */
sigBufSize = min( envelopeInfoPtr->bufSize - envelopeInfoPtr->bufPos,
8192 );
if( envelopeInfoPtr->postActionList->encodedSize + 64 > sigBufSize )
return( CRYPT_ERROR_OVERFLOW );
/* Sign the data */
status = iCryptCreateSignatureEx( envelopeInfoPtr->buffer + \
envelopeInfoPtr->bufPos, &sigSize,
sigBufSize, CRYPT_FORMAT_PGP,
envelopeInfoPtr->postActionList->iCryptHandle,
envelopeInfoPtr->actionList->iCryptHandle,
CRYPT_UNUSED, CRYPT_UNUSED );
if( cryptStatusError( status ) )
return( status );
envelopeInfoPtr->bufPos += sigSize;
/* Now that we've written the final data, set the end-of-segment-data
pointer to the end of the data in the buffer so that
copyFromEnvelope() can copy out the remaining data */
envelopeInfoPtr->segmentDataEnd = envelopeInfoPtr->bufPos;
envelopeInfoPtr->envState = ENVSTATE_DONE;
return( CRYPT_OK );
}
/****************************************************************************
* *
* Envelope Access Routines *
* *
****************************************************************************/
void initPGPEnveloping( ENVELOPE_INFO *envelopeInfoPtr )
{
/* Set the access method pointers */
envelopeInfoPtr->processPreambleFunction = emitPreamble;
envelopeInfoPtr->processPostambleFunction = emitPostamble;
envelopeInfoPtr->checkCryptAlgo = checkCryptAlgo;
envelopeInfoPtr->checkHashAlgo = checkHashAlgo;
/* Set up the processing state information */
envelopeInfoPtr->envState = ENVSTATE_NONE;
/* Remember the current default settings for use with the envelope.
Since the PGP algorithms represent only a subset of what's available,
we have to drop back to fixed values if the caller has selected
something exotic */
krnlSendMessage( envelopeInfoPtr->ownerHandle,
IMESSAGE_GETATTRIBUTE, &envelopeInfoPtr->defaultHash,
CRYPT_OPTION_ENCR_HASH );
if( cryptlibToPgpAlgo( envelopeInfoPtr->defaultHash ) == PGP_ALGO_NONE )
envelopeInfoPtr->defaultHash = CRYPT_ALGO_SHA;
krnlSendMessage( envelopeInfoPtr->ownerHandle,
IMESSAGE_GETATTRIBUTE, &envelopeInfoPtr->defaultAlgo,
CRYPT_OPTION_ENCR_ALGO );
if( cryptlibToPgpAlgo( envelopeInfoPtr->defaultAlgo ) == PGP_ALGO_NONE )
envelopeInfoPtr->defaultAlgo = CRYPT_ALGO_3DES;
envelopeInfoPtr->defaultMAC = CRYPT_ALGO_NONE;
/* Turn off segmentation of the envelope payload. PGP has a single
length at the start of the data and doesn't segment the payload */
envelopeInfoPtr->dataFlags |= ENVDATA_NOSEGMENT;
}
#endif /* USE_PGP */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -