📄 keyex_rw.c
字号:
const long position = stell( stream );
/* Because of the last-minute change in the PWRI format before the
RFC was published, older versions of cryptlib generate a slightly
different KEK algorithm info format. To handle this, we read
part of the AlgorithmIdentifier and, if it's the newer format,
skip the extra level of wrapping */
readSequence( stream, NULL );
status = readOID( stream, OID_PWRIKEK );
if( cryptStatusError( status ) )
{
/* It's the original format, clear the stream error state caused
by the failed PWRI KEK OID read and try again */
sClearError( stream );
sseek( stream, position );
}
status = readContextAlgoID( stream, NULL, queryInfo, DEFAULT_TAG );
}
if( cryptStatusError( status ) )
return( status );
/* Finally, read the start of the encrypted key. We never read the data
itself since it's passed directly to the decrypt function */
status = readOctetStringHole( stream, &queryInfo->dataLength,
DEFAULT_TAG );
if( cryptStatusOK( status ) )
{
queryInfo->dataStart = sMemBufPtr( stream );
if( queryInfo->dataLength < bitsToBytes( MIN_KEYSIZE_BITS ) )
/* We shouldn't be using a key this short, we can't actually
load it anyway but a CRYPT_ERROR_BADDATA at this point
provides more meaningful information to the caller */
status = CRYPT_ERROR_BADDATA;
}
return( status );
}
static int writeCryptlibKek( STREAM *stream, const CRYPT_CONTEXT iCryptContext,
const BYTE *encryptedKey, const int encryptedKeyLength )
{
STREAM localStream;
BYTE derivationInfo[ CRYPT_MAX_HASHSIZE + 32 ], kekInfo[ 128 ];
BOOLEAN hasKeyDerivationInfo = TRUE;
int derivationInfoSize = 0, kekInfoSize, value, status;
/* If it's a non-password-derived key and there's a label attached,
write it as a KEKRI with a PWRI algorithm identifier as the key
encryption algorithm */
status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE,
&value, CRYPT_CTXINFO_KEYING_ITERATIONS );
if( status == CRYPT_ERROR_NOTINITED )
{
RESOURCE_DATA msgData;
/* There's no password-derivation information present, see if there's
a label present */
hasKeyDerivationInfo = FALSE;
setMessageData( &msgData, NULL, 0 );
status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_CTXINFO_LABEL );
if( cryptStatusOK( status ) )
/* There's a label present, write it as a PWRI within a KEKRI */
return( writeCmsKek( stream, iCryptContext, encryptedKey,
encryptedKeyLength ) );
}
/* Determine the size of the derivation info and KEK info. To save
evaluating it twice in a row and because it's short, we just write
it to local buffers */
if( hasKeyDerivationInfo )
{
sMemOpen( &localStream, derivationInfo, CRYPT_MAX_HASHSIZE + 32 );
status = writeKeyDerivationInfo( &localStream, iCryptContext );
derivationInfoSize = stell( &localStream );
sMemDisconnect( &localStream );
if( cryptStatusError( status ) )
return( status );
}
sMemOpen( &localStream, kekInfo, 128 );
writeSequence( &localStream,
sizeofOID( OID_PWRIKEK ) + \
sizeofContextAlgoID( iCryptContext, CRYPT_ALGO_NONE,
ALGOID_FLAG_NONE ) );
writeOID( &localStream, OID_PWRIKEK );
status = writeContextAlgoID( &localStream, iCryptContext, CRYPT_ALGO_NONE,
ALGOID_FLAG_NONE );
kekInfoSize = stell( &localStream );
sMemDisconnect( &localStream );
if( cryptStatusError( status ) )
return( status );
/* Write the algorithm identifiers and encrypted key */
writeConstructed( stream, sizeofShortInteger( PWRI_VERSION ) +
derivationInfoSize + kekInfoSize +
( int ) sizeofObject( encryptedKeyLength ),
CTAG_RI_PWRI );
writeShortInteger( stream, PWRI_VERSION, DEFAULT_TAG );
if( derivationInfoSize )
swrite( stream, derivationInfo, derivationInfoSize );
swrite( stream, kekInfo, kekInfoSize );
return( writeOctetString( stream, encryptedKey, encryptedKeyLength,
DEFAULT_TAG ) );
}
#ifdef USE_PGP
/* Read/write PGP KEK data.
SKE:
byte ctb = PGP_PACKET_SKE
byte[] length
byte version = 4
byte cryptAlgo
byte stringToKey specifier:
byte[] stringToKey data
0x00: byte hashAlgo
0x01: byte[8] salt
0x02: byte iterations */
static int readPgpKek( STREAM *stream, QUERY_INFO *queryInfo )
{
int value, status;
/* Make sure that the packet header is in order and check the packet
version. This is an OpenPGP-only packet */
status = getPacketInfo( stream, queryInfo );
if( cryptStatusError( status ) )
return( status );
if( sgetc( stream ) != PGP_VERSION_OPENPGP )
return( CRYPT_ERROR_BADDATA );
queryInfo->version = PGP_VERSION_OPENPGP;
/* Get the password hash algorithm */
if( ( queryInfo->cryptAlgo = \
pgpToCryptlibAlgo( sgetc( stream ),
PGP_ALGOCLASS_PWCRYPT ) ) == CRYPT_ALGO_NONE )
return( CRYPT_ERROR_NOTAVAIL );
/* Read the S2K specifier */
value = sgetc( stream );
if( value != 0 && value != 1 && value != 3 )
return( cryptStatusError( value ) ? value : CRYPT_ERROR_BADDATA );
if( ( queryInfo->keySetupAlgo = \
pgpToCryptlibAlgo( sgetc( stream ),
PGP_ALGOCLASS_HASH ) ) == CRYPT_ALGO_NONE )
return( CRYPT_ERROR_NOTAVAIL );
if( value == 0 )
/* It's a straight hash, we're done */
return( CRYPT_OK );
status = sread( stream, queryInfo->salt, PGP_SALTSIZE );
if( cryptStatusError( status ) )
return( status );
queryInfo->saltLength = 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 );
queryInfo->keySetupIterations = \
( 16 + ( ( long ) value & 0x0F ) ) << ( value >> 4 );
if( queryInfo->keySetupIterations <= 0 || \
queryInfo->keySetupIterations > MAX_KEYSETUP_ITERATIONS )
return( CRYPT_ERROR_BADDATA );
}
return( CRYPT_OK );
}
static int writePgpKek( STREAM *stream, const CRYPT_CONTEXT iCryptContext,
const BYTE *encryptedKey, const int encryptedKeyLength )
{
CRYPT_ALGO_TYPE hashAlgo, cryptAlgo;
BYTE salt[ CRYPT_MAX_HASHSIZE ];
int keySetupIterations, count = 0, status;
assert( encryptedKey == NULL );
assert( encryptedKeyLength == 0 );
/* Get the key derivation information */
status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE,
&keySetupIterations, CRYPT_CTXINFO_KEYING_ITERATIONS );
if( cryptStatusOK( status ) )
status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE,
&hashAlgo, CRYPT_CTXINFO_KEYING_ALGO );
if( cryptStatusOK( status ) )
status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE,
&cryptAlgo, CRYPT_CTXINFO_ALGO );
if( cryptStatusOK( status ) )
{
RESOURCE_DATA msgData;
setMessageData( &msgData, salt, CRYPT_MAX_HASHSIZE );
status = krnlSendMessage( iCryptContext, 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 */
pgpWritePacketHeader( stream, PGP_PACKET_SKE, 4 + PGP_SALTSIZE + 1 );
sputc( stream, PGP_VERSION_OPENPGP );
sputc( stream, cryptlibToPgpAlgo( cryptAlgo ) );
sputc( stream, 3 ); /* S2K = salted, iterated hash */
sputc( stream, cryptlibToPgpAlgo( hashAlgo ) );
swrite( stream, salt, PGP_SALTSIZE );
return( sputc( stream, count ) );
}
#endif /* USE_PGP */
/****************************************************************************
* *
* Public-key Encrypted Key Routines *
* *
****************************************************************************/
/* Read/write CMS key transport data */
static int readCmsKeytrans( STREAM *stream, QUERY_INFO *queryInfo )
{
long value;
int status;
/* Read the header and version number */
readSequence( stream, NULL );
status = readShortInteger( stream, &value );
if( cryptStatusError( status ) )
return( status );
if( value != KEYTRANS_VERSION )
return( CRYPT_ERROR_BADDATA );
/* Read the key ID and PKC algorithm information */
value = getStreamObjectLength( stream );
if( cryptStatusError( value ) )
return( value );
queryInfo->iAndSStart = sMemBufPtr( stream );
queryInfo->iAndSLength = value;
readUniversal( stream );
status = readAlgoID( stream, &queryInfo->cryptAlgo );
if( cryptStatusError( status ) )
return( status );
/* Finally, read the start of the encrypted key. We never read the data
itself since it's passed directly to the PKC decrypt function */
status = readOctetStringHole( stream, &queryInfo->dataLength,
DEFAULT_TAG );
if( cryptStatusOK( status ) )
queryInfo->dataStart = sMemBufPtr( stream );
return( status );
}
static int writeCmsKeytrans( STREAM *stream,
const CRYPT_CONTEXT iCryptContext,
const BYTE *buffer, const int length,
const void *auxInfo, const int auxInfoLength )
{
const int dataLength = \
sizeofContextAlgoID( iCryptContext, CRYPT_ALGO_NONE,
ALGOID_FLAG_ALGOID_ONLY ) + \
( int ) sizeofObject( length );
writeSequence( stream, sizeofShortInteger( KEYTRANS_VERSION ) +
auxInfoLength + dataLength );
writeShortInteger( stream, KEYTRANS_VERSION, DEFAULT_TAG );
swrite( stream, auxInfo, auxInfoLength );
writeContextAlgoID( stream, iCryptContext, CRYPT_ALGO_NONE,
ALGOID_FLAG_ALGOID_ONLY );
return( writeOctetString( stream, buffer, length, DEFAULT_TAG ) );
}
/* Read/write cryptlib key transport data */
static int writeCryptlibKeytrans( STREAM *stream,
const CRYPT_CONTEXT iCryptContext,
const BYTE *buffer, const int length,
const void *auxInfo,
const int auxInfoLength )
{
RESOURCE_DATA msgData;
BYTE keyID[ CRYPT_MAX_HASHSIZE ];
const int dataLength = \
sizeofContextAlgoID( iCryptContext, CRYPT_ALGO_NONE,
ALGOID_FLAG_ALGOID_ONLY ) + \
( int ) sizeofObject( length );
setMessageData( &msgData, keyID, CRYPT_MAX_HASHSIZE );
krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE_S, &msgData,
CRYPT_IATTRIBUTE_KEYID );
writeSequence( stream, sizeofShortInteger( KEYTRANS_EX_VERSION ) +
( int ) sizeofObject( msgData.length ) + dataLength );
writeShortInteger( stream, KEYTRANS_EX_VERSION, DEFAULT_TAG );
writeOctetString( stream, msgData.data, msgData.length, CTAG_KT_SKI );
writeContextAlgoID( stream, iCryptContext, CRYPT_ALGO_NONE,
ALGOID_FLAG_ALGOID_ONLY );
return( writeOctetString( stream, buffer, length, DEFAULT_TAG ) );
}
static int readCryptlibKeytrans( STREAM *stream, QUERY_INFO *queryInfo )
{
long value;
int status;
/* Read the header and version number */
readSequence( stream, NULL );
status = readShortInteger( stream, &value );
if( cryptStatusError( status ) )
return( status );
if( value != KEYTRANS_EX_VERSION )
return( CRYPT_ERROR_BADDATA );
/* Read the key ID and PKC algorithm information */
readOctetStringTag( stream, queryInfo->keyID, &queryInfo->keyIDlength,
CRYPT_MAX_HASHSIZE, CTAG_KT_SKI );
status = readAlgoID( stream, &queryInfo->cryptAlgo );
if( cryptStatusError( status ) )
return( status );
/* Finally, read the start of the encrypted key. We never read the data
itself since it's passed directly to the PKC decrypt function */
status = readOctetStringHole( stream, &queryInfo->dataLength,
DEFAULT_TAG );
if( cryptStatusOK( status ) )
queryInfo->dataStart = sMemBufPtr( stream );
return( status );
}
#ifdef USE_PGP
/* Read/write PGP key transport data:
PKE:
byte ctb = PGP_PACKET_PKE
byte[] length
byte version = 2 or 3
byte[8] keyID
byte PKC algo
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -