dbxpgp.c
来自「提供了很多种加密算法和CA认证及相关服务如CMP、OCSP等的开发」· C语言 代码 · 共 1,074 行 · 第 1/3 页
C
1,074 行
/****************************************************************************
* *
* PGP Key Read Routines *
* Copyright Peter Gutmann 1992-2002 *
* *
****************************************************************************/
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if defined( INC_ALL )
#include "crypt.h"
#include "pgp.h"
#include "keyset.h"
#elif defined( INC_CHILD )
#include "../crypt.h"
#include "../envelope/pgp.h"
#include "keyset.h"
#else
#include "crypt.h"
#include "envelope/pgp.h"
#include "misc/keyset.h"
#endif /* Compiler-specific includes */
/* Key-related information needed to create a cryptlib context from PGP key
data */
typedef struct {
/* A copy of the ID used to identify the key, and the cached key. The
ID is used to identify repeated reads of the same key (for example if
an incorrect password is used), which allows the cached key to be
reused */
BYTE cachedKeyID[ CRYPT_MAX_TEXTSIZE ];
int cachedKeyIDlength;
BYTE cachedKey[ MAX_PRIVATE_KEYSIZE ];
int cachedKeyLength;
BOOLEAN cachedKeyPresent;
/* Key data */
CRYPT_ALGO pkcAlgo; /* Algorithm for the key data */
int actionFlags; /* cryptlib permitted key usage */
int usageFlags; /* Keymgmt flags permitted usage */
union {
CRYPT_PKCINFO_RSA rsaKey;
CRYPT_PKCINFO_DLP dlpKey;
} key; /* Key data */
BOOLEAN isOpenPGP; /* Whether data is PGP 2.x or OpenPGP */
/* Key-protection information */
CRYPT_ALGO cryptAlgo; /* Key wrap algorithm */
BYTE iv[ PGP_IVSIZE ]; /* Key wrap IV */
CRYPT_ALGO hashAlgo; /* Password hashing algo */
BYTE salt[ PGP_SALTSIZE ]; /* Password hashing salt */
int saltSize;
int keySetupIterations; /* Password hashing iterations */
int privKeyStart; /* Offset of priv.key data inside cached key */
/* userID and OpenPGP keyID for this key. Since subkeys inherit the
userID from the main key, we also record whether there's an ID still
present from the main when we're reading a subkey */
char userID[ PGP_MAX_USERIDSIZE ];
BYTE keyID[ PGP_KEYID_SIZE ];
BOOLEAN userIDset;
} PGP_INFO;
/****************************************************************************
* *
* Utility Routines *
* *
****************************************************************************/
/* Generate a cryptlib-style key ID for the PGP key and check it against the
given key ID. This will really suck with large public keyrings since it
requires creating a context for each key we check, but there's no easy
way around this */
static BOOLEAN matchKeyID( PGP_INFO *pgpInfo, const BYTE *requiredID,
const int requiredIDlength,
const BOOLEAN isPGPkeyID )
{
MESSAGE_CREATEOBJECT_INFO createInfo;
RESOURCE_DATA msgData;
BYTE keyID[ KEYID_SIZE ];
BOOLEAN *pubKeyStatusPtr = ( pgpInfo->pkcAlgo == CRYPT_ALGO_RSA ) ? \
&pgpInfo->key.rsaKey.isPublicKey : \
&pgpInfo->key.dlpKey.isPublicKey;
BOOLEAN pubKeyStatus;
int status;
/* If it's a PGP key ID, we can check it directly against the two PGP
key IDs. We don't distinguish between the two ID types externally
because it's a pain for external code to have to know that there are
two ID types which look the same and which are often used
interchangeably but only the OpenPGP variant is valid for all keys.
The chances of a collision are miniscule, and the worst that can
possibly happen is that a sig check will fail (encryption keys are
chosen by user ID and not key ID, so accidentally using the wrong
key to encrypt isn't an issue) */
if( isPGPkeyID )
{
CRYPT_PKCINFO_RSA *rsaKeyPtr = &pgpInfo->key.rsaKey;
assert( requiredIDlength == PGP_KEYID_SIZE );
if( !memcmp( requiredID, pgpInfo->keyID, PGP_KEYID_SIZE ) )
return( TRUE );
return( ( pgpInfo->pkcAlgo == CRYPT_ALGO_RSA ) && \
!memcmp( requiredID,
rsaKeyPtr->n + bitsToBytes( rsaKeyPtr->nLen ) - \
PGP_KEYID_SIZE,
PGP_KEYID_SIZE ) );
}
assert( requiredIDlength == KEYID_SIZE );
/* Generate the key ID. Since we only need the public components to
generate the ID (and typically won't have processed the private key
components at this point anyway), we make the key look like a public
key */
setMessageCreateObjectInfo( &createInfo, pgpInfo->pkcAlgo );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
RESOURCE_IMESSAGE_DEV_CREATEOBJECT,
&createInfo, OBJECT_TYPE_CONTEXT );
if( cryptStatusError( status ) )
{
assert( NOTREACHED );
return( FALSE );
}
setResourceData( &msgData, "PGP dummy label", 15 );
krnlSendMessage( createInfo.cryptHandle, RESOURCE_IMESSAGE_SETATTRIBUTE_S,
&msgData, CRYPT_CTXINFO_LABEL );
pubKeyStatus = *pubKeyStatusPtr;
*pubKeyStatusPtr = TRUE;
setResourceData( &msgData, &pgpInfo->key,
( pgpInfo->pkcAlgo == CRYPT_ALGO_RSA ) ? \
sizeof( CRYPT_PKCINFO_RSA ) : \
sizeof( CRYPT_PKCINFO_DLP ) );
status = krnlSendMessage( createInfo.cryptHandle,
RESOURCE_IMESSAGE_SETATTRIBUTE_S, &msgData,
CRYPT_CTXINFO_KEY_COMPONENTS );
*pubKeyStatusPtr = pubKeyStatus;
if( cryptStatusOK( status ) )
{
setResourceData( &msgData, keyID, KEYID_SIZE );
status = krnlSendMessage( createInfo.cryptHandle,
RESOURCE_IMESSAGE_GETATTRIBUTE_S, &msgData,
CRYPT_IATTRIBUTE_KEYID );
}
krnlSendNotifier( createInfo.cryptHandle, RESOURCE_IMESSAGE_DECREFCOUNT );
if( cryptStatusError( status ) )
{
assert( NOTREACHED );
return( FALSE );
}
/* Check if it's the same as the key ID we're looking for */
return( !memcmp( requiredID, keyID, requiredIDlength ) ? TRUE : FALSE );
}
/* Match a substring of a full string as done by PGP */
static BOOLEAN matchSubstring( const char *subString,
const int subStringLength,
const char *string, const int stringLength,
const int permittedUsage,
const int requestedUsage )
{
char firstChar = toupper( subString[ 0 ] );
int i;
/* If there's an explicitly requested key usage type, make sure the key
is suitable */
if( ( requestedUsage & KEYMGMT_MASK_USAGEOPTIONS ) && \
!( permittedUsage & requestedUsage ) )
return( FALSE );
/* Perform a case-insensitive match for the required substring in the
string */
for( i = 0; i <= stringLength - subStringLength; i++ )
if( ( toupper( string[ i ] ) == firstChar ) &&
!strnicmp( subString, string + i, subStringLength ) )
return( TRUE );
return( FALSE );
}
/****************************************************************************
* *
* Read Keyring Packets *
* *
****************************************************************************/
/* Skip to the start of the next key packet */
static void skipToKeyPacket( STREAM *stream, const long endPos )
{
int ctb;
/* Skip to the end of the current packet and see what's next */
sseek( stream, endPos );
ctb = sgetc( stream );
assert( ctb & PGP_CTB );
if( !( ctb & PGP_CTB ) )
{
sSetError( stream, CRYPT_ERROR_BADDATA );
return;
}
/* Skip any following non-key packets */
while( sGetStatus( stream ) == CRYPT_OK && \
getCTB( ctb ) != PGP_PACKET_PUBKEY && \
getCTB( ctb ) != PGP_PACKET_PUBKEY_SUB && \
getCTB( ctb ) != PGP_PACKET_SECKEY && \
getCTB( ctb ) != PGP_PACKET_SECKEY_SUB )
{
int length = ( int ) pgpGetLength( stream, ctb );
/* If we get an impossibly large packet, assume we're in trouble and
set the EOF status */
if( length > 5000 )
sSetError( stream, CRYPT_ERROR_UNDERFLOW );
else
if( length <= 0 )
sSetError( stream, CRYPT_ERROR_BADDATA );
else
/* Skip the current packet */
sSkip( stream, length );
ctb = sgetc( stream );
}
/* Finally, put back the last CTB we read unless we've reached the end
of the file */
if( sGetStatus( stream ) == CRYPT_OK )
sungetc( stream );
}
/* Read the information needed to decrypt a secret key */
static int readSecretKeyDecryptionInfo( STREAM *stream, PGP_INFO *pgpInfo )
{
const int ctb = sgetc( stream );
int status;
/* Clear return value */
pgpInfo->cryptAlgo = pgpInfo->hashAlgo = CRYPT_ALGO_NONE;
pgpInfo->saltSize = pgpInfo->keySetupIterations = 0;
/* If no encryption is being used, there's nothing more to do */
if( !ctb )
return( CRYPT_OK );
/* If it's a direct algorithm specifier, it's a PGP 2.x packet with
raw IDEA encryption */
if( ctb == PGP_ALGO_IDEA )
{
pgpInfo->cryptAlgo = CRYPT_ALGO_IDEA;
pgpInfo->hashAlgo = CRYPT_ALGO_MD5;
}
else
{
int value;
/* Must be an S2K specifier */
if( ctb != 0xFF )
return( CRYPT_ERROR_BADDATA );
/* Get the key wrap algorithm and S2K information */
switch( sgetc( stream ) )
{
case PGP_ALGO_IDEA:
pgpInfo->cryptAlgo = CRYPT_ALGO_IDEA;
break;
case PGP_ALGO_3DES:
pgpInfo->cryptAlgo = CRYPT_ALGO_3DES;
break;
case PGP_ALGO_CAST5:
pgpInfo->cryptAlgo = CRYPT_ALGO_CAST;
break;
case PGP_ALGO_BLOWFISH:
pgpInfo->cryptAlgo = CRYPT_ALGO_BLOWFISH;
break;
default:
/* Unknown algorithm type, skip this packet */
return( OK_SPECIAL );
}
value = sgetc( stream );
if( value != 0 && value != 1 && value != 3 )
return( CRYPT_ERROR_BADDATA );
switch( sgetc( stream ) )
{
case PGP_ALGO_MD5:
pgpInfo->hashAlgo = CRYPT_ALGO_MD5;
break;
case PGP_ALGO_SHA:
pgpInfo->hashAlgo = CRYPT_ALGO_SHA;
break;
case PGP_ALGO_RIPEMD160:
pgpInfo->hashAlgo = CRYPT_ALGO_RIPEMD160;
break;
default:
/* Unknown algorithm type, skip this packet */
return( OK_SPECIAL );
}
if( value != 0 )
{
/* It's a salted hash */
status = sread( stream, pgpInfo->salt, PGP_SALTSIZE );
if( cryptStatusError( status ) )
return( status );
pgpInfo->saltSize = PGP_SALTSIZE;
}
if( value == 3 )
{
/* Salted iterated hash, get the iteration count, limited to a
sane value. 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. The value we calculate here (to prevent
overflow on 16-bit machines) is the count without the
base * 64 scaling, this also puts the range within the value
of the standard sanity check */
value = sgetc( stream );
if( cryptStatusError( status ) )
return( status );
pgpInfo->keySetupIterations = \
( 16 + ( ( long ) value & 0x0F ) ) << ( value >> 4 );
if( pgpInfo->keySetupIterations > MAX_KEYSETUP_ITERATIONS )
return( CRYPT_ERROR_BADDATA );
}
}
return( sread( stream, pgpInfo->iv, PGP_IVSIZE ) );
}
/* Read public-key components */
static int readPublicKeyComponents( STREAM *stream, PGP_INFO *pgpInfo,
const BOOLEAN isPublicKey )
{
CRYPT_PKCINFO_DLP *dlpKeyPtr = &pgpInfo->key.dlpKey;
int actionFlags = 0, usageFlags = 0, value, status;
/* Get the algorithm type and make sure it's one we recognise */
value = sgetc( stream );
if( value != PGP_ALGO_RSA && value != PGP_ALGO_RSA_ENCRYPT && \
value != PGP_ALGO_RSA_SIGN && value != PGP_ALGO_DSA && \
value != PGP_ALGO_ELGAMAL )
/* Unknown PKC algorithm type, skip this packet */
return( OK_SPECIAL );
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?