in unittest/lib/capi_imp_blockcipherpattern.cpp [159:250]
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 );
}
}
}