如果我想加密数据,使用 Crypto++ 库并使用短于 32 字节的用户定义密码怎么办?
使用密钥派生函数 (KDF) 来消化密码。现代的是 Krawczyk 和 Eronen 的 HKDF,使用的是 Extract-then-Expand 模型。论文地址Cryptographic Extraction and Key Derivation: The HKDF Scheme。
您也应该考虑将它用于 IV。与其派生 32 个字节 (AES::MAX_KEYLENGTH),不如派生 48 个字节 (AES::MAX_KEYLENGTH+AES::BLOCKSIZE)。然后,您设计中的 IV 可用于 KDF 的 salt 参数。
可能是这样的:
#include <iostream>
#include <string>
using namespace std;
#include "cryptlib.h"
#include "aes.h"
#include "sha.h"
#include "hkdf.h"
#include "modes.h"
#include "filters.h"
using namespace CryptoPP;
int main(int argc, char* argv[])
{
SecByteBlock key(AES::MAX_KEYLENGTH+AES::BLOCKSIZE);
string password("passwordFromUser"), iv("<random value>"), message("encryptMe");
string encrypted, recovered;
try
{
HKDF<SHA256> hkdf;
hkdf.DeriveKey(key, key.size(), (const byte*)password.data(), password.size(), (const byte*)iv.data(), iv.size(), NULL, 0);
///////////////////////////////////////////////////////////////////////
CTR_Mode<AES>::Encryption encryption;
encryption.SetKeyWithIV(key, AES::MAX_KEYLENGTH, key+AES::MAX_KEYLENGTH);
StringSource encryptor(message, true,
new StreamTransformationFilter(encryption,
new StringSink(encrypted))
);
///////////////////////////////////////////////////////////////////////
CTR_Mode<AES>::Decryption decryption;
decryption.SetKeyWithIV(key, AES::MAX_KEYLENGTH, key+AES::MAX_KEYLENGTH);
StringSource decryptor(encrypted, true,
new StreamTransformationFilter(decryption,
new StringSink(recovered))
);
cout << "Message: " << message << endl;
cout << "Recovered: " << recovered << endl;
}
catch(const Exception& ex)
{
cerr << ex.what() << endl;
return 1;
}
return 0;
}
使用上述加密方法时,您必须跟踪{iv,message} 对。需要 IV 来确保每条消息的唯一性,因为密码有效地修复了 AES 密钥。
如果用户选择的密码长于 32 字节怎么办?在我的情况下,密码会被截断,这对我来说听起来不对。
KDF 会为您处理。无论多少熵,它都会提取熵。
StringSource encryptor(textToEncrypt, true,
new StreamTransformationFilter(encryption,
new StringSink(verschluesselterText),
StreamTransformationFilter::NO_PADDING
)
无需指定填充模式。另请参阅BlockPaddingScheme 的文档。
您应该非常小心点击率等模式。 CTR 模式 xor 是带有纯文本的密钥流。如果有人在不同的消息中重复使用他们的密码,那么就有可能恢复导致明文恢复的密钥流。
如果 ivText 对于每条消息都是唯一的,那么您应该将它添加到您的 KDF 以确保每条消息的密钥流都是唯一的。添加 IV 作为 HKDF 的 salt 参数。这里,"unique" 的意思是如果我有一条消息"Hello World",那么每次我加密消息时,IV 都是不同的。
如果 IV 真的只是“Iv16BytesOfText...”(即,它是固定的),那么它就没有什么独特之处了。只需从用户密码中提取额外的 16 个字节。然后,为了避免密钥流异或攻击,请切换到 CBC 之类的模式。
最后,您可能应该使用 CCM、EAX 或 GCM 模式。现在,你只有保密。通常你也想要真实性。为了获得真实性,您通常选择Authenticated Encryption 操作模式。