已经对齐的Windows CryptoAPI对称编码/解码块

时间:2016-10-25 11:16:15

标签: c++ aes padding cryptoapi ecb

我需要从OpenSSL迁移到MS CryptoAPI。

当我使用OpenSSL时,我得到了N字节(已经对齐 - 例如,假设数据长度= 32bytes)的数据,并将其从一个缓冲区编码/解码到另一个缓冲区。一切正常。

现在我必须"使用CryptoAPI!"。 所以我写了类似的东西:

    // Import AES key
    if(!CryptImportKey(m_hProvider, (CONST BYTE*)&aeskey, structsize, NULL, 0, &m_hAesKey ) ) {
        throw WinAESException("SetKey: Import key failed");
    }

    // Set Mode
    DWORD dwMode = CRYPT_MODE_ECB; //I can also use CRYPT_MODE_CBC with set of IV but let simple the code;
    if(!CryptSetKeyParam(m_hAesKey, KP_MODE, (BYTE*)&dwMode, 0)) {
        throw WinAESException("SetKey: Set ECB mode failed");
    }

它运作正常, 现在我尝试编码数据

    DWORD d = (DWORD)psize;
    result = CryptEncrypt( m_hAesKey, NULL, TRUE, 0, buffer, &d, (DWORD)bsize );

我看到了什么?数据的编码部分大于源。 我知道CryptEncrypt函数以某种方式填充了填充数据吗?

无论如何,是否有可能将编码结果与普通数据相同?

我不使用非对齐块,我希望,当我加密32字节时,准确得到32字节,而不是48 ...

当我测试预期的大小时

    DWORD d = 16;
    result = CryptEncrypt( m_hAesKey, NULL, TRUE, 0, 0, &d, (DWORD)bsize );  //need 32

    d = 32;
    result = CryptEncrypt( m_hAesKey, NULL, TRUE, 0, 0, &d, (DWORD)bsize );  //need 48 

    d = 48;
    result = CryptEncrypt( m_hAesKey, NULL, TRUE, 0, 0, &d, (DWORD)bsize );   //need 64

    d = 64;
    result = CryptEncrypt( m_hAesKey, NULL, TRUE, 0, 0, &d, (DWORD)bsize );  //need 80

我做错了吗? 附:如果我将加密结果截断为所需大小然后尝试解密,则使用返回的预期错误代码完成解密,但数据正确解密。但这个黑客不适合我...

2 个答案:

答案 0 :(得分:0)

首先,它不是编码和解码-它是加密和解密。

Microsoft可能默认情况下添加了PKCS5_PADDING-没有NO_PADDING这样的选项。 这很奇怪,尤其是对于ECB模式,但这解释了为什么CryptEncrypt返回扩展的缓冲区大小-它增加了一个用于填充的块。

另一方面,您在上述答案中使用bFinal == FALSE的“技巧”实际上是可以的,因为ECB模式不需要任何终结处理。

如果要使用其他加密模式,则应始终使用bFinal == TRUE加密。

如果您想正确执行操作,则应该分两步进行加密:

DWORD dwEncryptedDataLen = dwRealDataLen; 
result = CryptEncrypt(m_hAesKey, NULL, TRUE, 0, NULL, &dwEncryptedDataLen, 0);
...
pbData = (BYTE*)malloc(dwEncryptedDataLen);
memcpy(pbData, pbRealData, dwRealDataLen);
...
result = CryptEncrypt(m_hAesKey, NULL, TRUE, 0, pbData, &dwRealDataLen, dwEncryptedDataLen);
...

不要忘记检查Crypt函数的结果值。

答案 1 :(得分:-1)

我似乎找到了临时解决方案。 当我需要加密/解密整个块时 - 我需要的只是功能 - “它不是最后一个/唯一的块”: 所以不要输入:

result = CryptEncrypt( m_hAesKey, NULL, TRUE, 0, buffer, &d, (DWORD)bsize );

但:

result = CryptEncrypt( m_hAesKey, NULL, FALSE, 0, buffer, &d, (DWORD)bsize );

现在它有效。并希望他们不要在最后一篇文章的末尾更改填充数据的概念,以便在块的开头添加对齐...