VOID BlockCipherImp::encrypt()

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 );
        }
    }
}