我需要将字符串加密为AES / CBC。为了以后能够解密它,我必须将IV存储在最终结果中,该结果必须是base64字符串。
我设法使用此answer和Crypto ++示例:
std::string String::AESEncryptString(std::string str, std::string key)
{
std::string encoded;
std::string b64Result = "";
AutoSeededRandomPool prng;
unsigned char iv[AES::BLOCKSIZE];
prng.GenerateBlock(iv, sizeof(iv));
StringSink output(encoded);
// Put the IV at the begining of the output
StringSource(iv, sizeof(iv), true,
new Redirector(output)
);
try {
CBC_Mode<AES>::Encryption encryptor((unsigned char *)key.c_str(), key.length(), iv);
StringSource s(str, true,
new StreamTransformationFilter(encryptor,
new Redirector(output), StreamTransformationFilter::PKCS_PADDING
)
);
// Convert to b64
StringSource (encoded, true,
new Base64Encoder(
new StringSink(b64Result),
false // do not append a newline
)
);
return b64Result;
} catch (const Exception& e) {
return "";
}
}
要解密base64字符串,我首先提取IV,然后解密其余数据:
std::string String::AESDecryptString(std::string str, std::string key)
{
unsigned char iv[AES::BLOCKSIZE];
std::string b64decoded;
std::string decoded;
try {
StringSource(str, true,
new Base64Decoder(
new StringSink(b64decoded)
)
);
StringSource ss(b64decoded, false);
// Get the IV
ArraySink ivSink(iv, sizeof(iv));
ss.Attach(new Redirector(ivSink));
ss.Pump(AES::BLOCKSIZE);
CBC_Mode<AES>::Decryption decryptor((unsigned char *)key.c_str(), key.length(), iv);
ByteQueue queue;
ss.Detach(
new StreamTransformationFilter(decryptor,
new Redirector(queue)
)
);
ss.PumpAll(); // Pump remainder bytes
StringSink decodedSink(decoded);
queue.TransferTo(decodedSink);
return decoded;
}
catch (const Exception& e) {
return "";
}
}
一切正常,但是当我发现Crypto ++和流水线范例时,我觉得我可能已经完成了太多步骤来实现我想要的。
是否有更简洁或更有效的方法?
如果您真的喜欢恐怖故事,请考虑以下因素:
#include <iostream>
#include <string>
#include <cstdlib>
#include <cryptopp/osrng.h>
#include <cryptopp/base64.h>
#include <cryptopp/aes.h>
#include <cryptopp/filters.h>
#include <cryptopp/modes.h>
#include <cryptopp/cryptlib.h>
const std::string seckey = "this-has-16-char";
/**
* Encode : return encoded
*
*/
bool Encode(const std::string& input, std::string& output)
{
if (seckey.length()!=CryptoPP::AES::DEFAULT_KEYLENGTH) return false;
unsigned char iv[CryptoPP::AES::BLOCKSIZE];
// CryptoPP::AutoSeededRandomPool prng;
// prng.GenerateBlock(iv, sizeof(iv));
memcpy(iv, "this-also-has-16", CryptoPP::AES::BLOCKSIZE);
output.clear();
CryptoPP::StringSink outstr(output);
// Put the IV at the begining of the output
CryptoPP::StringSource(iv, sizeof(iv), true, new CryptoPP::Redirector(outstr));
try {
CryptoPP::CBC_Mode<CryptoPP::AES>::Encryption encryptor((unsigned char *)seckey.c_str(), seckey.length(), iv);
// encode, Convert to b64, do not append a newline
CryptoPP::StringSource (
input, true, new CryptoPP::StreamTransformationFilter(
encryptor, new CryptoPP::Base64Encoder( new CryptoPP::StringSink(output), false),
CryptoPP::StreamTransformationFilter::PKCS_PADDING));
}
catch (const CryptoPP::Exception& e) {
return false;
}
return true;
}
/**
* Decode : return decoded
*
*/
bool Decode(const std::string& input, std::string& output)
{
if (seckey.length()!=CryptoPP::AES::DEFAULT_KEYLENGTH) return false;
if (input.length()<=CryptoPP::AES::BLOCKSIZE) return false; // no iv
unsigned char iv[CryptoPP::AES::BLOCKSIZE];
memcpy(iv, input.c_str(), CryptoPP::AES::BLOCKSIZE);
try {
// Convert from b64 and decode
CryptoPP::CBC_Mode<CryptoPP::AES>::Decryption decryptor((unsigned char *)seckey.c_str(), seckey.length(), iv);
CryptoPP::StringSource ((const CryptoPP::byte*)&input[CryptoPP::AES::BLOCKSIZE], input.length()-CryptoPP::AES::BLOCKSIZE,
true,new CryptoPP::Base64Decoder(
new CryptoPP::StreamTransformationFilter( decryptor, new CryptoPP::StringSink(output))
));
}
catch (const CryptoPP::Exception& e) {
return false;
}
return true;
}
int main()
{
std::string input = "this is the data";
std::string output;
bool status = Encode(input,output);
if (status) std::cerr << "Encoded: " << ": " << output << std::endl;
input.clear();
status = Decode(output,input);
if (status) std::cerr << "Decoded: " << input << std::endl;
}