我需要将字符串加密为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 ++和流水线范例时,我觉得我可能已经完成了很多步骤来实现自己想要的。
是否有更简洁或更有效的方法?
答案 0 :(得分:1)
您可以将这两个步骤合并为一个 StringSource
调用:
StringSource s(str, true,
new StreamTransformationFilter(
encryptor,
new Base64Encoder(
new StringSink(b64Result),
false // do not append a newline
),
StreamTransformationFilter::PKCS_PADDING
)
);
StringSource s(
str, true,
new Base64Decoder(
new StreamTransformationFilter(decryptor, new StringSink(decoded))
)
);
答案 1 :(得分:0)
创建用于链接的锚点类。跟随this
#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>
#ifndef CRYPTOPP_NO_GLOBAL_BYTE
namespace CryptoPP { typedef unsigned char byte; }
#endif // CRYPTOPP_NO_GLOBAL_BYTE
const std::string seckey = "this-has-16-char";
class Anchor : public CryptoPP::Bufferless<CryptoPP::Filter>
{
public:
Anchor(CryptoPP::BufferedTransformation* attachment = NULL) { Detach(attachment); };
size_t Put2(const CryptoPP::byte * inString, size_t length, int messageEnd, bool blocking )
{
return AttachedTransformation()->Put2(inString, length, messageEnd, blocking );
}
};
/**
* 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();
try {
Anchor anchor;
// Put the IV at the begining of the output
anchor.Attach(new CryptoPP::StringSink(output));
anchor.Put( iv, sizeof(iv) );
anchor.MessageEnd();
anchor.Detach();
CryptoPP::CBC_Mode<CryptoPP::AES>::Encryption encryptor((unsigned char *)seckey.c_str(), seckey.length(), iv);
anchor.Attach(new CryptoPP::StreamTransformationFilter(encryptor,NULL, CryptoPP::StreamTransformationFilter::PKCS_PADDING));
anchor.Attach(new CryptoPP::Base64Encoder(NULL, false));
anchor.Attach(new CryptoPP::StringSink(output));
anchor.Put( (CryptoPP::byte*)input.c_str(), input.length() );
anchor.MessageEnd();
}
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);
Anchor anchor;
anchor.Attach(new CryptoPP::Base64Decoder());
anchor.Attach(new CryptoPP::StreamTransformationFilter( decryptor, NULL));
anchor.Attach(new CryptoPP::StringSink(output));
anchor.Put( (const CryptoPP::byte*)&input[CryptoPP::AES::BLOCKSIZE], input.length()-CryptoPP::AES::BLOCKSIZE );
anchor.MessageEnd();
}
catch (const CryptoPP::Exception& e) {
return false;
}
return true;
}
int main()
{
std::string input = "The five boxing wizards jump quickly.";
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;
}