📄 keyex_rw.c
字号:
return( status );
}
sMemOpen( &localStream, kekInfo, 128 );
writeSequence( &localStream, sizeofOID( OID_PWRIKEK ) + algoIdInfoSize );
writeOID( &localStream, OID_PWRIKEK );
status = writeCryptContextAlgoID( &localStream, iCryptContext );
if( cryptStatusOK( status ) )
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 > 0 )
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 = PGP_VERSION_OPENPGP
byte cryptAlgo
byte stringToKey specifier, 0, 1, or 3
byte[] stringToKey data
0x00: byte hashAlgo
0x01: byte[8] salt
0x03: byte iterations */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int readPgpKek( INOUT STREAM *stream, INOUT QUERY_INFO *queryInfo )
{
int value, status;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isWritePtr( queryInfo, sizeof( QUERY_INFO ) ) );
/* Make sure that the packet header is in order and check the packet
version. This is an OpenPGP-only packet */
status = getPgpPacketInfo( 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 */
status = readPgpAlgo( stream, &queryInfo->cryptAlgo,
PGP_ALGOCLASS_PWCRYPT );
if( cryptStatusError( status ) )
return( status );
/* Read the S2K specifier */
value = sgetc( stream );
if( value != 0 && value != 1 && value != 3 )
return( cryptStatusError( value ) ? value : CRYPT_ERROR_BADDATA );
status = readPgpAlgo( stream, &queryInfo->keySetupAlgo,
PGP_ALGOCLASS_HASH );
if( cryptStatusError( status ) )
return( status );
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 )
{
/* It's a non-iterated hash, we're done */
return( CRYPT_OK );
}
/* Salted iterated hash, decode the iteration count from the bizarre
fixed-point encoded value, limiting the result to a sane value range:
count = ( ( Int32 ) 16 + ( c & 15 ) ) << ( ( c >> 4 ) + 6 )
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 that
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 iteration-count 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 );
}
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int writePgpKek( INOUT STREAM *stream,
IN_HANDLE const CRYPT_CONTEXT iCryptContext,
STDC_UNUSED const BYTE *encryptedKey,
STDC_UNUSED const int encryptedKeyLength )
{
CRYPT_ALGO_TYPE hashAlgo = DUMMY_INIT, cryptAlgo = DUMMY_INIT;
BYTE salt[ CRYPT_MAX_HASHSIZE + 8 ];
int pgpCryptAlgo, pgpHashAlgo = DUMMY_INIT, keySetupIterations;
int count = 0, status;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
REQUIRES( isHandleRangeValid( iCryptContext ) );
REQUIRES( encryptedKey == NULL && 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 ) )
{
MESSAGE_DATA msgData;
setMessageData( &msgData, salt, CRYPT_MAX_HASHSIZE );
status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_CTXINFO_KEYING_SALT );
}
if( cryptStatusError( status ) )
return( status );
status = cryptlibToPgpAlgo( cryptAlgo, &pgpCryptAlgo );
if( cryptStatusOK( status ) )
status = cryptlibToPgpAlgo( hashAlgo, &pgpHashAlgo );
ENSURES( cryptStatusOK( 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 that
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 */
REQUIRES( keySetupIterations % 16 == 0 );
keySetupIterations /= 32; /* Remove fixed offset before log2 op.*/
while( keySetupIterations > 0 )
{
count++;
keySetupIterations >>= 1;
}
count <<= 4; /* Exponent comes first */
ENSURES( count >= 0 && count <= 0xFF );
/* Write the SKE packet */
pgpWritePacketHeader( stream, PGP_PACKET_SKE,
PGP_VERSION_SIZE + PGP_ALGOID_SIZE + 1 + \
PGP_ALGOID_SIZE + PGP_SALTSIZE + 1 );
sputc( stream, PGP_VERSION_OPENPGP );
sputc( stream, pgpCryptAlgo );
sputc( stream, 3 ); /* S2K = salted, iterated hash */
sputc( stream, pgpHashAlgo );
swrite( stream, salt, PGP_SALTSIZE );
return( sputc( stream, count ) );
}
#endif /* USE_PGP */
/****************************************************************************
* *
* Public-key Encrypted Key Routines *
* *
****************************************************************************/
/* Read/write CMS key transport data:
SEQUENCE {
version INTEGER (0),
issuerAndSerial IssuerAndSerialNumber,
algorithm AlgorithmIdentifier,
encryptedKey OCTET STRING
} */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int readCmsKeytrans( INOUT STREAM *stream,
INOUT QUERY_INFO *queryInfo )
{
const int startPos = stell( stream );
long value;
int length, status;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isWritePtr( queryInfo, sizeof( QUERY_INFO ) ) );
/* 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. Since we're recording
the position of the issuerAndSerialNumber as a blob we have to use
getStreamObjectLength() to get the overall blob data size */
status = getStreamObjectLength( stream, &length );
if( cryptStatusError( status ) )
return( status );
queryInfo->iAndSStart = stell( stream ) - startPos;
queryInfo->iAndSLength = length;
sSkip( stream, length );
status = readAlgoID( stream, &queryInfo->cryptAlgo );
if( cryptStatusError( status ) )
return( status );
/* Finally, read the start of the encrypted key */
status = readOctetStringHole( stream, &queryInfo->dataLength,
MIN_PKCSIZE, DEFAULT_TAG );
if( cryptStatusError( status ) )
return( status );
queryInfo->dataStart = stell( stream ) - startPos;
/* Make sure that the remaining key data is present */
return( sSkip( stream, queryInfo->dataLength ) );
}
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 5 ) ) \
static int writeCmsKeytrans( INOUT STREAM *stream,
IN_HANDLE const CRYPT_CONTEXT iCryptContext,
IN_BUFFER( encryptedKeyLength ) \
const BYTE *encryptedKey,
IN_LENGTH_SHORT_MIN( MIN_PKCSIZE ) \
const int encryptedKeyLength,
IN_BUFFER( auxInfoLength ) const void *auxInfo,
IN_LENGTH_SHORT const int auxInfoLength )
{
const int algoIdInfoSize = \
sizeofContextAlgoID( iCryptContext, CRYPT_ALGO_NONE );
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isReadPtr( encryptedKey, encryptedKeyLength ) );
assert( isReadPtr( auxInfo, auxInfoLength ) );
REQUIRES( isHandleRangeValid( iCryptContext ) );
REQUIRES( encryptedKeyLength >= MIN_PKCSIZE && \
encryptedKeyLength < MAX_INTLENGTH_SHORT );
REQUIRES( auxInfoLength > 0 && auxInfoLength < MAX_INTLENGTH_SHORT );
if( cryptStatusError( algoIdInfoSize ) )
return( algoIdInfoSize );
writeSequence( stream, sizeofShortInteger( KEYTRANS_VERSION ) +
auxInfoLength + algoIdInfoSize + \
( int ) sizeofObject( encryptedKeyLength ) );
writeShortInteger( stream, KEYTRANS_VERSION, DEFAULT_TAG );
swrite( stream, auxInfo, auxInfoLength );
writeContextAlgoID( stream, iCryptContext, CRYPT_ALGO_NONE );
return( writeOctetString( stream, encryptedKey, encryptedKeyLength,
DEFAULT_TAG ) );
}
/* Read/write cryptlib key transport data:
SEQUENCE {
version INTEGER (2),
keyID [0] SubjectKeyIdentifier,
algorithm AlgorithmIdentifier,
encryptedKey OCTET STRING
} */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int readCryptlibKeytrans( INOUT STREAM *stream,
INOUT QUERY_INFO *queryInfo )
{
const int startPos = stell( stream );
long value;
int status;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isWritePtr( queryInfo, sizeof( QUERY_INFO ) ) );
/* 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,
8, CRYPT_MAX_HASHSIZE, CTAG_KT_SKI );
status = readAlgoID( stream, &queryInfo->cryptAlgo );
if( cryptStatusError( status ) )
return( status );
/* Finally, read the start of the encrypted key */
status = readOctetStringHole( stream, &queryInfo->dataLength,
MIN_KEYSIZE, DEFAULT_TAG );
if( cryptStatusError( status ) )
return( status );
queryInfo->dataStart = stell( stream ) - startPos;
/* Make sure that the remaining key data is present */
return( sSkip( stream, queryInfo->dataLength ) );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -