如何使用Crypto++库结合口令与盐解密OpenSSL加密内容?
问题分析与解决方案
1. 解密前未做Base64解码
OpenSSL加密后会将二进制密文编码为Base64字符串,而Crypto++直接使用这个Base64字符串进行解密——Base64编码后的长度通常不是AES块大小(16字节)的倍数,这就是触发StreamTransformationFilter块大小异常的直接原因。
修正步骤:解密前先对密文做Base64解码,Crypto++可通过Base64Decoder实现:
std::string decoded_cipher; CryptoPP::Base64Decoder decoder; decoder.Attach(new CryptoPP::StringSink(decoded_cipher)); decoder.Put(reinterpret_cast<const unsigned char*>(enc.data()), enc.size()); decoder.MessageEnd();
2. IV推导逻辑完全错误
OpenSSL中通过PBKDF2生成32字节派生数据,前16字节用作AES-128的Key,后16字节用作IV;但你的Crypto++代码存在两处关键错误:
- 派生数据长度仅设为
16 + saltLen(salt为"salt123"时长度是7,仅派生23字节),远不足32字节 - IV取的是派生数据中16字节之后的
saltLen字节(7字节),和OpenSSL的16字节IV完全不匹配
修正步骤:派生32字节数据,取后16字节作为IV:
// 派生32字节数据用于Key和IV CryptoPP::SecByteBlock derived(32); CryptoPP::PKCS5_PBKDF2_HMAC<CryptoPP::SHA1> pbkdf; pbkdf.DeriveKey(derived, derived.size(), 0, reinterpret_cast<const CryptoPP::byte*>(password), strlen(password), reinterpret_cast<const CryptoPP::byte*>(salt), saltLen, 1000); // 前16字节是Key,后16字节是IV CryptoPP::SecByteBlock key(16), iv(16); std::memcpy(key.data(), derived.data(), key.size()); std::memcpy(iv.data(), derived.data() + 16, iv.size());
3. 其他代码错误修正
- 加密函数调用拼写错误:
ecrypt("test123", ...)→encrypt("test123", ...) strLen(password)改为标准C函数strlen(password)- OpenSSL加密函数中补充
ctx初始化:EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new();,并删除重复定义的unsigned char key[EVP_MAX_KEY_LENGTH]; - Crypto++解密可使用更简洁的
CBC_Mode<AES>::Decryption替代CBC_Mode_ExternalCipher
修正后的完整代码
#include <openssl/rand.h> #include <openssl/evp.h> #include <openssl/bio.h> #include <string.h> #include <cryptopp/aes.h> #include <cryptopp/modes.h> #include <cryptopp/filters.h> #include <cryptopp/base64.h> #include <cryptopp/pwdbased.h> #include <cryptopp/sha.h> #include <iostream> std::string stringToBase64(const std::string& input) { BIO* bio = BIO_new(BIO_s_mem()); BIO* base64 = BIO_new(BIO_f_base64()); BIO_set_flags(base64, BIO_FLAGS_BASE64_NO_NL); // No line breaks BIO* bio_chain = BIO_push(base64, bio); BIO_write(bio_chain, input.c_str(), input.length()); BIO_flush(bio_chain); char* encoded_data; long encoded_length = BIO_get_mem_data(bio, &encoded_data); std::string base64_string(encoded_data, static_cast<size_t>(encoded_length)); BIO_free_all(bio_chain); return base64_string; } std::string encrypt(std::string str, const char* password, const char* salt) { EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new(); // 初始化ctx if (!ctx) return {}; unsigned char derived[32]; // 32 bytes for both key and IV if(!PKCS5_PBKDF2_HMAC(password, strlen(password), reinterpret_cast<const unsigned char *>(salt), strlen(salt), 1000, EVP_sha1(), 32, derived)) { EVP_CIPHER_CTX_free(ctx); return {}; } unsigned char key[16]; // AES-128 key unsigned char iv[16]; memcpy(key, derived, 16); memcpy(iv, derived + 16, 16); if (EVP_CipherInit(ctx, EVP_aes_128_cbc(), key, iv, true) != 1) { EVP_CIPHER_CTX_free(ctx); return {}; } int len = 0; int outLen; int blocksize = EVP_CIPHER_CTX_block_size(ctx); std::string cipherBuf; cipherBuf.resize(str.size() + blocksize); if (EVP_CipherUpdate(ctx, reinterpret_cast<unsigned char*>(cipherBuf.data()), &outLen, reinterpret_cast<unsigned char*>(str.data()), str.size()) != 1) { EVP_CIPHER_CTX_free(ctx); return {}; } len += outLen; if (EVP_CipherFinal(ctx, reinterpret_cast<unsigned char*>(cipherBuf.data() + len), &outLen) != 1) { EVP_CIPHER_CTX_free(ctx); return {}; } len += outLen; cipherBuf.resize(len); EVP_CIPHER_CTX_free(ctx); std::string base64_enc = stringToBase64(cipherBuf); memset(cipherBuf.data(), 0, cipherBuf.size()); return base64_enc; } int main(int argc, char* argv[]) { const char* password = "password123"; const char* salt = "salt123"; std::string enc = encrypt("test123", password, salt); std::cout << "Encrypted: " << enc << std::endl; size_t saltLen = strlen(salt); // 派生32字节数据用于Key和IV CryptoPP::SecByteBlock derived(32); CryptoPP::PKCS5_PBKDF2_HMAC<CryptoPP::SHA1> pbkdf; pbkdf.DeriveKey(derived, derived.size(), 0, reinterpret_cast<const CryptoPP::byte*>(password), strlen(password), reinterpret_cast<const CryptoPP::byte*>(salt), saltLen, 1000); CryptoPP::SecByteBlock key(16), iv(16); std::memcpy(key.data(), derived.data(), key.size()); std::memcpy(iv.data(), derived.data() + 16, iv.size()); // 打印Key和IV验证 CryptoPP::HexEncoder encoder; std::string key_hex, iv_hex; encoder.Attach(new CryptoPP::StringSink(key_hex)); encoder.Put(key.data(), key.size()); encoder.MessageEnd(); encoder.Detach(new CryptoPP::StringSink(iv_hex)); encoder.Put(iv.data(), iv.size()); encoder.MessageEnd(); std::cout << "Key: " << key_hex << std::endl; std::cout << "IV: " << iv_hex << std::endl; // Base64解码密文 std::string decoded_cipher; CryptoPP::Base64Decoder decoder; decoder.Attach(new CryptoPP::StringSink(decoded_cipher)); decoder.Put(reinterpret_cast<const unsigned char*>(enc.data()), enc.size()); decoder.MessageEnd(); // 解密 std::string dec; CryptoPP::CBC_Mode<CryptoPP::AES>::Decryption cbcDecryption(key, key.size(), iv); CryptoPP::StreamTransformationFilter stf(cbcDecryption, new CryptoPP::StringSink(dec)); stf.Put(reinterpret_cast<const unsigned char*>(decoded_cipher.data()), decoded_cipher.size()); stf.MessageEnd(); std::cout << "Decrypted: " << dec << std::endl; return 0; }
内容的提问来源于stack exchange,提问作者Jabu
相关产品推荐
相关产品推荐

