【发布时间】:2017-03-07 09:59:23
【问题描述】:
我需要从 OpenSSL 迁移到 MS CryptoAPI。
当我使用 OpenSSL 时,我得到了 N 字节(已经对齐 - 例如,假设数据长度 = 32 字节)的数据,并将其从一个缓冲区编码/解码到另一个缓冲区。一切正常。
现在我必须“使用 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
WTHF 我做错了吗? 附言如果我将加密的结果截断为所需的大小,然后尝试对其进行解密,则使用返回的预期错误代码完成解密,但数据已正确解密。但这个 hack 不适合我...
【问题讨论】:
-
数据被填充,因为 AES 只加密整个块。 AES 假设在解密时最后一个加密的数据块有填充。这意味着如果要加密的最后一个数据块的大小与 AES 块大小相同,则必须添加填充块。如果不添加此填充,AES 无法确定最后一个块是否包含填充。
-
当我使用 OpenSSL 或 LibTomCrypt 时,我可以关闭 AES ECB/CBC 的填充。在 MS cryptoAPI 中似乎没有这样的选项......我没有看到“NO_PADDING”标志:msdn.microsoft.com/en-us/library/windows/desktop/…(参见 KP_PADDING 值)
-
这不是你的问题,但ECB是一种可怕模式。 即使如果您的消息总是少于一个块,它会泄露您发送相同消息两次的事实。我怀疑 CAPI 只是不支持你想要的。然而,一切都没有丢失:使用 BCryptEncrypt(这是一个 CNG API)。它确实支持不填充整个块消息。
-
不要使用 ECB 模式,它不安全,请参阅ECB mode,向下滚动到 Penguin。
标签: c++ aes padding cryptoapi ecb