📄 dbxpgp.c
字号:
int i;
/* Perform a case-insensitive match for the required substring in the
string */
for( i = 0; i <= stringLength - subStringLength; i++ )
if( ( toUpper( string[ i ] ) == firstChar ) &&
!strCompare( subString, string + i, subStringLength ) )
return( TRUE );
return( FALSE );
}
/* Check whether a key matches the required user ID */
static BOOLEAN checkKeyMatch( const PGP_INFO *pgpInfo,
const PGP_KEYINFO *keyInfo,
const KEY_MATCH_INFO *keyMatchInfo )
{
int i;
/* If there's an explicitly requested key usage type, make sure the key
is suitable */
if( ( keyMatchInfo->flags & KEYMGMT_MASK_USAGEOPTIONS ) && \
!( keyInfo->usageFlags & keyMatchInfo->flags ) )
return( FALSE );
/* If we're searching by key ID, check whether this is the packet we
want */
if( keyMatchInfo->keyIDtype == CRYPT_IKEYID_KEYID || \
keyMatchInfo->keyIDtype == CRYPT_IKEYID_PGPKEYID )
return( matchKeyID( keyInfo, keyMatchInfo->keyID,
keyMatchInfo->keyIDlength,
( keyMatchInfo->keyIDtype == CRYPT_IKEYID_PGPKEYID ) ? \
TRUE : FALSE ) );
assert( keyMatchInfo->keyIDtype == CRYPT_KEYID_NAME || \
keyMatchInfo->keyIDtype == CRYPT_KEYID_EMAIL );
/* We're searching by user ID, walk down the list of userIDs checking
for a match */
for( i = 0; i < pgpInfo->lastUserID; i++ )
/* Check if it's the one we want. If it's a key with subkeys and no
usage type is explicitly specified, this will always return the
main key. This is the best solution since the main key is always
a signing key, which is more likely to be what the user wants.
Encryption keys will typically only be accessed via envelopes,
and the enveloping code can specify a preference of an encryption-
capable key, while signing keys will be read directly and pushed
into the envelope */
if( matchSubstring( ( char * ) keyMatchInfo->keyID,
keyMatchInfo->keyIDlength, pgpInfo->userID[ i ],
pgpInfo->userIDlen[ i ] ) )
return( TRUE );
return( FALSE );
}
/* Locate a key based on an ID. This is complicated somewhat by the fact
that PGP */
static PGP_INFO *findEntry( const PGP_INFO *pgpInfo,
const CRYPT_KEYID_TYPE keyIDtype,
const void *keyID, const int keyIDlength,
const int requestedUsage, PGP_KEYINFO **keyInfo )
{
CONST_INIT KEY_MATCH_INFO keyMatchInfo = \
{ keyIDtype, keyID, keyIDlength, requestedUsage };
int i;
for( i = 0; i < MAX_PGP_OBJECTS; i++ )
{
if( checkKeyMatch( &pgpInfo[ i ], &pgpInfo[ i ].key,
&keyMatchInfo ) )
{
if( keyInfo != NULL )
*keyInfo = ( PGP_KEYINFO * ) &pgpInfo->key;
return( ( PGP_INFO * ) &pgpInfo[ i ] );
}
if( checkKeyMatch( &pgpInfo[ i ], &pgpInfo[ i ].subKey,
&keyMatchInfo ) )
{
if( keyInfo != NULL )
*keyInfo = ( PGP_KEYINFO * ) &pgpInfo->subKey;
return( ( PGP_INFO * ) &pgpInfo[ i ] );
break;
}
}
return( NULL );
}
/****************************************************************************
* *
* Read a Key *
* *
****************************************************************************/
/* Read the information needed to decrypt a secret key */
static int readSecretKeyDecryptionInfo( STREAM *stream, PGP_KEYINFO *keyInfo )
{
const int ctb = sgetc( stream );
int status;
/* Clear return value */
keyInfo->cryptAlgo = keyInfo->hashAlgo = CRYPT_ALGO_NONE;
keyInfo->saltSize = keyInfo->keySetupIterations = 0;
/* If no encryption is being used, we mark the key as unusable. This
isn't exactly the correct thing to do, but storing plaintext private
keys on disk is extremely dangerous and we probably shouldn't be
using them, and an attempt to import an unencrypted key will trigger
so many security check failures in the key unwrap code it's not even
worth trying */
if( !ctb )
return( OK_SPECIAL );
/* If it's a direct algorithm specifier, it's a PGP 2.x packet with
raw IDEA encryption */
if( ctb == PGP_ALGO_IDEA )
{
keyInfo->cryptAlgo = CRYPT_ALGO_IDEA;
keyInfo->hashAlgo = CRYPT_ALGO_MD5;
}
else
{
int value;
/* Must be an S2K specifier */
if( ctb != PGP_S2K && ctb != PGP_S2K_HASHED )
return( CRYPT_ERROR_BADDATA );
/* Get the key wrap algorithm and S2K information */
if( ( keyInfo->cryptAlgo = \
pgpToCryptlibAlgo( sgetc( stream ),
PGP_ALGOCLASS_PWCRYPT ) ) == CRYPT_ALGO_NONE )
/* Unknown algorithm type, skip this packet */
return( OK_SPECIAL );
value = sgetc( stream );
if( value != 0 && value != 1 && value != 3 )
return( cryptStatusError( value ) ? value : OK_SPECIAL );
if( ( keyInfo->hashAlgo = \
pgpToCryptlibAlgo( sgetc( stream ),
PGP_ALGOCLASS_HASH ) ) == CRYPT_ALGO_NONE )
/* Unknown algorithm type, skip this packet */
return( OK_SPECIAL );
if( value != 0 )
{
/* It's a salted hash */
status = sread( stream, keyInfo->salt, PGP_SALTSIZE );
if( cryptStatusError( status ) )
return( status );
keyInfo->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( value ) )
return( value );
keyInfo->keySetupIterations = \
( 16 + ( ( long ) value & 0x0F ) ) << ( value >> 4 );
if( keyInfo->keySetupIterations <= 0 || \
keyInfo->keySetupIterations > MAX_KEYSETUP_ITERATIONS )
return( CRYPT_ERROR_BADDATA );
}
}
status = sread( stream, keyInfo->iv, PGP_IVSIZE );
return( cryptStatusError( status ) ? status : CRYPT_OK );
}
/* Read a single key in a group of key packets */
static int readKey( STREAM *stream, PGP_INFO *pgpInfo )
{
PGP_KEYINFO *keyInfo = &pgpInfo->key;
HASHFUNCTION hashFunction;
HASHINFO hashInfo;
BYTE hash[ CRYPT_MAX_HASHSIZE ], packetHeader[ 64 ];
BOOLEAN isPublicKey = TRUE;
void *pubKeyPayload;
long packetLength;
int startPos, endPos, ctb, length, pubKeyPayloadLen;
int value, hashSize, status;
/* Skip CTB, packet length, and version byte */
ctb = sPeek( stream );
switch( getCTB( ctb ) )
{
case PGP_PACKET_SECKEY_SUB:
keyInfo = &pgpInfo->subKey;
/* Fall through */
case PGP_PACKET_SECKEY:
isPublicKey = FALSE;
break;
case PGP_PACKET_PUBKEY_SUB:
keyInfo = &pgpInfo->subKey;
/* Fall through */
case PGP_PACKET_PUBKEY:
break;
default:
return( cryptStatusError( ctb ) ? \
CRYPT_ERROR_NOTFOUND : CRYPT_ERROR_BADDATA );
}
status = pgpReadPacketHeader( stream, NULL, &packetLength );
if( cryptStatusError( status ) )
return( status );
if( packetLength < 64 || sMemDataLeft( stream ) < packetLength )
return( CRYPT_ERROR_BADDATA );
length = ( int ) packetLength;
keyInfo->pubKeyData = sMemBufPtr( stream );
startPos = stell( stream );
endPos = startPos + length;
value = sgetc( stream );
if( value != PGP_VERSION_2 && value != PGP_VERSION_3 && \
value != PGP_VERSION_OPENPGP )
/* Unknown version number, skip this packet */
return( OK_SPECIAL );
pgpInfo->isOpenPGP = ( value == PGP_VERSION_OPENPGP ) ? TRUE : FALSE;
/* Build the packet header, which is hashed along with the key components
to get the OpenPGP keyID. This is generated anyway when the context
is created, but we need to generate it here as well in order to locate
the key in the first place:
byte ctb = 0x99
byte[2] length
byte version = 4
byte[4] key generation time
byte[] key data
We can't add the length or key data yet since we have to parse the
key data to know how long it is, so we can only build the static part
of the header at this point */
packetHeader[ 0 ] = 0x99;
packetHeader[ 3 ] = PGP_VERSION_OPENPGP;
/* Read the timestamp and validity period (for PGP 2.x keys) */
sread( stream, packetHeader + 4, 4 );
if( !pgpInfo->isOpenPGP )
sSkip( stream, 2 );
/* Read the public key components */
pubKeyPayload = sMemBufPtr( stream );
pubKeyPayloadLen = stell( stream );
value = sgetc( stream );
if( value == PGP_ALGO_RSA || value == PGP_ALGO_RSA_ENCRYPT || \
value == PGP_ALGO_RSA_SIGN )
{
/* RSA: n + e. The LSBs of n serve as the PGP 2.x key ID, so we
copy the data out before continuing */
keyInfo->pkcAlgo = CRYPT_ALGO_RSA;
if( value != PGP_ALGO_RSA_SIGN )
keyInfo->usageFlags = KEYMGMT_FLAG_USAGE_CRYPT;
if( value != PGP_ALGO_RSA_ENCRYPT )
keyInfo->usageFlags |= KEYMGMT_FLAG_USAGE_SIGN;
length = 1 + getMPIsize( stream );
if( sStatusOK( stream ) && \
stell( stream ) - startPos > PGP_KEYID_SIZE )
memcpy( keyInfo->pgpKeyID, sMemBufPtr( stream ) - PGP_KEYID_SIZE,
PGP_KEYID_SIZE );
length += getMPIsize( stream );
}
else
{
/* If it's an unknown algorithm, skip this key */
if( value != PGP_ALGO_DSA && value != PGP_ALGO_ELGAMAL )
return( cryptStatusError( value ) ? value: OK_SPECIAL );
/* DSA/Elgamal: p + g + y */
if( value == PGP_ALGO_DSA )
{
keyInfo->pkcAlgo = CRYPT_ALGO_DSA;
keyInfo->usageFlags = KEYMGMT_FLAG_USAGE_SIGN;
}
else
{
keyInfo->pkcAlgo = CRYPT_ALGO_ELGAMAL;
keyInfo->usageFlags = KEYMGMT_FLAG_USAGE_CRYPT;
}
length = 1 + getMPIsize( stream ) + getMPIsize( stream ) + \
getMPIsize( stream );
if( value == PGP_ALGO_DSA )
/* DSA has q as well */
length += getMPIsize( stream );
}
status = sGetStatus( stream );
if( cryptStatusError( status ) )
return( status );
keyInfo->pubKeyDataLen = stell( stream ) - startPos;
pubKeyPayloadLen = stell( stream ) - pubKeyPayloadLen;
/* Complete the packet header that we read earlier on by adding the
length information */
packetHeader[ 1 ] = ( ( 1 + 4 + length ) >> 8 ) & 0xFF;
packetHeader[ 2 ] = ( 1 + 4 + length ) & 0xFF;
/* Hash the data needed to generate the OpenPGP keyID */
getHashParameters( CRYPT_ALGO_SHA, &hashFunction, &hashSize );
hashFunction( hashInfo, NULL, packetHeader, 1 + 2 + 1 + 4, HASH_START );
hashFunction( hashInfo, hash, pubKeyPayload, pubKeyPayloadLen, HASH_END );
memcpy( keyInfo->openPGPkeyID, hash + hashSize - PGP_KEYID_SIZE,
PGP_KEYID_SIZE );
/* If it's a private keyring, process the private key components */
if( !isPublicKey )
{
/* Handle decryption info for secret components if necessary */
status = readSecretKeyDecryptionInfo( stream, keyInfo );
if( cryptStatusError( status ) )
return( status );
/* What's left is the private-key data */
keyInfo->privKeyData = sMemBufPtr( stream );
keyInfo->privKeyDataLen = endPos - stell( stream );
status = sSkip( stream, keyInfo->privKeyDataLen );
}
/* Read the userID packet(s) */
while( cryptStatusOK( status ) )
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -