📄 pgp_denv.c
字号:
break;
case PGP_PACKET_COPR:
value = sgetc( &stream );
if( envelopeInfoPtr->usage != ACTION_NONE )
{
status = CRYPT_ERROR_BADDATA;
break;
}
envelopeInfoPtr->usage = ACTION_COMPRESS;
#ifdef USE_COMPRESSION
if( value == PGP_ALGO_ZIP )
{
/* PGP 2.x has a funny compression level based on DOS
memory limits (13-bit windows) and no zlib header
(because it uses very old InfoZIP code). Setting
the windowSize to a negative value has the
undocumented effect of not reading zlib headers */
if( inflateInit2( &envelopeInfoPtr->zStream, -13 ) == Z_OK )
envelopeInfoPtr->flags |= ENVELOPE_ZSTREAMINITED;
else
status = CRYPT_ERROR_MEMORY;
}
else
if( value == PGP_ALGO_ZLIB )
{
/* Standard zlib compression */
if( inflateInit( &envelopeInfoPtr->zStream ) == Z_OK )
envelopeInfoPtr->flags |= ENVELOPE_ZSTREAMINITED;
else
status = CRYPT_ERROR_MEMORY;
}
else
{
status = ( value < 0 ) ? \
value : CRYPT_ERROR_NOTAVAIL;
break;
}
#else
status = CRYPT_ERROR_NOTAVAIL;
#endif /* USE_COMPRESSION */
state = PGP_DEENVSTATE_DATA;
break;
case PGP_PACKET_SKE:
case PGP_PACKET_PKE:
/* Read the SKE/PKE packet */
if( envelopeInfoPtr->usage != ACTION_NONE && \
envelopeInfoPtr->usage != ACTION_CRYPT )
{
status = CRYPT_ERROR_BADDATA;
break;
}
envelopeInfoPtr->usage = ACTION_CRYPT;
sseek( &stream, streamPos );
status = addContentListItem( &stream, envelopeInfoPtr,
FALSE );
break;
case PGP_PACKET_SIGNATURE:
case PGP_PACKET_SIGNATURE_ONEPASS:
/* Try and guess whether this is a standalone signature.
This is rather difficult since, unlike S/MIME, there's
no way to tell whether a PGP signature packet is part
of other data or standalone. The best we can do is
assume that if the caller added a hash action and we
find a signature, it's a detached signature.
Unfortunately there's no way to tell whether a
signature packet with no user-supplied hash is a
standalone signature or the start of further signed
data, so we can't handle detached signatures where the
user doesn't supply the hash */
if( envelopeInfoPtr->usage == ACTION_SIGN && \
envelopeInfoPtr->actionList != NULL && \
envelopeInfoPtr->actionList->action == ACTION_HASH )
{
/* We can't have a detached sig packet as a one-pass
sig */
if( packetType == PGP_PACKET_SIGNATURE_ONEPASS )
{
status = CRYPT_ERROR_BADDATA;
break;
}
envelopeInfoPtr->flags |= ENVELOPE_DETACHED_SIG;
}
/* Read the signature/signature information packet. We
allow the usage to be set already if we find a
signature packet since it could have been preceded by
a one-pass signature packet or be a detached
signature */
if( envelopeInfoPtr->usage != ACTION_NONE && \
!( packetType == PGP_PACKET_SIGNATURE && \
envelopeInfoPtr->usage == ACTION_SIGN ) )
{
status = CRYPT_ERROR_BADDATA;
break;
}
envelopeInfoPtr->usage = ACTION_SIGN;
sseek( &stream, streamPos );
status = addContentListItem( &stream, envelopeInfoPtr,
FALSE );
if( cryptStatusError( status ) )
break;
if( envelopeInfoPtr->flags & ENVELOPE_DETACHED_SIG )
{
/* If it's a one-pass sig, there's no payload
present, we can go straight to the postdata
state */
envelopeInfoPtr->dataFlags |= ENVDATA_HASHACTIONSACTIVE;
envelopeInfoPtr->payloadSize = 0;
state = PGP_DEENVSTATE_DONE;
}
else
state = PGP_DEENVSTATE_DATA;
break;
case PGP_PACKET_ENCR_MDC:
/* The encrypted-data-with-MDC packet is preceded by a
version number */
status = sgetc( &stream );
if( !cryptStatusError( status ) && status != 1 )
status = CRYPT_ERROR_BADDATA;
if( cryptStatusError( status ) )
break;
packetLength--;
/* Fall through */
case PGP_PACKET_ENCR:
if( envelopeInfoPtr->usage != ACTION_NONE && \
envelopeInfoPtr->usage != ACTION_CRYPT )
{
status = CRYPT_ERROR_BADDATA;
break;
}
/* Remember the packet length in case the inner packet
uses an indefinite-length encoding */
if( packetLength != CRYPT_UNUSED )
envelopeInfoPtr->payloadSize = packetLength;
envelopeInfoPtr->usage = ACTION_CRYPT;
state = ( packetType == PGP_PACKET_ENCR_MDC ) ? \
PGP_DEENVSTATE_ENCR_MDC : PGP_DEENVSTATE_ENCR;
break;
case PGP_PACKET_MARKER:
/* Obsolete marker packet, skip it */
status = sSkip( &stream, packetLength );
break;
default:
status = CRYPT_ERROR_BADDATA;
}
/* If there's a problem, exit */
if( cryptStatusError( status ) )
break;
/* Remember how far we got */
streamPos = stell( &stream );
}
/* Process the start of an encrypted data packet */
if( state == PGP_DEENVSTATE_ENCR || \
state == PGP_DEENVSTATE_ENCR_MDC )
{
BYTE ivInfoBuffer[ CRYPT_MAX_IVSIZE + 2 ];
int ivSize;
/* If there aren't any non-session-key keying resource objects
present, we can't go any further until we get a session key */
if( envelopeInfoPtr->actionList == NULL )
{
/* There's no session key object present, add a pseudo-object
that takes the place of the (password-derived) session key
object in the content list. This can only occur for PGP
2.x conventionally-encrypted data, which didn't encode any
algorithm information with the data, so if we get to this
point we know we've hit data encrypted with the default
IDEA/CFB derived from a user password using MD5 */
if( envelopeInfoPtr->contentList == NULL )
{
status = addContentListItem( NULL, envelopeInfoPtr, FALSE );
if( cryptStatusError( status ) )
break;
}
/* We can't continue until we're given some sort of keying
resource */
status = CRYPT_ENVELOPE_RESOURCE;
break;
}
assert( envelopeInfoPtr->actionList->action == ACTION_CRYPT );
/* Read and process PGP's peculiar two-stage IV */
status = krnlSendMessage( envelopeInfoPtr->actionList->iCryptHandle,
IMESSAGE_GETATTRIBUTE, &ivSize,
CRYPT_CTXINFO_IVSIZE );
if( cryptStatusOK( status ) )
status = sread( &stream, ivInfoBuffer, ivSize + 2 );
if( !cryptStatusError( status ) )
status = pgpProcessIV( envelopeInfoPtr->actionList->iCryptHandle,
ivInfoBuffer, ivSize, FALSE,
( state == PGP_DEENVSTATE_ENCR ) ? \
TRUE : FALSE );
if( cryptStatusError( status ) )
break;
envelopeInfoPtr->iCryptContext = \
envelopeInfoPtr->actionList->iCryptHandle;
/* If we're keeping track of the outer packet size in case
there's no inner size info present, adjust it by the data
we've just processed and any other data that may be
present */
if( envelopeInfoPtr->payloadSize != CRYPT_UNUSED )
{
envelopeInfoPtr->payloadSize -= stell( &stream );
if( state == PGP_DEENVSTATE_ENCR_MDC )
/* There was a bug in all versions of GPG before 1.0.8,
which omitted the MDC packet length when a packet was
encrypted without compression. As a result,
uncompressed messages generated by this version can't
be processed */
envelopeInfoPtr->payloadSize -= PGP_MDC_PACKET_SIZE;
}
/* If there's an MDC packet present, prepare to hash the payload
data */
if( state == PGP_DEENVSTATE_ENCR_MDC )
{
MESSAGE_CREATEOBJECT_INFO createInfo;
/* Append a hash action to the action list */
setMessageCreateObjectInfo( &createInfo, CRYPT_ALGO_SHA );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
IMESSAGE_DEV_CREATEOBJECT,
&createInfo, OBJECT_TYPE_CONTEXT );
if( cryptStatusError( status ) )
break;
if( addAction( &envelopeInfoPtr->actionList,
envelopeInfoPtr->memPoolState, ACTION_HASH,
createInfo.cryptHandle ) == NULL )
{
krnlSendNotifier( createInfo.cryptHandle,
IMESSAGE_DECREFCOUNT );
status = CRYPT_ERROR_MEMORY;
break;
}
envelopeInfoPtr->dataFlags |= ENVDATA_HASHACTIONSACTIVE;
}
/* Remember where we are and move on to the next state */
streamPos = stell( &stream );
state = PGP_DEENVSTATE_DATA;
}
/* Process the start of a data packet */
if( state == PGP_DEENVSTATE_DATA )
{
/* Synchronise the data stream processing to the start of the
encrypted data and move back to the start of the data
stream */
status = envelopeInfoPtr->syncDeenvelopeData( envelopeInfoPtr,
&stream );
if( cryptStatusError( status ) )
break;
streamPos = 0;
assert( actionsOK( envelopeInfoPtr ) );
/* Move on to the next state. For plain data we're done,
however for other content types we have to either process or
strip out the junk PGP puts at the start of the content */
if( envelopeInfoPtr->usage != ACTION_NONE )
{
envelopeInfoPtr->oobEventCount = 1;
state = PGP_DEENVSTATE_DATA_HEADER;
}
else
state = PGP_DEENVSTATE_DONE;
assert( actionsOK( envelopeInfoPtr ) );
}
/* PGP doesn't provide any indication of what the content of the
current packet is, so we have to burrow down into the encrypted
data to see whether the payload needs any further processing.
This state looks ahead into this data to see whether we need to
strip the header (for a plain data packet) or inform the user
that there's a nested content type */
if( state == PGP_DEENVSTATE_DATA_HEADER )
{
STREAM headerStream;
BYTE buffer[ 64 + 256 ];
int bytesWanted;
/* If there's no out-of-band data left to remove at the start of
the payload, we're done */
if( !envelopeInfoPtr->oobEventCount && \
!envelopeInfoPtr->oobDataLeft )
break;
/* We have to perform all sorts of special-case processing to
handle the out-of-band packet header at the start of the
payload. Initially, we need to find out how much header data
is actually present. The header consists of:
byte ctb
byte[] length
byte type = 'b' | 't'
byte filename length
byte[] filename
byte[4] timestamp
The smallest size for this header (1-byte length, no filename)
is 1 + 1 + 1 + 1 + 4 = 8 bytes. This is also just enough to
get us to the filename length for a maximum-size header, which
is 1 + 5 + 1 + 1 bytes up to the filename length. Thus we
read 8 bytes */
bytesWanted = envelopeInfoPtr->oobEventCount ? \
-8 : envelopeInfoPtr->oobDataLeft;
/* Try and read the the requested amount of out-of-band data
from the start of the payload */
length = envelopeInfoPtr->copyFromEnvelopeFunction( envelopeInfoPtr,
buffer, bytesWanted );
if( cryptStatusError( length ) )
status = length;
else
if( length < \
( ( bytesWanted >= 0 ) ? bytesWanted : -bytesWanted ) )
status = CRYPT_ERROR_UNDERFLOW;
if( cryptStatusError( status ) )
break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -