CryptEncrypt AES 256在加密最后一个块时失败

时间:2012-02-01 05:11:48

标签: c++ winapi encryption

首先,如果我在这里遗漏了什么,我道歉。这是我第一次尝试使用Windows CryptAPI,虽然我已经浏览了谷歌,MSDN,MSDN的例子等等,但我无法弄清楚为什么会出现这个问题。 我有以下代码,它应该复制在特定地址找到的操作码(字节块),加密它们,然后将它们写回。它绝不是一个完整的代码,它只进行很少的错误检查。我使用的是AES256。

bool CryptoClass::encrypt(DWORD address, DWORD len)
{
    DWORD dwBlockLen = 0; 
    DWORD dwBufferLen = 0; 
    DWORD dwCount = 0; 
    PBYTE pbBuffer = NULL;    
    dwBlockLen = AES_BLOCK_SIZE - AES_BLOCK_SIZE % ENCRYPT_BLOCK_SIZE; 
    dwBufferLen = dwBlockLen + ENCRYPT_BLOCK_SIZE; 
    if(pbBuffer = (BYTE *)malloc(dwBufferLen))
    {
        bool EOB = FALSE;
        while ( dwCount <= len) )
        {
            memcpy((void*)pbBuffer,(void*)address,dwBlockLen);              
            if ( (len - dwCount) < dwBlockLen) EOB = TRUE;              

            if(CryptEncrypt(hKey,NULL,EOB,0,pbBuffer,&dwBlockLen,dwBufferLen))
            {
                memcpy((void*)address,(void*)pbBuffer,dwBlockLen);
                address += dwBlockLen;                              
                dwCount += dwBlockLen;                              
            }
            else
            {
                error = GetLastError();
                MessageBoxA(NULL,"problem","error",MB_OK);
            }
        }
        free(pbBuffer);
       return true;
    }
    else return false;
}

根据我的理解,AES可以加密16字节的块,因此AES_BLOCK_SIZE定义为16。 我的ENCRYPT_BLOCK_SIZE也设置为8.我基本上复制了一个我在MSDN上找到的例子,并调整了AES256并用于内存而不是文件。 但是在我的while循环中,只要它到达缓冲区的末尾,其中FINAL设置为TRUE,CryptEncrypt就会失败。我已尝试过许多不同的方法来做到这一点,但总是失败。 是因为最后的缓冲区小于16字节? 有些人可以帮忙,在加密方面我是一个完全的菜鸟。 谢谢 编辑:GetLastError返回:0x000000ea

3 个答案:

答案 0 :(得分:4)

您收到错误ERROR_MORE_DATA。这转化为:

如果为pbData分配的缓冲区不足以容纳加密数据,则GetLastError返回ERROR_MORE_DATA并将所需的缓冲区大小(以字节为单位)存储在pdwDataLen指向的DWORD值中。

如果该方法使用CBC加密(微软,其智慧,未在其API中指定模式或填充算法),则应执行以下算法来计算缓冲区的输出大小:

buffer_size =(plain_size_bytes / AES_BLOCK_SIZE + 1)* AES_BLOCK_SIZE;

换句话说,如果plain_size_bytes是N * AES_BLOCK_SIZE,您仍然需要一个完整的填充块。这是因为你总是需要执行填充,否则unpadding算法不能区分纯文本和填充字节。

当然,您也可以简单地创建一个plain_size_bytes + AES_BLOCK_SIZE的缓冲区,并使用pdwDataLen值来获取实际长度。

编辑:如果你单独加密每个纯文本块,并且密码使用带填充的CBC或ECB,那么最后一个普通块可能需要2个整块,因为上面

答案 1 :(得分:1)

while ( address < (address + len) )

我的神秘答案是“想一想 - 你不会永远想想它,但......”

答案 2 :(得分:0)

if ( (len - dwCount) < dwBlockLen) EOB = TRUE;

也许应该像

if ( (len - dwCount) < dwBlockLen)
{
    EOB = TRUE;
    dwBlockLen = ENCRYPT_BLOCK_SIZE;
}