📄 mech_pkwrap.c
字号:
return( CRYPT_OK );
}
/* Perform PKCS #1 wrapping/unwrapping. There are several variations of
this that are handled through common PKCS #1 mechanism functions */
typedef enum { PKCS1_WRAP_NONE, PKCS1_WRAP_NORMAL, PKCS1_WRAP_RAW,
PKCS1_WRAP_PGP, PKCS1_WRAP_LAST } PKCS1_WRAP_TYPE;
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int pkcs1Wrap( INOUT MECHANISM_WRAP_INFO *mechanismInfo,
IN_ENUM( PKCS1_WRAP ) const PKCS1_WRAP_TYPE type )
{
CRYPT_ALGO_TYPE cryptAlgo;
BYTE *wrappedData = mechanismInfo->wrappedData, *dataPtr;
int payloadSize, length, dataBlockSize, status;
#ifdef USE_PGP
int pgpAlgoID = DUMMY_INIT;
#endif /* USE_PGP */
assert( isWritePtr( mechanismInfo, sizeof( MECHANISM_WRAP_INFO ) ) );
REQUIRES( type > PKCS1_WRAP_NONE && type < PKCS1_WRAP_LAST );
/* Clear return value */
if( mechanismInfo->wrappedData != NULL )
{
memset( mechanismInfo->wrappedData, 0,
mechanismInfo->wrappedDataLength );
}
/* Get various algorithm parameters */
status = getPkcAlgoParams( mechanismInfo->wrapContext, &cryptAlgo,
&length );
if( cryptStatusError( status ) )
return( status );
/* If this is just a length check, we're done */
if( mechanismInfo->wrappedData == NULL )
{
/* Determine how long the encrypted value will be. In the case of
Elgamal it's just an estimate since it can change by up to two
bytes depending on whether the values have the high bit set or
not, which requires zero-padding of the ASN.1-encoded integers.
This is rather nasty because it means that we can't tell how
large an encrypted value will be without actually creating it.
The 10-byte length at the start is for the ASN.1 SEQUENCE (= 4)
and 2 * INTEGER (= 2*3) encoding */
mechanismInfo->wrappedDataLength = \
( cryptAlgo == CRYPT_ALGO_ELGAMAL ) ? \
10 + ( 2 * ( length + 1 ) ) : length;
return( CRYPT_OK );
}
/* Make sure that there's enough room for the wrapped key data */
if( length > mechanismInfo->wrappedDataLength )
return( CRYPT_ERROR_OVERFLOW );
/* Get the payload details, either as data passed in by the caller or
from the key context */
if( type == PKCS1_WRAP_RAW )
payloadSize = mechanismInfo->keyDataLength;
else
{
status = krnlSendMessage( mechanismInfo->keyContext,
IMESSAGE_GETATTRIBUTE, &payloadSize,
CRYPT_CTXINFO_KEYSIZE );
if( cryptStatusError( status ) )
return( status );
}
#ifdef USE_PGP
if( type == PKCS1_WRAP_PGP )
{
CRYPT_ALGO_TYPE sessionKeyAlgo;
/* PGP includes an additional algorithm specifier and checksum with
the wrapped key so we adjust the length to take this into
account */
status = krnlSendMessage( mechanismInfo->keyContext,
IMESSAGE_GETATTRIBUTE, &sessionKeyAlgo,
CRYPT_CTXINFO_ALGO );
if( cryptStatusOK( status ) )
status = cryptlibToPgpAlgo( sessionKeyAlgo, &pgpAlgoID );
if( cryptStatusError( status ) )
return( status );
payloadSize += 3; /* 1-byte algo ID + 2-byte checksum */
}
#endif /* USE_PGP */
/* Perform a preliminary check for an excessively long payload to make
it explicit, however generatePkcs1DataBlock() will also perform a
more precise check when it performs the data formatting */
if( payloadSize >= length )
return( CRYPT_ERROR_OVERFLOW );
/* Generate the PKCS #1 data block with room for the payload at the end */
status = generatePkcs1DataBlock( wrappedData, length, &dataBlockSize,
payloadSize );
if( cryptStatusError( status ) )
{
zeroise( wrappedData, length );
return( status );
}
ENSURES( dataBlockSize + payloadSize == length );
/* Copy the payload in at the last possible moment, then encrypt it */
dataPtr = wrappedData + dataBlockSize;
switch( type )
{
case PKCS1_WRAP_NORMAL:
status = extractKeyData( mechanismInfo->keyContext, dataPtr,
payloadSize, "keydata", 7 );
break;
case PKCS1_WRAP_RAW:
memcpy( dataPtr, mechanismInfo->keyData, payloadSize );
break;
#ifdef USE_PGP
case PKCS1_WRAP_PGP:
*dataPtr++ = pgpAlgoID;
status = extractKeyData( mechanismInfo->keyContext, dataPtr,
payloadSize - 3, "keydata", 7 );
if( cryptStatusOK( status ) )
{
status = pgpGenerateChecksum( dataPtr, payloadSize - 1,
payloadSize - ( 1 + UINT16_SIZE ) );
}
break;
#endif /* USE_PGP */
default:
retIntError();
}
if( cryptStatusError( status ) )
{
zeroise( wrappedData, length );
return( status );
}
/* Wrap the encoded data using the public key */
return( pkcWrapData( mechanismInfo, wrappedData, length,
( type == PKCS1_WRAP_PGP ) ? TRUE : FALSE,
( cryptAlgo == CRYPT_ALGO_ELGAMAL ) ? TRUE : FALSE ) );
}
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int pkcs1Unwrap( INOUT MECHANISM_WRAP_INFO *mechanismInfo,
IN_ENUM( PKCS1_WRAP ) const PKCS1_WRAP_TYPE type )
{
CRYPT_ALGO_TYPE cryptAlgo;
MESSAGE_DATA msgData;
BYTE decryptedData[ CRYPT_MAX_PKCSIZE + 8 ];
const BYTE *payloadPtr;
int length, dataBlockSize, status;
assert( isWritePtr( mechanismInfo, sizeof( MECHANISM_WRAP_INFO ) ) );
REQUIRES( type > PKCS1_WRAP_NONE && type < PKCS1_WRAP_LAST );
/* Clear the return value if we're returning raw data */
if( type == PKCS1_WRAP_RAW )
memset( mechanismInfo->keyData, 0, mechanismInfo->keyDataLength );
/* Get various algorithm parameters */
status = getPkcAlgoParams( mechanismInfo->wrapContext, &cryptAlgo,
&length );
if( cryptStatusError( status ) )
return( status );
/* Decrypt the data */
status = pkcUnwrapData( mechanismInfo, decryptedData, CRYPT_MAX_PKCSIZE,
&length, length,
( type == PKCS1_WRAP_PGP ) ? TRUE : FALSE,
( cryptAlgo == CRYPT_ALGO_ELGAMAL ) ? TRUE : FALSE );
if( cryptStatusError( status ) )
return( status );
/* Recover the PKCS #1 data block, with the payload at the end */
status = recoverPkcs1DataBlock( decryptedData, length, &dataBlockSize );
if( cryptStatusError( status ) )
{
zeroise( decryptedData, CRYPT_MAX_PKCSIZE );
return( status );
}
payloadPtr = decryptedData + dataBlockSize;
length -= dataBlockSize;
/* Return the result to the caller or load it into a context as a key */
switch( type )
{
#ifdef USE_PGP
case PKCS1_WRAP_PGP:
/* PGP includes extra wrapping around the key so we have to
process that before we can load it */
status = pgpExtractKey( &mechanismInfo->keyContext, payloadPtr,
length );
if( cryptStatusError( status ) )
break;
payloadPtr++; /* Skip algorithm ID */
length -= 3; /* Subtract extra wrapping length */
if( length < MIN_KEYSIZE )
return( CRYPT_ERROR_BADDATA );
/* Fall through */
#endif /* USE_PGP */
case PKCS1_WRAP_NORMAL:
/* Load the decrypted keying information into the session key
context */
setMessageData( &msgData, ( void * ) payloadPtr, length );
status = krnlSendMessage( mechanismInfo->keyContext,
IMESSAGE_SETATTRIBUTE_S, &msgData,
CRYPT_CTXINFO_KEY );
if( cryptArgError( status ) )
{
/* If there was an error with the key value or size convert
the return value into something more appropriate */
status = CRYPT_ERROR_BADDATA;
}
break;
case PKCS1_WRAP_RAW:
/* Return the result to the caller */
if( length > mechanismInfo->keyDataLength )
status = CRYPT_ERROR_OVERFLOW;
else
{
memcpy( mechanismInfo->keyData, payloadPtr, length );
mechanismInfo->keyDataLength = length;
}
break;
default:
retIntError();
}
zeroise( decryptedData, CRYPT_MAX_PKCSIZE );
return( status );
}
CHECK_RETVAL STDC_NONNULL_ARG( ( 2 ) ) \
int exportPKCS1( STDC_UNUSED void *dummy,
INOUT MECHANISM_WRAP_INFO *mechanismInfo )
{
UNUSED_ARG( dummy );
assert( isWritePtr( mechanismInfo, sizeof( MECHANISM_WRAP_INFO ) ) );
return( pkcs1Wrap( mechanismInfo,
( mechanismInfo->keyContext == CRYPT_UNUSED ) ? \
PKCS1_WRAP_RAW : PKCS1_WRAP_NORMAL ) );
}
CHECK_RETVAL STDC_NONNULL_ARG( ( 2 ) ) \
int importPKCS1( STDC_UNUSED void *dummy,
INOUT MECHANISM_WRAP_INFO *mechanismInfo )
{
UNUSED_ARG( dummy );
assert( isWritePtr( mechanismInfo, sizeof( MECHANISM_WRAP_INFO ) ) );
return( pkcs1Unwrap( mechanismInfo,
( mechanismInfo->keyData != NULL ) ? \
PKCS1_WRAP_RAW : PKCS1_WRAP_NORMAL ) );
}
#ifdef USE_PGP
CHECK_RETVAL STDC_NONNULL_ARG( ( 2 ) ) \
int exportPKCS1PGP( STDC_UNUSED void *dummy,
INOUT MECHANISM_WRAP_INFO *mechanismInfo )
{
UNUSED_ARG( dummy );
assert( isWritePtr( mechanismInfo, sizeof( MECHANISM_WRAP_INFO ) ) );
return( pkcs1Wrap( mechanismInfo, PKCS1_WRAP_PGP ) );
}
CHECK_RETVAL STDC_NONNULL_ARG( ( 2 ) ) \
int importPKCS1PGP( STDC_UNUSED void *dummy,
INOUT MECHANISM_WRAP_INFO *mechanismInfo )
{
UNUSED_ARG( dummy );
assert( isWritePtr( mechanismInfo, sizeof( MECHANISM_WRAP_INFO ) ) );
return( pkcs1Unwrap( mechanismInfo, PKCS1_WRAP_PGP ) );
}
#endif /* USE_PGP */
/****************************************************************************
* *
* OAEP Key Wrap/Unwrap Mechanisms *
* *
****************************************************************************/
/* If OAEP is used with SHA2-512 in the PRF then the standard
CRYPT_MAX_HASHSIZE value isn't sufficient to contain the hash data any
more so we have to define a special larger-than-normal maximum hash size
to contain it */
#define OAEP_MAX_HASHSIZE 64
/* Get the lHash value used for OAEP. In theory this should be a hash of a
label applied to the OAEP operation but this is never used so what ends
up being used is a fixed hash of an empty string. Since this is
constant we can use a pre-calculated value for each hash algorithm */
typedef struct {
const CRYPT_ALGO_TYPE hashAlgo;
BUFFER_FIXED( lHashSize ) \
const BYTE FAR_BSS *lHash;
const int lHashSize;
} LHASH_INFO;
static const LHASH_INFO FAR_BSS lHashInfo[] = {
{ CRYPT_ALGO_SHA1, ( const BYTE * ) /* For pedantic compilers */
"\xDA\x39\xA3\xEE\x5E\x6B\x4B\x0D\x32\x55\xBF\xEF\x95\x60\x18\x90"
"\xAF\xD8\x07\x09", 20 },
{ CRYPT_ALGO_SHA2, ( const BYTE * ) /* For pedantic compilers */
"\xE3\xB0\xC4\x42\x98\xFC\x1C\x14\x9A\xFB\xF4\xC8\x99\x6F\xB9\x24"
"\x27\xAE\x41\xE4\x64\x9B\x93\x4C\xA4\x95\x99\x1B\x78\x52\xB8\x55", 32 },
#ifdef USE_SHA2_512
/* SHA2-512 is only available on systems with 64-bit data type support,
at the moment this is only used internally for some PRFs so we have
to identify it via a kludge on the SHA2 algorithm ID */
{ CRYPT_ALGO_SHA2 + 1, ( const BYTE * ) /* For pedantic compilers */
"\xCF\x83\xE1\x35\x7E\xEF\xB8\xBD\xF1\x54\x28\x50\xD6\x6D\x80\x07"
"\xD6\x20\xE4\x05\x0B\x57\x15\xDC\x83\xF4\xA9\x21\xD3\x6C\xE9\xCE"
"\x47\xD0\xD1\x3C\x5D\x85\xF2\xB0\xFF\x83\x18\xD2\x87\x7E\xEC\x2F"
"\x63\xB9\x31\xBD\x47\x41\x7A\x81\xA5\x38\x32\x7A\xF9\x27\xDA\x3E", 64 },
#endif /* USE_SHA2_512 */
{ CRYPT_ALGO_NONE, NULL, 0 }, { CRYPT_ALGO_NONE, NULL, 0 }
};
CHECK_RETVAL STDC_NONNULL_ARG( ( 3 ) ) \
static int getOaepHash( OUT_BUFFER_OPT( lHashMaxLen, *lHashLen ) void *lHash,
IN_LENGTH_SHORT_Z const int lHashMaxLen,
OUT_LENGTH_SHORT_Z int *lHashLen,
IN_ALGO const CRYPT_ALGO_TYPE hashAlgo )
{
int i;
assert( ( lHash == NULL && lHashMaxLen == 0 ) || \
isWritePtr( lHash, lHashMaxLen ) );
REQUIRES( ( lHash == NULL && lHashMaxLen == 0 ) || \
( lHashMaxLen >= OAEP_MAX_HASHSIZE && \
lHashMaxLen < MAX_INTLENGTH_SHORT ) );
REQUIRES( hashAlgo >= CRYPT_ALGO_FIRST_HASH && \
hashAlgo <= CRYPT_ALGO_LAST_HASH );
/* Clear return value */
if( lHash != NULL )
zeroise( lHash, lHashMaxLen );
*lHashLen = 0;
for( i = 0; lHashInfo[ i ].hashAlgo != CRYPT_ALGO_NONE && \
i < FAILSAFE_ARRAYSIZE( lHashInfo, LHASH_INFO ); i++ )
{
if( lHashInfo[ i ].hashAlgo == hashAlgo )
{
if( lHash != NULL )
{
memcpy( lHash, lHashInfo[ i ].lHash,
lHashInfo[ i ].lHashSize );
}
*lHashLen = lHashInfo[ i ].lHashSize;
return( CRYPT_OK );
}
}
ENSURES( i < FAILSAFE_ARRAYSIZE( lHashInfo, LHASH_INFO ) );
if( lHash != NULL )
zeroise( lHash, lHashMaxLen );
return( CRYPT_ERROR_NOTAVAIL );
}
#define getOaepHashSize( hashLen, hashAlgo ) \
getOaepHash( NULL, 0, hashLen, hashAlgo )
/* OAEP mask generation function MGF1 */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3 ) ) \
static int mgf1( OUT_BUFFER_FIXED( maskLen ) void *mask,
IN_LENGTH_PKC const int maskLen,
IN_BUFFER( seedLen ) const void *seed,
IN_LENGTH_PKC const int seedLen,
IN_ALGO const CRYPT_ALGO_TYPE hashAlgo )
{
HASHFUNCTION hashFunction;
HASHINFO hashInfo;
BYTE countBuffer[ 4 + 8 ], maskBuffer[ OAEP_MAX_HASHSIZE + 8 ];
BYTE *maskOutPtr = mask;
int hashSize, maskIndex, blockCount = 0, iterationCount;
assert( isWritePtr( mask, maskLen ) );
assert( isReadPtr( seed, seedLen ) );
REQUIRES( maskLen >= 16 && maskLen <= CRYPT_MAX_PKCSIZE );
REQUIRES( seedLen >= 16 && seedLen <= CRYPT_MAX_PKCSIZE );
REQUIRES( hashAlgo >= CRYPT_ALGO_FIRST_HASH && \
hashAlgo <= CRYPT_ALGO_LAST_HASH );
getHashParameters( hashAlgo, &hashFunction, &hashSize );
/* Set up the block counter buffer. This will never have more than the
last few bits set (8 bits = 5120 bytes of mask for the smallest hash,
SHA-1) so we only change the last byte */
memset( countBuffer, 0, 4 );
/* Produce enough blocks of output to fill the mask */
for( maskIndex = 0, iterationCount = 0;
maskIndex < maskLen && iterationCount < FAILSAFE_ITERATIONS_MED;
maskIndex += hashSize, maskOutPtr += hashSize, iterationCount++ )
{
const int noMaskBytes = ( maskLen - maskIndex > hashSize ) ? \
hashSize : maskLen - maskIndex;
/* Calculate hash( seed || counter ) */
countBuffer[ 3 ] = ( BYTE ) blockCount++;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -