📄 env_pgp.c
字号:
/****************************************************************************
* *
* cryptlib PGP Enveloping Routines *
* Copyright Peter Gutmann 1996-2003 *
* *
****************************************************************************/
#include <stdlib.h>
#include <string.h>
#if defined( INC_ALL )
#include "envelope.h"
#include "pgp.h"
#include "misc_rw.h"
#elif defined( INC_CHILD )
#include "envelope.h"
#include "pgp.h"
#include "../misc/misc_rw.h"
#else
#include "envelope/envelope.h"
#include "envelope/pgp.h"
#include "misc/misc_rw.h"
#endif /* Compiler-specific includes */
#ifdef USE_PGP
/****************************************************************************
* *
* Utility Routines *
* *
****************************************************************************/
/* Check that a requested algorithm type is valid with PGP data */
static int checkCryptAlgo( const CRYPT_ALGO_TYPE cryptAlgo,
const CRYPT_ALGO_TYPE cryptMode )
{
return( ( cryptlibToPgpAlgo( cryptAlgo ) != CRYPT_ALGO_NONE && \
cryptMode == CRYPT_MODE_CFB ) ? \
CRYPT_OK : CRYPT_ERROR_NOTAVAIL );
}
static int checkHashAlgo( const CRYPT_ALGO_TYPE hashAlgo )
{
return( ( cryptlibToPgpAlgo( hashAlgo ) != CRYPT_ALGO_NONE ) ? \
CRYPT_OK : CRYPT_ERROR_NOTAVAIL );
}
/****************************************************************************
* *
* Write Key Exchange/Signature Packets *
* *
****************************************************************************/
/* One-pass signature info:
byte version = 3
byte sigType
byte hashAlgo
byte sigAlgo
byte[8] keyID
byte 1
This is additional header data written at the start of a block of signed
data, so we can't write it as part of the standard PGP packet read/write
routines */
static int writeSignatureInfoPacket( STREAM *stream,
const CRYPT_CONTEXT iSignContext,
const CRYPT_CONTEXT iHashContext )
{
CRYPT_ALGO_TYPE hashAlgo, signAlgo;
BYTE keyID[ PGP_KEYID_SIZE ];
int status;
/* Get the signature information */
status = krnlSendMessage( iHashContext, IMESSAGE_GETATTRIBUTE,
&hashAlgo, CRYPT_CTXINFO_ALGO );
if( cryptStatusOK( status ) )
status = krnlSendMessage( iSignContext, IMESSAGE_GETATTRIBUTE,
&signAlgo, CRYPT_CTXINFO_ALGO );
if( cryptStatusOK( status ) )
{
RESOURCE_DATA msgData;
setMessageData( &msgData, keyID, PGP_KEYID_SIZE );
status = krnlSendMessage( iSignContext, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_IATTRIBUTE_KEYID_OPENPGP );
}
if( cryptStatusError( status ) )
return( status );
/* Write the signature info packet */
pgpWritePacketHeader( stream, PGP_PACKET_SIGNATURE_ONEPASS, \
1 + 1 + 1 + 1 + PGP_KEYID_SIZE + 1 );
sputc( stream, 3 ); /* Version = 3 (OpenPGP) */
sputc( stream, 0 ); /* Binary document sig. */
sputc( stream, cryptlibToPgpAlgo( hashAlgo ) );
sputc( stream, cryptlibToPgpAlgo( signAlgo ) );
swrite( stream, keyID, PGP_KEYID_SIZE );
return( sputc( stream, 1 ) );
}
/****************************************************************************
* *
* Envelope Pre/Post-processing Functions *
* *
****************************************************************************/
/* The following functions take care of pre/post-processing of envelope data
during the enveloping process */
static int preEnvelopeEncrypt( ENVELOPE_INFO *envelopeInfoPtr )
{
CRYPT_DEVICE iCryptDevice = CRYPT_ERROR;
ACTION_LIST *actionListPtr;
int status;
/* Create the session key if necessary */
if( envelopeInfoPtr->actionList == NULL )
{
MESSAGE_CREATEOBJECT_INFO createInfo;
static const CRYPT_MODE_TYPE mode = CRYPT_MODE_CFB;
/* Create a default encryption action and add it to the action
list */
setMessageCreateObjectInfo( &createInfo,
envelopeInfoPtr->defaultAlgo );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
IMESSAGE_DEV_CREATEOBJECT,
&createInfo, OBJECT_TYPE_CONTEXT );
if( cryptStatusError( status ) )
return( status );
if( envelopeInfoPtr->defaultAlgo == CRYPT_ALGO_BLOWFISH )
{
static const int keySize = 16;
/* If we're using an algorithm with a variable-length key,
restrict it to a fixed length. There shouldn't be any need
for this because the key length is communicated as part of
the wrapped key, but some implementations choke if it's not
exactly 128 bits */
krnlSendMessage( createInfo.cryptHandle, IMESSAGE_SETATTRIBUTE,
( void * ) &keySize, CRYPT_CTXINFO_KEYSIZE );
}
krnlSendMessage( createInfo.cryptHandle, IMESSAGE_SETATTRIBUTE,
( void * ) &mode, CRYPT_CTXINFO_MODE );
status = krnlSendMessage( createInfo.cryptHandle,
IMESSAGE_CTX_GENKEY, NULL, FALSE );
if( cryptStatusOK( status ) && \
addAction( &envelopeInfoPtr->actionList,
envelopeInfoPtr->memPoolState, ACTION_CRYPT,
createInfo.cryptHandle ) == NULL )
status = CRYPT_ERROR_MEMORY;
if( cryptStatusError( status ) )
{
krnlSendNotifier( createInfo.cryptHandle,
IMESSAGE_DECREFCOUNT );
return( status );
}
}
else
{
/* If the session key context is tied to a device, get its handle so
we can check that all key exchange objects are also in the same
device */
status = krnlSendMessage( envelopeInfoPtr->actionList->iCryptHandle,
MESSAGE_GETDEPENDENT, &iCryptDevice,
OBJECT_TYPE_DEVICE );
if( cryptStatusError( status ) )
iCryptDevice = CRYPT_ERROR;
}
/* Notify the kernel that the session key context is attached to the
envelope. This is an internal object used only by the envelope so we
tell the kernel not to increment its reference count when it attaches
it */
krnlSendMessage( envelopeInfoPtr->objectHandle, IMESSAGE_SETDEPENDENT,
&envelopeInfoPtr->actionList->iCryptHandle,
SETDEP_OPTION_NOINCREF );
/* Now walk down the list of key exchange actions connecting each one to
the session key action */
for( actionListPtr = findAction( envelopeInfoPtr->preActionList,
ACTION_KEYEXCHANGE_PKC );
actionListPtr != NULL && \
actionListPtr->action == ACTION_KEYEXCHANGE_PKC;
actionListPtr = actionListPtr->next )
{
/* If the session key context is tied to a device, make sure that
the key exchange object is in the same device */
if( iCryptDevice != CRYPT_ERROR )
{
CRYPT_DEVICE iKeyexDevice;
status = krnlSendMessage( actionListPtr->iCryptHandle,
MESSAGE_GETDEPENDENT, &iKeyexDevice,
OBJECT_TYPE_DEVICE );
if( cryptStatusError( status ) || iCryptDevice != iKeyexDevice )
return( CRYPT_ERROR_INVALID );
}
/* Remember that we now have a controlling action and connect the
controller to the subject */
envelopeInfoPtr->actionList->flags &= ~ACTION_NEEDSCONTROLLER;
actionListPtr->associatedAction = envelopeInfoPtr->actionList;
/* Evaluate the size of the exported action. We only get PKC
actions at this point so we don't have to provide any special-
case handling for other key exchange types */
status = iCryptExportKeyEx( NULL, &actionListPtr->encodedSize, 0,
CRYPT_FORMAT_PGP,
envelopeInfoPtr->actionList->iCryptHandle,
actionListPtr->iCryptHandle, CRYPT_UNUSED );
if( cryptStatusError( status ) )
return( status );
}
return( CRYPT_OK );
}
static int preEnvelopeSign( ENVELOPE_INFO *envelopeInfoPtr )
{
ACTION_LIST *actionListPtr = envelopeInfoPtr->postActionList;
/* Evaluate the size of the signature action */
return( iCryptCreateSignatureEx( NULL, &actionListPtr->encodedSize, 0,
CRYPT_FORMAT_PGP, actionListPtr->iCryptHandle,
envelopeInfoPtr->actionList->iCryptHandle,
CRYPT_UNUSED, CRYPT_UNUSED ) );
}
/****************************************************************************
* *
* Emit Envelope Preamble/Postamble *
* *
****************************************************************************/
/* Output as much of the preamble as possible into the envelope buffer */
static int emitPreamble( ENVELOPE_INFO *envelopeInfoPtr )
{
int status = CRYPT_OK;
/* If we've finished processing the header information, don't do
anything */
if( envelopeInfoPtr->envState == ENVSTATE_DONE )
return( CRYPT_OK );
/* If we haven't started doing anything yet, perform various final
initialisations */
if( envelopeInfoPtr->envState == ENVSTATE_NONE )
{
/* If there's no nested content type set, default to plain data */
if( envelopeInfoPtr->contentType == CRYPT_CONTENT_NONE )
envelopeInfoPtr->contentType = CRYPT_CONTENT_DATA;
/* Perform any remaining initialisation. Since PGP derives the
session key directly from the user password, we only perform this
initialisation if there are PKC key exchange actions present */
if( envelopeInfoPtr->usage == ACTION_CRYPT && \
findAction( envelopeInfoPtr->preActionList,
ACTION_KEYEXCHANGE_PKC ) != NULL )
status = preEnvelopeEncrypt( envelopeInfoPtr );
else
if( envelopeInfoPtr->usage == ACTION_SIGN )
status = preEnvelopeSign( envelopeInfoPtr );
if( cryptStatusError( status ) )
return( status );
/* Delete any orphaned actions such as automatically-added hash
actions that were overridden with user-supplied alternate
actions */
deleteUnusedActions( envelopeInfoPtr );
/* We're ready to go, prepare to emit the outer header */
envelopeInfoPtr->envState = ENVSTATE_HEADER;
assert( actionsOK( envelopeInfoPtr ) );
}
/* Emit the outer header. This always follows directly from the final
initialisation step, but we keep the two logically distinct to
emphasise that the former is merely finalised enveloping actions
without performing any header processing, while the latter is that
first stage that actually emits header data */
if( envelopeInfoPtr->envState == ENVSTATE_HEADER )
{
/* If we're encrypting, set up the encryption-related information.
Since PGP doesn't perform a key exchange of a session key when
conventionally-encrypting data, the encryption information could
be coming from either an encryption action (derived from a
password) or a conventional key exchange action that results in
the direct creation of a session encryption key */
if( envelopeInfoPtr->usage == ACTION_CRYPT )
{
status = initEnvelopeEncryption( envelopeInfoPtr,
envelopeInfoPtr->actionList->iCryptHandle,
CRYPT_UNUSED, CRYPT_UNUSED, NULL, 0, FALSE );
if( cryptStatusError( status ) )
return( status );
/* Prepare to start emitting the key exchange (PKC-encrypted) or
session key (conventionally encrypted) actions */
envelopeInfoPtr->lastAction = \
findAction( envelopeInfoPtr->preActionList,
ACTION_KEYEXCHANGE_PKC );
if( envelopeInfoPtr->lastAction == NULL )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -