c++ - AES-128 CFB-8解密前16字节损坏
问题描述
我最近一直在做一个项目,该项目应该在协议的帮助下连接到服务器。到目前为止一切都很好,但是当我梳理解密包时,我很快注意到有些东西不能正常工作。
所有数据包的前 16 个字节都被错误地解密。我已经尝试过使用不同的库,但这也不起作用。我使用 C++ 语言工作,迄今为止使用 Crypto++ 和 OpenSSL 进行解密,但没有成功。
在此链接下您可以找到协议,这里是解密协议链接,这是我的相应代码:
OpenSSL:
void init() {
unsigned char* sharedSecret = new unsigned char[AES_BLOCK_SIZE];
std::generate(sharedSecret,
sharedSecret + AES_BLOCK_SIZE,
std::bind(&RandomGenerator::GetInt, &m_RNG, 0, 255));
for (int i = 0; i < 16; i++) {
sharedSecretKey += sharedSecret[i];
}
// Initialize AES encryption and decryption
if (!(m_EncryptCTX = EVP_CIPHER_CTX_new()))
std::cout << "123" << std::endl;
if (!(EVP_EncryptInit_ex(m_EncryptCTX, EVP_aes_128_cfb8(), nullptr, (unsigned char*)sharedSecretKey.c_str(), (unsigned char*)sharedSecretKey.c_str())))
std::cout << "123" << std::endl;
if (!(m_DecryptCTX = EVP_CIPHER_CTX_new()))
std::cout << "123" << std::endl;
if (!(EVP_DecryptInit_ex(m_DecryptCTX, EVP_aes_128_cfb8(), nullptr, (unsigned char*)sharedSecretKey.c_str(), (unsigned char*)sharedSecretKey.c_str())))
std::cout << "123" << std::endl;
m_BlockSize = EVP_CIPHER_block_size(EVP_aes_128_cfb8());
}
std::string result;
int size = 0;
result.resize(1000);
EVP_DecryptUpdate(m_DecryptCTX, &((unsigned char*)result.c_str())[0], &size, &sendString[0], data.size());
加密++:
CryptoPP::CFB_Mode<CryptoPP::AES>::Decryption AESDecryptor((byte*)sharedSecret.c_str(), (unsigned int)16, sharedSecret.c_str(), 1);
std::string sTarget("");
CryptoPP::StringSource ss(data, true, new CryptoPP::StreamTransformationFilter(AESDecryptor, new CryptoPP::StringSink(sTarget)));
我认为值得一提的是,我对密钥和 iv(初始化向量)使用了相同的共享密钥。在其他帖子中,这通常被标记为问题。在这种情况下,我不知道如何解决它,因为协议需要它。
我期待着建设性的反馈。
解决方案
EVP_EncryptInit_ex(m_EncryptCTX, EVP_aes_128_cfb8(), nullptr, (unsigned char*)sharedSecretKey.c_str(), (unsigned char*)sharedSecretKey.c_str()))
和:
CFB_Mode<AES>::Decryption AESDecryptor((byte*)sharedSecret.c_str(), (unsigned int)16, sharedSecret.c_str(), 1); std::string sTarget(""); StringSource ss(data, true, new StreamTransformationFilter(AESDecryptor, new StringSink(sTarget)));
这不是很明显,但是您需要为 Crypto++ 中的分组密码的操作模式设置反馈大小。Crypto++ 反馈大小默认为 128。
设置 CFB 模式反馈大小的代码可以在Crypto++ wiki 上的CFB模式中找到。您想要页面下方的第三个或第四个示例。
AlgorithmParameters params =
MakeParameters(Name::FeedbackSize(), 1 /*8-bits*/)
(Name::IV(), ConstByteArrayParameter(iv));
这是传递参数的一种尴尬方式。它记录在源文件和 wiki 的NameValuePairs 中。它允许您通过一致的接口传递任意参数。一旦你尝到了它的味道,它就会很强大。
然后使用params
密钥加密器和解密器:
CFB_Mode< AES >::Encryption enc;
enc.SetKey( key, key.size(), params );
// CFB mode must not use padding. Specifying
// a scheme will result in an exception
StringSource ss1( plain, true,
new StreamTransformationFilter( enc,
new StringSink( cipher )
) // StreamTransformationFilter
); // StringSource
我相信你的电话看起来像这样(如果我正确解析 OpenSSL):
const byte* ptr = reinterpret_cast<const byte*>(sharedSecret.c_str());
AlgorithmParameters params =
MakeParameters(Name::FeedbackSize(), 1 /*8-bits*/)
(Name::IV(), ConstByteArrayParameter(ptr, 16));
CFB_Mode< AES >::Encryption enc;
enc.SetKey( ptr, 16, params );
在您的生产代码中,您应该使用唯一键和 iv。所以使用HKDF做这样的事情:
std::string seed(AES_BLOCK_SIZE, '0');
std::generate(seed, seed + AES_BLOCK_SIZE,
std::bind(&RandomGenerator::GetInt, &m_RNG, 0, 255));
SecByteBlock sharedSecret(32);
const byte usage[] = "Key and IV v1";
HKDF<SHA256> hkdf;
hkdf.DeriveKey(sharedSecret, 32, &seed[0], 16, usage, COUNTOF(usage), nullptr, 0);
AlgorithmParameters params =
MakeParameters(Name::FeedbackSize(), 1 /*8-bits*/)
(Name::IV(), ConstByteArrayParameter(sharedSecret+16, 16));
CFB_Mode< AES >::Encryption enc;
enc.SetKey(sharedSecret+0, 0, params);
在上面的代码中,sharedSecret
它是所需大小的两倍。您使用 . 从种子中派生密钥和 iv HDKF
。sharedSecret+0
是 16 字节的密钥,sharedSecret+16
是 16 字节的 iv。
推荐阅读
- excel - 如何选择一系列单元格直到特定值
- authentication - 微服务的去中心化身份验证
- python - 如何在 Gurobi 中线性化约束
- python-3.x - Atom 脚本在 Mac 上找不到 Python 3 的路径
- reactjs - 什么时候使用没有依赖的 useEffect?
- .net - TransactionScope 需要在 C# MVC 中启用 DTC
- spring - hibernate回滚错误信息不清楚
- c# - 无法从访问数据库中获取数据
- java - FCM:使用 Java 服务器设置 TTL(“time_to_live”或寿命)属性(Google 文档错误/不清楚)
- hyperledger-fabric - 如何扩展结构网络以在数千个用户/对等/组织之间共享私有数据?