📄 pgp_env.c
字号:
/****************************************************************************
* *
* cryptlib PGP Enveloping Routines *
* Copyright Peter Gutmann 1996-2002 *
* *
****************************************************************************/
#include <stdlib.h>
#include <string.h>
#include <time.h>
#if defined( INC_ALL )
#include "envelope.h"
#include "pgp.h"
#elif defined( INC_CHILD )
#include "../envelope/envelope.h"
#include "../envelope/pgp.h"
#else
#include "envelope/envelope.h"
#include "envelope/pgp.h"
#endif /* Compiler-specific includes */
/* Prototypes for functions in envelope.c */
int copyFromAuxBuffer( ENVELOPE_INFO *envelopeInfoPtr );
int copyFromAuxStream( ENVELOPE_INFO *envelopeInfoPtr );
/****************************************************************************
* *
* Utility Routines *
* *
****************************************************************************/
/* Check that a requested algorithm type is valid with PGP data */
static int checkCryptAlgo( const CRYPT_ALGO cryptAlgo,
const CRYPT_ALGO cryptMode )
{
return( ( isPGPCryptAlgo( cryptAlgo ) && cryptMode == CRYPT_MODE_CFB ) ? \
CRYPT_OK : CRYPT_ERROR_NOTAVAIL );
}
static int checkHashAlgo( const CRYPT_ALGO hashAlgo )
{
return( isPGPHashAlgo( hashAlgo ) ? CRYPT_OK : CRYPT_ERROR_NOTAVAIL );
}
/****************************************************************************
* *
* Write Key Exchange/Signature Packets *
* *
****************************************************************************/
/* Write a PGP packet header */
static int writePacketHeader( STREAM *stream, const int packetType,
const long length )
{
#if 0 /* PGP 2.x */
/* Write the CTB and length */
if( length <= 0xFF )
{
sputc( stream, PGP_CTB | ( packetType << 2 ) );
return( sputc( stream, length ) );
}
if( length <= 0xFFFF )
{
sputc( stream, PGP_CTB | ( packetType << 2 ) | 0x01 );
sputc( stream, ( length >> 8 ) & 0xFF );
return( sputc( stream, ( length & 0xFF ) ) );
}
sputc( stream, PGP_CTB | ( packetType << 2 ) | 0x02 );
sputc( stream, ( length >> 24 ) & 0xFF );
sputc( stream, ( length >> 16 ) & 0xFF );
sputc( stream, ( length >> 8 ) & 0xFF );
return( sputc( stream, ( length & 0xFF ) ) );
#else /* OpenPGP */
if( packetType == PGP_PACKET_COPR )
/* Compressed data packets use a special unkown-length encoding
which doesn't work like any other PGP packet type */
return( sputc( stream, PGP_CTB_COMPRESSED ) );
if( packetType )
sputc( stream, PGP_CTB_OPENPGP | packetType );
if( length <= 191 )
return( sputc( stream, length ) );
if( length <= 8383 )
{
sputc( stream, ( ( length >> 8 ) & 0xFF ) + 192 );
return( sputc( stream, ( length & 0xFF ) ) );
}
sputc( stream, 0xFF );
sputc( stream, ( length >> 24 ) & 0xFF );
sputc( stream, ( length >> 16 ) & 0xFF );
sputc( stream, ( length >> 8 ) & 0xFF );
return( sputc( stream, ( length & 0xFF ) ) );
#endif /* 0 */
}
static int sizeofPacketHeader( const long length )
{
#if 0 /* PGP 2.x */
return( ( length <= 0xFF ) ? 2 : ( length <= 0xFFFF ) ? 3 : 5 );
#else /* OpenPGP */
return( ( length <= 191 ) ? 2 : ( length <= 8383 ) ? 3 : 5 );
#endif /* 0 */
}
/* Write various cryptlib algorithm types as PGP algorithm IDs */
static int writeHashAlgorithmID( STREAM *stream, const CRYPT_ALGO cryptAlgo )
{
switch( cryptAlgo )
{
case CRYPT_ALGO_MD2:
return( sputc( stream, PGP_ALGO_MD2 ) );
case CRYPT_ALGO_MD5:
return( sputc( stream, PGP_ALGO_MD5 ) );
case CRYPT_ALGO_SHA:
return( sputc( stream, PGP_ALGO_SHA ) );
case CRYPT_ALGO_RIPEMD160:
return( sputc( stream, PGP_ALGO_RIPEMD160 ) );
}
assert( NOTREACHED );
return( CRYPT_ERROR ); /* Get rid of compiler warning */
}
static int writeCryptAlgorithmID( STREAM *stream,
const CRYPT_ALGO cryptAlgo )
{
switch( cryptAlgo )
{
case CRYPT_ALGO_3DES:
return( sputc( stream, PGP_ALGO_3DES ) );
case CRYPT_ALGO_AES:
return( sputc( stream, PGP_ALGO_AES_128 ) );
case CRYPT_ALGO_BLOWFISH:
return( sputc( stream, PGP_ALGO_BLOWFISH ) );
case CRYPT_ALGO_CAST:
return( sputc( stream, PGP_ALGO_CAST5 ) );
case CRYPT_ALGO_IDEA:
return( sputc( stream, PGP_ALGO_IDEA ) );
}
assert( NOTREACHED );
return( CRYPT_ERROR ); /* Get rid of compiler warning */
}
/* Write various PGP packets.
SKE: byte version = 4
byte cryptAlgo
byte stringToKey specifier
byte[] stringToKey data */
static int writeSKEPacket( STREAM *stream, const CRYPT_CONTEXT iCryptContext )
{
CRYPT_ALGO hashAlgo, cryptAlgo;
BYTE salt[ CRYPT_MAX_HASHSIZE ];
int keySetupIterations, count = 0, status;
/* Get the key derivation information */
status = krnlSendMessage( iCryptContext,
RESOURCE_IMESSAGE_GETATTRIBUTE,
&keySetupIterations, CRYPT_CTXINFO_KEYING_ITERATIONS );
if( cryptStatusOK( status ) )
status = krnlSendMessage( iCryptContext,
RESOURCE_IMESSAGE_GETATTRIBUTE,
&hashAlgo, CRYPT_CTXINFO_KEYING_ALGO );
if( cryptStatusOK( status ) )
status = krnlSendMessage( iCryptContext,
RESOURCE_IMESSAGE_GETATTRIBUTE,
&cryptAlgo, CRYPT_CTXINFO_ALGO );
if( cryptStatusOK( status ) )
{
RESOURCE_DATA msgData;
setResourceData( &msgData, salt, CRYPT_MAX_HASHSIZE );
status = krnlSendMessage( iCryptContext,
RESOURCE_IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_CTXINFO_KEYING_SALT );
}
if( cryptStatusError( status ) )
return( status );
/* Calculate the PGP "iteration count" from the value used to derive
the key. The "iteration count" is actually a count of how many bytes
are hashed, this is because the "iterated hashing" treats the salt +
password as an infinitely-repeated sequence of values and hashes the
resulting string for PGP-iteration-count bytes worth. Instead of
being written directly the count is encoded in a complex manner which
saves a whole byte, so before we can write it we have to encode it
into the base + exponent form expected by PGP. This has a default
base of 16 + the user-supplied base value, we can set this to zero
since the iteration count used by cryptlib is always a multiple of
16, the remainder is just log2 of what's left of the iteration
count */
assert( keySetupIterations % 16 == 0 );
keySetupIterations /= 32; /* Remove fixed offset before log2 op.*/
while( keySetupIterations )
{
count++;
keySetupIterations >>= 1;
}
count <<= 4; /* Exponent comes first */
/* Write the SKE packet */
writePacketHeader( stream, PGP_PACKET_SKE, 4 + PGP_SALTSIZE + 1 );
sputc( stream, 4 ); /* Version = 4 (OpenPGP) */
writeCryptAlgorithmID( stream, cryptAlgo );
sputc( stream, 3 ); /* S2K = salted, iterated hash */
writeHashAlgorithmID( stream, hashAlgo );
swrite( stream, salt, PGP_SALTSIZE );
return( sputc( stream, count ) );
}
/* PKE: byte version = 2 or 3
byte[8] keyID
byte PKC algo
mpi(s) encrypted session key */
static int writePKEPacket( STREAM *stream,
const CRYPT_CONTEXT iSessionKeyContext,
const CRYPT_CONTEXT iExportContext )
{
CRYPT_ALGO cryptAlgo;
MECHANISM_WRAP_INFO mechanismInfo;
BYTE buffer[ ( CRYPT_MAX_PKCSIZE * 2 ) + 64 ], *bufPtr = buffer;
BYTE keyID[ PGP_KEYID_SIZE ];
int bufSize = CRYPT_MAX_PKCSIZE, wrappedKeySize, status;
/* Get the key information */
status = krnlSendMessage( iExportContext,
RESOURCE_IMESSAGE_GETATTRIBUTE,
&cryptAlgo, CRYPT_CTXINFO_ALGO );
if( cryptStatusOK( status ) )
{
RESOURCE_DATA msgData;
setResourceData( &msgData, keyID, PGP_KEYID_SIZE );
status = krnlSendMessage( iExportContext,
RESOURCE_IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_IATTRIBUTE_OPENPGP_KEYID );
}
if( cryptStatusError( status ) )
return( status );
/* Wrap the key using PGP's variant of PKCS #1 */
if( sIsNullStream( stream ) )
{
bufPtr = NULL;
bufSize = 0;
}
setMechanismWrapInfo( &mechanismInfo, bufPtr, bufSize, NULL, 0,
iSessionKeyContext, iExportContext, CRYPT_UNUSED );
status = krnlSendMessage( iExportContext, RESOURCE_IMESSAGE_DEV_EXPORT,
&mechanismInfo, MECHANISM_PKCS1_PGP );
wrappedKeySize = mechanismInfo.wrappedDataLength;
clearMechanismInfo( &mechanismInfo );
if( cryptStatusError( status ) )
return( status );
/* Write the PKE packet */
if( cryptAlgo == CRYPT_ALGO_RSA )
{
writePacketHeader( stream, PGP_PACKET_PKE,
1 + PGP_KEYID_SIZE + 1 + \
sizeofMPI( wrappedKeySize ) );
sputc( stream, 3 ); /* Version = 3 (OpenPGP) */
swrite( stream, keyID, PGP_KEYID_SIZE );
sputc( stream, PGP_ALGO_RSA );
status = pgpWriteMPI( stream, buffer, wrappedKeySize );
}
else
{
assert( cryptAlgo == CRYPT_ALGO_ELGAMAL );
writePacketHeader( stream, PGP_PACKET_PKE,
1 + PGP_KEYID_SIZE + 1 + wrappedKeySize );
sputc( stream, 3 ); /* Version = 3 (OpenPGP) */
swrite( stream, keyID, PGP_KEYID_SIZE );
sputc( stream, PGP_ALGO_ELGAMAL );
status = swrite( stream, buffer, wrappedKeySize );
}
zeroise( buffer, CRYPT_MAX_PKCSIZE );
return( status );
}
/* Signature info:
byte version = 3
byte sigType
byte hashAlgo
byte sigAlgo
byte[8] keyID
byte 1 */
static int writeSignatureInfoPacket( STREAM *stream,
const CRYPT_CONTEXT iSignContext,
const CRYPT_CONTEXT iHashContext )
{
CRYPT_ALGO hashAlgo, signAlgo;
BYTE keyID[ PGP_KEYID_SIZE ];
int status;
/* Get the signature information */
status = krnlSendMessage( iHashContext,
RESOURCE_IMESSAGE_GETATTRIBUTE,
&hashAlgo, CRYPT_CTXINFO_ALGO );
if( cryptStatusOK( status ) )
status = krnlSendMessage( iSignContext,
RESOURCE_IMESSAGE_GETATTRIBUTE,
&signAlgo, CRYPT_CTXINFO_ALGO );
if( cryptStatusOK( status ) )
{
RESOURCE_DATA msgData;
setResourceData( &msgData, keyID, PGP_KEYID_SIZE );
status = krnlSendMessage( iSignContext,
RESOURCE_IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_IATTRIBUTE_OPENPGP_KEYID );
}
if( cryptStatusError( status ) )
return( status );
/* Write the signature info packet */
writePacketHeader( 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. */
writeHashAlgorithmID( stream, hashAlgo );
sputc( stream, ( signAlgo == CRYPT_ALGO_RSA ) ? \
PGP_ALGO_RSA : PGP_ALGO_DSA );
swrite( stream, keyID, PGP_KEYID_SIZE );
return( sputc( stream, 1 ) );
}
/* Signature:
byte version = 4
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -