зеркало из https://github.com/microsoft/SymCrypt.git
326 строки
10 KiB
C++
326 строки
10 KiB
C++
//
|
|
// capi_imp_blockcipherpattern.cpp
|
|
//
|
|
// Copyright (c) Microsoft Corporation. Licensed under the MIT license.
|
|
//
|
|
|
|
//
|
|
// Perf Invariant: buf 1 contains the key handle
|
|
//
|
|
template<>
|
|
VOID
|
|
algImpKeyPerfFunction<ImpXxx, AlgXxx, ModeXxx>(PBYTE buf1, PBYTE buf2, PBYTE buf3, SIZE_T keySize )
|
|
{
|
|
UNREFERENCED_PARAMETER( buf3 );
|
|
|
|
HCRYPTKEY hKey;
|
|
struct {
|
|
BLOBHEADER header;
|
|
DWORD klen;
|
|
BYTE key[CAPI_MAX_KEY_SIZE];
|
|
} capiKeyBlob;
|
|
|
|
capiKeyBlob.header.bType = PLAINTEXTKEYBLOB;
|
|
capiKeyBlob.header.bVersion = CUR_BLOB_VERSION;
|
|
capiKeyBlob.header.reserved = 0;
|
|
capiKeyBlob.klen = (ULONG) keySize;
|
|
if( BlockCipherImpState<ImpXxx,AlgXxx,ModeXxx>::calg[ keySize ] == -1 )
|
|
{
|
|
// We don't have a CALG for this key size.
|
|
return;
|
|
}
|
|
|
|
capiKeyBlob.header.aiKeyAlg = BlockCipherImpState<ImpXxx,AlgXxx,ModeXxx>::calg[ keySize ];
|
|
|
|
SYMCRYPT_ASSERT( keySize <= CAPI_MAX_KEY_SIZE );
|
|
memcpy( &capiKeyBlob.key[0], buf2, keySize );
|
|
|
|
CHECK( CryptImportKey( g_capiProvider, (PBYTE) &capiKeyBlob, sizeof( capiKeyBlob ), 0, 0, &hKey ),
|
|
"CAPI key import failure" );
|
|
|
|
CHECK( NT_SUCCESS( CapiRc2KeySupport<AlgXxx>( hKey ) ), "CAPI RC2 key support failure" );
|
|
|
|
DWORD mode = CAPI_MODE( ALG_MODE );
|
|
if( mode != CRYPT_MODE_CBC )
|
|
{
|
|
CHECK( CryptSetKeyParam( hKey, KP_MODE, (PBYTE) &mode, 0 ), "Failed to set mode" );
|
|
}
|
|
*(HCRYPTKEY *) buf1 = hKey;
|
|
}
|
|
|
|
template<>
|
|
VOID
|
|
algImpCleanPerfFunction<ImpXxx, AlgXxx, ModeXxx>( PBYTE buf1, PBYTE buf2, PBYTE buf3 )
|
|
{
|
|
UNREFERENCED_PARAMETER( buf2 );
|
|
UNREFERENCED_PARAMETER( buf3 );
|
|
|
|
CHECK( CryptDestroyKey( *(HCRYPTKEY *) buf1 ), "Failed to destroy key" );
|
|
}
|
|
|
|
template<>
|
|
VOID
|
|
algImpDataPerfFunction<ImpXxx, AlgXxx, ModeXxx>(PBYTE buf1, PBYTE buf2, PBYTE buf3, SIZE_T dataSize )
|
|
{
|
|
UNREFERENCED_PARAMETER( buf2 );
|
|
|
|
ULONG len = (ULONG) dataSize;
|
|
CHECK( CryptEncrypt( *(HCRYPTKEY*) buf1, 0, FALSE, 0, buf3, &len, len ), "Encryption failure" );
|
|
}
|
|
|
|
template<>
|
|
VOID
|
|
algImpDecryptPerfFunction<ImpXxx, AlgXxx, ModeXxx>(PBYTE buf1, PBYTE buf2, PBYTE buf3, SIZE_T dataSize )
|
|
{
|
|
UNREFERENCED_PARAMETER( buf2 );
|
|
|
|
ULONG len = (ULONG) dataSize;
|
|
CHECK( CryptDecrypt( *(HCRYPTKEY*) buf1, 0, FALSE, 0, buf3, &len ), "Decryption failure" );
|
|
}
|
|
|
|
|
|
|
|
BlockCipherImp<ImpXxx, AlgXxx, ModeXxx>::BlockCipherImp()
|
|
{
|
|
state.hKey = 0;
|
|
|
|
CapiSetCalgArray<AlgXxx>( &state.calg[0] );
|
|
|
|
m_perfDataFunction = &algImpDataPerfFunction <ImpXxx, AlgXxx, ModeXxx>;
|
|
m_perfDecryptFunction = &algImpDecryptPerfFunction <ImpXxx, AlgXxx, ModeXxx>;
|
|
m_perfKeyFunction = &algImpKeyPerfFunction <ImpXxx, AlgXxx, ModeXxx>;
|
|
m_perfCleanFunction = &algImpCleanPerfFunction <ImpXxx, AlgXxx, ModeXxx>;
|
|
}
|
|
|
|
template<>
|
|
BlockCipherImp<ImpXxx, AlgXxx, ModeXxx>::~BlockCipherImp()
|
|
{
|
|
if( state.hKey != 0 )
|
|
{
|
|
CryptDestroyKey( state.hKey );
|
|
state.hKey = 0;
|
|
}
|
|
}
|
|
|
|
SIZE_T BlockCipherImp<ImpXxx, AlgXxx, ModeXxx>::coreBlockLen()
|
|
{
|
|
return SCSHIM_XXX_BLOCK_SIZE;
|
|
}
|
|
|
|
ULONG BlockCipherImpState<ImpXxx,AlgXxx,ModeXxx>::calg[CAPI_CALG_ARRAY_SIZE];
|
|
|
|
NTSTATUS
|
|
BlockCipherImp<ImpXxx, AlgXxx, ModeXxx>::setKey( _In_reads_( cbKey ) PCBYTE pbKey, SIZE_T cbKey )
|
|
{
|
|
if( state.hKey != 0 )
|
|
{
|
|
CHECK( CryptDestroyKey( state.hKey ), "?" );
|
|
state.hKey = 0;
|
|
}
|
|
|
|
struct {
|
|
BLOBHEADER header;
|
|
DWORD klen;
|
|
BYTE key[CAPI_MAX_KEY_SIZE];
|
|
} capiKeyBlob;
|
|
|
|
if( (ModeXxx::flags & MODE_FLAG_CFB) != 0 && g_modeCfbShiftParam != 1 )
|
|
{
|
|
return STATUS_NOT_SUPPORTED;
|
|
}
|
|
|
|
capiKeyBlob.header.bType = PLAINTEXTKEYBLOB;
|
|
capiKeyBlob.header.bVersion = CUR_BLOB_VERSION;
|
|
capiKeyBlob.header.reserved = 0;
|
|
capiKeyBlob.klen = (ULONG) cbKey;
|
|
CHECK( cbKey < ARRAY_SIZE( state.calg ), "Key too long" );
|
|
if( state.calg[ cbKey ] == -1 || g_rc2EffectiveKeyLength > 128 || g_rc2EffectiveKeyLength < 16 )
|
|
{
|
|
// We don't have a CALG for this key size, or the effective key size is too large
|
|
return STATUS_NOT_SUPPORTED;
|
|
}
|
|
|
|
capiKeyBlob.header.aiKeyAlg = state.calg[ cbKey ];
|
|
|
|
CHECK( cbKey < sizeof( capiKeyBlob.key ), "Key too large for CAPI blob" );
|
|
memcpy( &capiKeyBlob.key[0], pbKey, cbKey );
|
|
|
|
CHECK3( CryptImportKey( g_capiProvider, (PBYTE) &capiKeyBlob, sizeof( capiKeyBlob ), 0, 0, &state.hKey ),
|
|
"CAPI key import failure %08x", GetLastError() );
|
|
|
|
CHECK3( NT_SUCCESS(CapiRc2KeySupport<AlgXxx>( state.hKey )) , "Rc2 key support failure %d", g_rc2EffectiveKeyLength );
|
|
|
|
DWORD mode = CAPI_MODE( ALG_MODE );
|
|
CHECK( CryptSetKeyParam( state.hKey, KP_MODE, (PBYTE) &mode, 0 ), "Failed to set mode" );
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
VOID BlockCipherImp<ImpXxx, AlgXxx, ModeXxx>::encrypt(
|
|
_Inout_updates_opt_( cbChain ) PBYTE pbChain,
|
|
SIZE_T cbChain,
|
|
_In_reads_( cbData ) PCBYTE pbSrc,
|
|
_Out_writes_( cbData ) PBYTE pbDst,
|
|
SIZE_T cbData )
|
|
{
|
|
BYTE buf[32];
|
|
ULONG len;
|
|
SIZE_T coreBlockLength = coreBlockLen();
|
|
SIZE_T cbWhole;
|
|
SIZE_T cbPartial;
|
|
|
|
//
|
|
// You can set a new IV value, but it is only picked up if CAPI thinks you starting a new encryption.
|
|
// To do that we have to call Encrypt with the final flag.
|
|
//
|
|
if( cbChain > 0 )
|
|
{
|
|
CHECK( cbChain == chainBlockLen(), "?" );
|
|
len = 0;
|
|
CHECK( CryptEncrypt( state.hKey, 0, TRUE, 0, buf, &len, 32 ), "Failed encrypt with final=TRUE" );
|
|
CHECK3( CryptSetKeyParam( state.hKey, KP_IV, pbChain, 0 ), "Failed to set IV %08x", GetLastError() );
|
|
}
|
|
memcpy( pbDst, pbSrc, cbData );
|
|
|
|
cbPartial = cbData % coreBlockLength;
|
|
|
|
if( ( ModeXxx::flags & MODE_FLAG_CFB ) != 0 && cbPartial > 0 )
|
|
{
|
|
CHECK( cbChain == coreBlockLength, "?" );
|
|
|
|
//
|
|
// CFB mode can have arbitrary length messages, but CAPI doesn't support that.
|
|
// To help test SymCrypt we implement it here using messages that are a multiple of the block size.
|
|
//
|
|
// First we do the whole blocks
|
|
//
|
|
|
|
cbWhole = cbData - cbPartial;
|
|
if( cbWhole > 0 )
|
|
{
|
|
len = (DWORD) cbWhole;
|
|
CHECK( CryptEncrypt( state.hKey, 0, FALSE, 0, pbDst, &len, len ), "Encryption failure" );
|
|
CHECK( len == cbWhole, "Length failure" );
|
|
}
|
|
|
|
//
|
|
// Then the remaining bytes
|
|
//
|
|
CHECK( cbPartial < coreBlockLength, "??" );
|
|
|
|
memcpy( buf, pbDst + cbWhole, cbPartial );
|
|
len = (DWORD) coreBlockLength;
|
|
CHECK( CryptEncrypt( state.hKey, 0, FALSE, 0, buf, &len, len ), "Encryption failure" );
|
|
CHECK( len == coreBlockLength, "Length failure" );
|
|
memcpy( pbDst + cbWhole, buf, cbPartial );
|
|
|
|
//
|
|
// Now we have to re-construct the proper chaining value
|
|
//
|
|
if( cbData >= coreBlockLength )
|
|
{
|
|
memcpy( pbChain, pbDst + cbData - cbChain, cbChain );
|
|
}
|
|
else
|
|
{
|
|
memcpy( pbChain, pbChain + cbData, cbChain - cbData );
|
|
memcpy( pbChain + cbChain - cbData, pbDst, cbData );
|
|
}
|
|
|
|
//
|
|
// And set the chaining state inside CAPI
|
|
//
|
|
//len = 0;
|
|
//CHECK( CryptEncrypt( state.hKey, 0, TRUE, 0, buf, &len, 32 ), "Failed encrypt with final=TRUE" );
|
|
//CHECK3( CryptSetKeyParam( state.hKey, KP_IV, pbChain, 0 ), "Failed to set IV %08x", GetLastError() );
|
|
|
|
}
|
|
else
|
|
{
|
|
len = (ULONG) cbData;
|
|
CHECK( CryptEncrypt( state.hKey, 0, FALSE, 0, pbDst, &len, len ), "Encryption failure" );
|
|
CHECK( len == cbData, "Length failure" );
|
|
|
|
if( cbChain > 0 && cbData > 0 )
|
|
{
|
|
CHECK( cbChain <= cbData, "?" );
|
|
memcpy( pbChain, pbDst + cbData - cbChain, cbChain );
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID BlockCipherImp<ImpXxx, AlgXxx, ModeXxx>::decrypt(
|
|
_Inout_updates_opt_( cbChain ) PBYTE pbChain,
|
|
SIZE_T cbChain,
|
|
_In_reads_( cbData ) PCBYTE pbSrc,
|
|
_Out_writes_( cbData ) PBYTE pbDst,
|
|
SIZE_T cbData )
|
|
{
|
|
BYTE buf[32];
|
|
ULONG len;
|
|
SIZE_T coreBlockLength = coreBlockLen();
|
|
SIZE_T cbWhole;
|
|
SIZE_T cbPartial;
|
|
|
|
//
|
|
// You can set a new IV value, but it is only picked up if CAPI thinks you starting a new encryption.
|
|
// To do that we have to call Encrypt with the final flag.
|
|
//
|
|
if( cbChain > 0 && cbData > 0)
|
|
{
|
|
len = 0;
|
|
CHECK( CryptEncrypt( state.hKey, 0, TRUE, 0, buf, &len, 32 ), "Failed encrypt with final=TRUE" );
|
|
CHECK( CryptSetKeyParam( state.hKey, KP_IV, pbChain, 0 ), "Failed to set IV" );
|
|
CHECK( cbChain <= sizeof( buf ), "?" );
|
|
|
|
if( cbData < cbChain )
|
|
{
|
|
memcpy( pbChain, pbChain + cbData, cbChain - cbData );
|
|
memcpy( pbChain + cbChain - cbData, pbSrc, cbData );
|
|
}
|
|
else
|
|
{
|
|
memcpy( pbChain, pbSrc + cbData - cbChain, cbChain );
|
|
}
|
|
}
|
|
|
|
memcpy( pbDst, pbSrc, cbData );
|
|
cbPartial = cbData % coreBlockLength;
|
|
|
|
if( ( ModeXxx::flags & MODE_FLAG_CFB ) != 0 && cbPartial > 0 )
|
|
{
|
|
CHECK( cbChain == coreBlockLength, "?" );
|
|
|
|
cbWhole = cbData -cbPartial;
|
|
|
|
if( cbWhole > 0 )
|
|
{
|
|
len = (DWORD) cbWhole;
|
|
CHECK( CryptDecrypt( state.hKey, 0, FALSE, 0, pbDst, &len ), "Decryption failure" );
|
|
CHECK( len == cbWhole, "Length failure" );
|
|
}
|
|
|
|
memcpy( buf, pbDst + cbWhole, cbPartial );
|
|
len = (DWORD) coreBlockLength;
|
|
CHECK( CryptDecrypt( state.hKey, 0, FALSE, 0, buf, &len ), "Decryption failure" );
|
|
CHECK( len == coreBlockLength, "Length failure" );
|
|
memcpy( pbDst + cbWhole, buf, cbPartial );
|
|
|
|
//
|
|
// Se the proper chaining value again
|
|
//
|
|
//len = 0;
|
|
//CHECK( CryptEncrypt( state.hKey, 0, TRUE, 0, buf, &len, 32 ), "Failed Encrypt with final=TRUE" );
|
|
//CHECK( CryptSetKeyParam( state.hKey, KP_IV, pbChain, 0 ), "Failed to set IV" );
|
|
//
|
|
}
|
|
else
|
|
{
|
|
len = (ULONG) cbData;
|
|
CHECK( CryptDecrypt( state.hKey, 0, FALSE, 0, pbDst, &len ), "Decryption failure" );
|
|
CHECK( len == cbData, "Length failure" );
|
|
}
|
|
}
|
|
|
|
|