📄 keyex_rw.c
字号:
/****************************************************************************
* *
* Key Exchange Read/Write Routines *
* Copyright Peter Gutmann 1992-2007 *
* *
****************************************************************************/
#if defined( INC_ALL )
#include "mech.h"
#include "asn1.h"
#include "asn1_ext.h"
#include "misc_rw.h"
#include "pgp_rw.h"
#else
#include "mechs/mech.h"
#include "misc/asn1.h"
#include "misc/asn1_ext.h"
#include "misc/misc_rw.h"
#include "misc/pgp_rw.h"
#endif /* Compiler-specific includes */
/* Context-specific tags for the KEK record */
enum { CTAG_KK_DA };
/* Context-specific tags for the KeyTrans record */
enum { CTAG_KT_SKI };
/****************************************************************************
* *
* Conventionally-Encrypted Key Routines *
* *
****************************************************************************/
/* The OID for the PKCS #5 v2.0 key derivation function and the parameterised
PWRI key wrap algorithm */
#define OID_PBKDF2 MKOID( "\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x05\x0C" )
#define OID_PWRIKEK MKOID( "\x06\x0B\x2A\x86\x48\x86\xF7\x0D\x01\x09\x10\x03\x09" )
/* Read/write a PBKDF2 key derivation record:
SEQUENCE {
algorithm AlgorithmIdentifier (pkcs-5 12),
params SEQUENCE {
salt OCTET STRING,
iterationCount INTEGER (1..MAX),
}
} */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int readKeyDerivationInfo( INOUT STREAM *stream,
INOUT QUERY_INFO *queryInfo )
{
long endPos, value;
int length, status;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isWritePtr( queryInfo, sizeof( QUERY_INFO ) ) );
/* Read the outer wrapper and key derivation algorithm OID */
readConstructed( stream, NULL, CTAG_KK_DA );
status = readFixedOID( stream, OID_PBKDF2, sizeofOID( OID_PBKDF2 ) );
if( cryptStatusError( status ) )
return( status );
/* Read the PBKDF2 parameters, limiting the salt and iteration count to
sane values */
status = readSequence( stream, &length );
if( cryptStatusError( status ) )
return( status );
endPos = stell( stream ) + length;
readOctetString( stream, queryInfo->salt, &queryInfo->saltLength,
2, CRYPT_MAX_HASHSIZE );
status = readShortInteger( stream, &value );
if( cryptStatusError( status ) )
return( status );
if( value < 1 || value > MAX_KEYSETUP_ITERATIONS )
return( CRYPT_ERROR_BADDATA );
queryInfo->keySetupIterations = ( int ) value;
queryInfo->keySetupAlgo = CRYPT_ALGO_HMAC_SHA;
if( stell( stream ) < endPos )
return( sseek( stream, endPos ) );
return( CRYPT_OK );
}
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int writeKeyDerivationInfo( INOUT STREAM *stream,
IN_HANDLE const CRYPT_CONTEXT iCryptContext )
{
MESSAGE_DATA msgData;
BYTE salt[ CRYPT_MAX_HASHSIZE + 8 ];
int saltLength, keySetupIterations, derivationInfoSize, status;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
REQUIRES( isHandleRangeValid( iCryptContext ) );
/* Get the key derivation information */
status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE,
&keySetupIterations,
CRYPT_CTXINFO_KEYING_ITERATIONS );
if( cryptStatusError( status ) )
return( status );
setMessageData( &msgData, salt, CRYPT_MAX_HASHSIZE );
status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_CTXINFO_KEYING_SALT );
if( cryptStatusError( status ) )
return( status );
saltLength = msgData.length;
derivationInfoSize = ( int ) sizeofObject( saltLength ) + \
sizeofShortInteger( keySetupIterations );
/* Write the PBKDF2 information */
writeConstructed( stream, sizeofOID( OID_PBKDF2 ) +
( int ) sizeofObject( derivationInfoSize ), CTAG_KK_DA );
writeOID( stream, OID_PBKDF2 );
writeSequence( stream, derivationInfoSize );
writeOctetString( stream, salt, saltLength, DEFAULT_TAG );
status = writeShortInteger( stream, keySetupIterations, DEFAULT_TAG );
zeroise( salt, CRYPT_MAX_HASHSIZE );
return( status );
}
/* Read/write CMS KEK data. This is the weird Spyrus key wrap that was
slipped into CMS, nothing seems to support this so we don't either */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int readCmsKek( INOUT STREAM *stream, INOUT QUERY_INFO *queryInfo )
{
long value;
int status;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isWritePtr( queryInfo, sizeof( QUERY_INFO ) ) );
/* Read the header */
readConstructed( stream, NULL, CTAG_RI_KEKRI );
status = readShortInteger( stream, &value );
if( cryptStatusError( status ) )
return( status );
if( value != KEK_VERSION )
return( CRYPT_ERROR_BADDATA );
return( CRYPT_ERROR_NOTAVAIL );
}
#if 0 /* 21/4/06 Disabled since it was never used */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3 ) ) \
static int writeCmsKek( INOUT STREAM *stream,
IN_HANDLE const CRYPT_CONTEXT iCryptContext,
IN_BUFFER( encryptedKeyLength ) const BYTE *encryptedKey,
IN_LENGTH_SHORT_MIN( MIN_KEYSIZE ) \
const int encryptedKeyLength )
{
STREAM localStream;
MESSAGE_DATA msgData;
BYTE kekInfo[ 128 + 8 ], label[ CRYPT_MAX_TEXTSIZE + 8 ];
const int algoIdInfoSize = \
sizeofContextAlgoID( iCryptContext, CRYPT_ALGO_NONE,
ALGOID_FLAG_NONE );
int kekInfoSize, labelSize, status;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isReadPtr( encryptedKey, encryptedKeyLength ) );
REQUIRES( isHandleRangeValid( iCryptContext ) );
REQUIRES( encryptedKeyLength >= MIN_KEYSIZE && \
encryptedKeyLength < MAX_INTLENGTH_SHORT );
if( cryptStatusError( algoIdInfoSize ) )
return( algoIdInfoSize );
/* Get the label */
setMessageData( &msgData, label, CRYPT_MAX_TEXTSIZE );
status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_CTXINFO_LABEL );
if( cryptStatusError( status ) )
return( status );
labelSize = msgData.length;
/* Determine the size of the KEK info. To save evaluating it twice in a
row and because it's short, we just write it to local buffers */
sMemOpen( &localStream, kekInfo, 128 );
writeSequence( &localStream, sizeofOID( OID_PWRIKEK ) + algoIdInfoSize );
writeOID( &localStream, OID_PWRIKEK );
status = writeContextCryptAlgoID( &localStream, iCryptContext );
if( cryptStatusOK( status ) )
kekInfoSize = stell( &localStream );
sMemDisconnect( &localStream );
if( cryptStatusError( status ) )
return( status );
/* Write the algorithm identifiers and encrypted key */
writeConstructed( stream, ( int ) sizeofShortInteger( KEK_VERSION ) + \
sizeofObject( sizeofObject( labelSize ) ) + \
kekInfoSize + sizeofObject( encryptedKeyLength ),
CTAG_RI_KEKRI );
writeShortInteger( stream, KEK_VERSION, DEFAULT_TAG );
writeSequence( stream, sizeofObject( labelSize ) );
writeOctetString( stream, label, labelSize, DEFAULT_TAG );
swrite( stream, kekInfo, kekInfoSize );
return( writeOctetString( stream, encryptedKey, encryptedKeyLength,
DEFAULT_TAG ) );
}
#endif /* 0 */
/* Read/write cryptlib KEK data:
[3] SEQUENCE {
version INTEGER (0),
keyDerivationAlgorithm [0] AlgorithmIdentifier OPTIONAL,
keyEncryptionAlgorithm AlgorithmIdentifier,
encryptedKey OCTET STRING
} */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int readCryptlibKek( 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 ) ) );
/* If it's a CMS KEK, read it as such */
if( peekTag( stream ) == CTAG_RI_KEKRI )
return( readCmsKek( stream, queryInfo ) );
/* Read the header */
readConstructed( stream, NULL, CTAG_RI_PWRI );
status = readShortInteger( stream, &value );
if( cryptStatusError( status ) )
return( status );
if( value != PWRI_VERSION )
return( CRYPT_ERROR_BADDATA );
/* Read the optional KEK derivation info and KEK algorithm info */
if( peekTag( stream ) == MAKE_CTAG( CTAG_KK_DA ) )
{
status = readKeyDerivationInfo( stream, queryInfo );
if( cryptStatusError( status ) )
return( status );
}
readSequence( stream, NULL );
readFixedOID( stream, OID_PWRIKEK, sizeofOID( OID_PWRIKEK ) );
status = readContextAlgoID( stream, NULL, queryInfo, DEFAULT_TAG );
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 ) );
}
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3 ) ) \
static int writeCryptlibKek( STREAM *stream,
IN_HANDLE const CRYPT_CONTEXT iCryptContext,
IN_BUFFER( encryptedKeyLength ) \
const BYTE *encryptedKey,
IN_LENGTH_SHORT_MIN( MIN_KEYSIZE ) \
const int encryptedKeyLength )
{
STREAM localStream;
BYTE derivationInfo[ CRYPT_MAX_HASHSIZE + 32 + 8 ], kekInfo[ 128 + 8 ];
BOOLEAN hasKeyDerivationInfo = TRUE;
const int algoIdInfoSize = sizeofCryptContextAlgoID( iCryptContext );
int derivationInfoSize = 0, kekInfoSize = DUMMY_INIT, value, status;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isReadPtr( encryptedKey, encryptedKeyLength ) );
REQUIRES( isHandleRangeValid( iCryptContext ) );
REQUIRES( encryptedKeyLength >= MIN_KEYSIZE && \
encryptedKeyLength < MAX_INTLENGTH_SHORT );
if( cryptStatusError( algoIdInfoSize ) )
return( algoIdInfoSize );
/* 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 )
{
hasKeyDerivationInfo = FALSE;
#if 0 /* 21/4/06 Disabled since it was never used */
MESSAGE_DATA msgData;
/* There's no password-derivation information present, see if there's
a label present */
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 ) );
}
#endif /* 0 */
}
/* 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 );
if( cryptStatusOK( status ) )
derivationInfoSize = stell( &localStream );
sMemDisconnect( &localStream );
if( cryptStatusError( status ) )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -