I'm trying to encrypt a file using AES EAX mode and CryptoPP library.
Here is the main() content:
SecByteBlock key(AES::MAX_KEYLENGTH);
rnd.GenerateBlock(key, key.size());
ArraySource as(key.begin(), key.size(), true, new FileSink("key.bin"));
SecByteBlock iv(AES::BLOCKSIZE);
rnd.GenerateBlock(iv, AES::BLOCKSIZE);
EAX<AES>::Encryption encryptor;
encryptor.SetKeyWithIV(key, key.size(), iv, iv.size());
FileSink file("image.jpg.enc");
ArraySource write_iv(iv, iv.size(), true, new Redirector(file));
FileSource write_ciphertext("image.jpg", true, new AuthenticatedEncryptionFilter(encryptor, new Redirector(file)));
const int delete_file = std::remove("image.jpg");
std::cout << delete_file << std::endl;
std::cout << "Error code is:" << GetLastError();
return 0;
The encryption part ends successfully,however,removing the original file (image.jpg) fails.The output I get is:
Error code is:32
Which is an ERROR_SHARING_VIOLATION, meaning that "The process cannot access the file because it is being used by another process."
My question is : How can I close the file after the Filesource line,to be able to delete the file after ? With a classic ifstream ,it would be file.close(), but how can i do it with Crypto++ ?
I'm not familiar with crypto++ but if they're following the RAII pattern then triggering the ~FileSource destructor should be sufficient to close the handle of the file.
In C++ you would use an anonymous scope to define the lifetime of an automatic variable. Anonymous scopes are defined using curly braces without any keywords:
using namespace std;
...
encryptor.SetKeyWithIV(key, key.size(), iv, iv.size());
// begin an anonymous scope:
{
FileSink file ( "image.jpg.enc" );
ArraySource write_iv ( iv, iv.size(), true, new Redirector( file ) );
FileSource write_ciphertext ( "image.jpg", true, new AuthenticatedEncryptionFilter( encryptor, new Redirector( file ) ) );
}
// end the scope, causing all objects declared within to have their destructors called
const int delete_file = remove("image.jpg");
cout << delete_file << endl;
cout << "Error code is:" << GetLastError();
...
BTW, I noticed you use new without delete. I believe you can make those argument objects also automatic, like so:
using namespace std;
...
encryptor.SetKeyWithIV(key, key.size(), iv, iv.size());
// begin an anonymous scope:
{
FileSink file ( "image.jpg.enc" );
Redirector write_redir ( file );
ArraySource write_iv ( iv, iv.size(), true, &write_redir );
AuthenticatedEncryptionFilter filter ( encryptor, &write_redir )
FileSource write_ciphertext( "image.jpg", true, &filter );
}
// end the scope, causing all objects declared within to have their destructors called
const int delete_file = remove("image.jpg");
cout << delete_file << endl;
cout << "Error code is:" << GetLastError();
...
Related
In Crpto++ one can easily use pipeline to hash an input.
std::string out;
CryptoPP::SHA256 sha;
CryptoPP::StringSource ss(input,true,
new CryptoPP::HashFilter(sha,
new CryptoPP::HexEncoder(
new CryptoPP::StringSink(out))));
Now inorder to verify a gives message x produces the same hash output, I would like to use HashVerificationFilter. I have tried it but it doesn't work. Anyone know the correct syntax ?
const int flags = CryptoPP::HashVerificationFilter::THROW_EXCEPTION | CryptoPP::HashVerificationFilter::HASH_AT_END;
CryptoPP::SHA256 sha;
try
{
CryptoPP::StringSource ss(input + out, true,
new CryptoPP::HashVerificationFilter(sha, NULL , flags));
}
catch(const CryptoPP::Exception& e)
{
std::cerr << e.what() << std::endl;
exit(1);
}
I get the output :
HashVerificationFilter: message hash or MAC not valid
std::string out;
SHA256 sha;
StringSource ss(input,true,
new HashFilter(sha,
new HexEncoder(
new StringSink(out)
)));
You HexEncode your hash. You need to decode it before passing it to the filter:
StringSource ss(input + out, true,
new HashVerificationFilter(sha, NULL , flags)
);
Or, remove the encoding filter:
std::string out;
SHA256 sha;
StringSource ss(input,true,
new HashFilter(sha,
new StringSink(out)
));
I have the followind piece of code that encrypts and decrypts the message.
QString AesUtils::encrypt(QString message, QString aesKey)
{
string plain = message.toStdString();
qDebug() << "Encrypt" << plain.data() << " " << plain.size();
string ciphertext;
// Hex decode symmetric key:
HexDecoder decoder;
string stdAesKey = aesKey.toStdString();
decoder.Put((byte*)stdAesKey.data(), aesKey.size());
decoder.MessageEnd();
word64 size = decoder.MaxRetrievable();
char *decodedKey = new char[size];
decoder.Get((byte *)decodedKey, size);
// Generate Cipher, Key, and CBC
byte key[ AES::MAX_KEYLENGTH ], iv[ AES::BLOCKSIZE ];
StringSource( reinterpret_cast<const char *>(decodedKey), true,
new HashFilter(*(new SHA256), new ArraySink(key, AES::MAX_KEYLENGTH)) );
memset( iv, 0x00, AES::BLOCKSIZE );
CBC_Mode<AES>::Encryption Encryptor( key, sizeof(key), iv );
StringSource( plain, true, new StreamTransformationFilter( Encryptor,
new HexEncoder(new StringSink( ciphertext )) ) );
return QString::fromStdString(ciphertext);
}
QString AesUtils::decrypt(QString message, QString aesKey)
{
string plain;
string encrypted = message.toStdString();
// Hex decode symmetric key:
HexDecoder decoder;
string stdAesKey = aesKey.toStdString();
decoder.Put( (byte *)stdAesKey.data(), aesKey.size() );
decoder.MessageEnd();
word64 size = decoder.MaxRetrievable();
char *decodedKey = new char[size];
decoder.Get((byte *)decodedKey, size);
// Generate Cipher, Key, and CBC
byte key[ AES::MAX_KEYLENGTH ], iv[ AES::BLOCKSIZE ];
StringSource( reinterpret_cast<const char *>(decodedKey), true,
new HashFilter(*(new SHA256), new ArraySink(key, AES::MAX_KEYLENGTH)) );
memset( iv, 0x00, AES::BLOCKSIZE );
try {
CBC_Mode<AES>::Decryption Decryptor
( key, sizeof(key), iv );
StringSource( encrypted, true,
new HexDecoder(new StreamTransformationFilter( Decryptor,
new StringSink( plain )) ) );
}
catch (Exception &e) { // ...
qDebug() << "Exception while decrypting " << e.GetWhat().data();
}
catch (...) { // ...
}
qDebug() << "decrypt" << plain.data() << " " << AES::BLOCKSIZE;
return QString::fromStdString(plain);
}
The problem is that I randomly get:
StreamTransformationFilter: invalid PKCS #7 block padding found
When decrypting the content. The encryption should fully support QString,
since it may contain some Unicode data. But it doesn't work even with a basic,
string which contains only [A-z][a-z][0-9]
The aesKey size is 256.
Following some answers on Stack Overflow, somebody suggested the use of HexDecoder / HexEncoder, but it does not solve the problem in my case.
The fist problem with my code was that I was feeding normal string in aesKey QString.
So instead of "1231fsdf$5r4" you need to give a key in hex format: [0-9][A-F]
Then, the problem was here:
char *decodedKey = new char[size];
decoder.Get((byte *)decodedKey, size);
I guess the string was full 64 bytes and there was no space for NULL at the end. The problem dissapeared after I changed to:
char *decodedKey = new char[size+2];
Now the code works fine. Hope this will help somebody in the future.
I'm playing around with AES and write the iv and derived key to the file so that I use it later for decryption...
following function encrypts the file and saves the iv and derived key into the file, it also saves encrypted text into separate file:
void MainWindow::on_button_encrypt() try
{
using namespace std;
using namespace Gtk;
using namespace CryptoPP;
fstream file;
file.open(m_file_name + ".aes", std::ios::out | std::ios::trunc);
if (file.is_open())
{
// get the plain password:
SecByteBlock password;
password_dialog get_passwd(password);
get_passwd.run();
// generate random salt
const int SALT_SIZE = 32;
SecByteBlock salt(SALT_SIZE);
AutoSeededRandomPool prng;
prng.GenerateBlock(salt.BytePtr(), SALT_SIZE);
// derive a key from password and salt:
SecByteBlock key(AES::DEFAULT_KEYLENGTH);
PKCS5_PBKDF2_HMAC<SHA512> gen;
gen.DeriveKey(key.BytePtr(), key.size(), 1, password.BytePtr(), password.size(), salt.BytePtr(), salt.size(), 200);
// genereate random iv:
SecByteBlock iv(AES::BLOCKSIZE);
OS_GenerateRandomBlock(false, iv.BytePtr(), AES::BLOCKSIZE);
// encrypt plain text:
AES::Encryption enc(key.BytePtr(), AES::DEFAULT_KEYLENGTH);
CBC_Mode_ExternalCipher::Encryption mode(enc, iv);
string cipher_text;
StringSink* sink = new StringSink(cipher_text);
StreamTransformationFilter encryptor(mode, sink);
string plain_text = m_file_buffer->get_text();
encryptor.Put(reinterpret_cast<const byte*>(plain_text.c_str()), plain_text.length() + 1);
encryptor.MessageEnd();
// write the result:
file << cipher_text.c_str();
file.close();
file.open(m_file_name + ".key", std::ios::out | std::ios::trunc);
file << key << '\n' << iv;
file.close();
}
}
// catch ...
The above function writes the iv and derived key to the file.
0000000002F9F140
0000000002F9F4E0
Following function is supposed to read the file and decrypt it by using the *.key file:
void MainWindow::on_button_decrypt()
{
using namespace std;
using namespace CryptoPP;
Gtk::MessageDialog info("Info");
fstream file;
file.open("decrypted.txt", ios::out | ios::trunc);
if (file.is_open())
{
// read the key:
fstream stream;
string input;
SecByteBlock key(AES::DEFAULT_KEYLENGTH);
SecByteBlock iv(AES::BLOCKSIZE);
stream.open("test.txt.key", std::ios::in);
if (stream.is_open())
{
getline(stream, input);
key.Assign(reinterpret_cast<const byte*>(input.c_str()), input.size());
input.clear();
getline(stream, input);
iv.Assign(reinterpret_cast<const byte*>(input.c_str()), input.size());
}
else
{
info.set_secondary_text("can't read key file");
info.run();
return;
}
// decrypt:
AES::Decryption dec(key, AES::DEFAULT_KEYLENGTH);
CBC_Mode_ExternalCipher::Decryption mode(dec, iv);
string plain_text;
StringSink* sink = new StringSink(plain_text);
StreamTransformationFilter decryptor(mode, sink);
try
{
// get encrypted text from buffer (obtained from other function):
string cipher_text = m_file_buffer->get_text();
decryptor.Put(reinterpret_cast<const byte*>(cipher_text.c_str()), cipher_text.size());
decryptor.MessageEnd();
file << plain_text;
file.close();
}
catch (CryptoPP::Exception& ex)
{
info.set_secondary_text(ex.what());
info.run();
}
}
}
CryptoPP trows an exception while decrypting saying this:
FileTransformationFilter: ciphertext length is not multiple of a block size.
How ever it does not throw anything if decryption process is done in first function ( on_btn_encrypt() ) no file is read there, so it looks I'm having problem with reading encrypted file but have no idea how?
This is content of encrypted file:
&`OôÍoYjÜMe×Q°Þ
plaintext is:
some text
Do you see what am I missing here? thanks so much!
EDIT:
here are modification which solved the problem as sugested by Qmick and Artjom:
ENCRYPTION
// encrypt the file:
AES::Encryption enc(key.BytePtr(), AES::DEFAULT_KEYLENGTH);
CBC_Mode_ExternalCipher::Encryption mode(enc, iv);
string file = m_file_name + ".aes";
FileSink* sink = new FileSink(file.c_str());
StreamTransformationFilter encryptor(mode, sink);
string plain_text = m_file_buffer->get_text();
encryptor.Put(reinterpret_cast<const byte*>(plain_text.c_str()), plain_text.length());
encryptor.MessageEnd();
// write the key:
file = m_file_name + ".key";
FileSink* out = new FileSink(file.c_str());
Base64Encoder* base64_enc = new Base64Encoder;
base64_enc->Attach(out);
base64_enc->Put(key.BytePtr(), key.size());
base64_enc->MessageEnd();
// write the iv:
file = m_file_name + ".iv";
FileSink* out2 = new FileSink(file.c_str());
Base64Encoder* base64_enc2 = new Base64Encoder;
base64_enc2->Attach(out2);
base64_enc2->Put(iv.BytePtr(), iv.size());
base64_enc2->MessageEnd();
DECRYPTION:
//
// read key
//
string store_key;
StringSink* string_key_in = new StringSink(store_key);
Base64Decoder* base64_key_dec = new Base64Decoder(string_key_in);
string file = "test.txt.key";
FileSource* file_key_in = new FileSource(file.c_str(), true, base64_key_dec);
SecByteBlock key(AES::DEFAULT_KEYLENGTH);
key.Assign(reinterpret_cast<const byte*>(store_key.c_str()), store_key.size());
//
// read iv
//
string store_iv;
StringSink* string_iv_in = new StringSink(store_iv);
Base64Decoder* base64_iv_dec = new Base64Decoder(string_iv_in);
file = "test.txt.iv";
FileSource* file_iv_in = new FileSource(file.c_str(), true, base64_iv_dec);
SecByteBlock iv(AES::BLOCKSIZE);
iv.Assign(reinterpret_cast<const byte*>(store_iv.c_str()), store_iv.size());
// read ciphertext:
string store_ciphertext;
StringSink* ciphertext_in = new StringSink(store_ciphertext);
file = m_file_name;
FileSource* file_ciphertext_in = new FileSource(file.c_str(), true, ciphertext_in);
SecByteBlock cipher_text;
cipher_text.Assign(reinterpret_cast<const byte*>(store_ciphertext.c_str()), store_ciphertext.size());
//
// decrypt:
//
AES::Decryption dec(key, AES::DEFAULT_KEYLENGTH);
CBC_Mode_ExternalCipher::Decryption mode(dec, iv);
file = "decrypted.txt";
FileSink* sink = new FileSink(file.c_str());
StreamTransformationFilter decryptor(mode, sink);
decryptor.Put(cipher_text.BytePtr(), cipher_text.size());
decryptor.MessageEnd();
There is no guarentee cipher text will not contain escape sequence like \n, which make getline() get wrong string(truncated).
So it is recommended to transform the cipher text to hex or something else to avoid escape sequence.
I have this code to try decryption:
byte key[AES::DEFAULT_KEYLENGTH];
string key_s = "essasenhaehfraca";
for (int i = 0; i < key_s.size(); i++)
key[i] = (byte) key_s[i];
string ciphertext = "A506A19333F306AC2C62CBE931963AE7DFCFFA940360A40FFD5DC69B9C2E53AD"
string decryptedtext;
try
{
ECB_Mode< AES >::Decryption decryptor;
decryptor.SetKey(key, sizeof(key));
CryptoPP::StringSource(ciphertext, true,
new CryptoPP::StreamTransformationFilter( decryptor,
new CryptoPP::StringSink( decryptedtext )
)
);
}
catch(const CryptoPP::Exception& e)
{
cerr << e.what() << endl;
system("pause");
exit(1);
}
return 0;
When I execute it, I get the exception
StreamTransformationFilter: invalid pkcs #7 block padding found.
I searched and didn't find anything. Someone knows why I get this error? Every example I found in the internet is in this same way and none of them mention this error.
It looks like your Cipher text is hex-encoded. You need to add a HexDecoder to your decryption stream:
CryptoPP::StringSource ss(ciphertext, true,
new CryptoPP::HexDecoder(
new CryptoPP::StreamTransformationFilter( decryptor,
new CryptoPP::StringSink( decryptedtext ) ) ) );
In my experience, I think it's because you don't create your key correctly:
byte* key_s = (byte*)"essasenhaehfraca";
SecByteBlock key( key_s, AES::DEFAULT_KEYLENGTH );
And after that:
ECB_Mode< AES >::Decryption d;
d.SetKey( key, key.size() );
How it is possible to verify a digital signature with the crypto++ library?
The input data is:
public_key BASE64 encoded hex string.
public exponent from the public key.
signature as hex string.
I don't know the private key part.
I have written this test function but it alway ends with "VerifierFilter: digital signature not valid" error.
The key here is exported from a valid KeyPair!
void rawRSAVerificationTest()
{
// RSA 2048 digital signature verification
try {
std::string pupKeyStr ("e0c3851114c758fb943a30ca8f9b4c7f506d52aa101c34ad5134f2cdbdddbef11ee6d1470d54caf3774d4d17d69488abf0b78beaebc046115cb29617610e98be3d5c303e19c14ae57ce0994701e3f24a628abf5c421777fb3c2b9b8b17f2a4cda4b9fd89e3c122085831c3e4502734bc3f3157d3ccd01198a8e3795f03661b55112acb69e8d5782bdf506bf5222777baf382d4d4bc2dd83e53af9236ed6e7a0fb8b5bb543ed4abbf478911bdc517e13e580b138f10f153eb2733ad60f3796e99b7d59f9abbd6666c69ba5ecc17a391424dc8ca3cf24a759c62d490056cda30265e11e316e7695028721c50eaf8e596161f0b59e4f598c85063bb3a847a5acb9d");
//sha256 hashed data signature
std::string signatureStr = "d8d1df600d6781a9c030d9c697ec928eac34bf0670cf469f7fffb9c046deaee359b4e1218b419ff2589434510db8470ccf7abd28876a04b8d5a27293723e897f97a9367d2fbb379f8c52ec2a04cb71a06891a3f44d00e8bb9622b2038dbe6f29d0118203c372853ae09fb820702f1c16ee772998bd8a3db9e5127992a18d999fc422822caf0a82d9c12d6231605457ce651b0350b1e98584f9d4e6b973d6668df863d4b73784bbc00d8449918a0f049ddbeffc0d79579ade13a2d9012906b7ded7aae934bc54c5b85c924aee6627d66b7b200a23cd9b6a9c14650f1f9384e9ef9b90ac217ece026a1802bc0623150057ecd2b31f5f758e4ff866bb2e81d28368";
//Chinese Remainder Theorem (CRT)
std::string pupExpStr ("0x10001");
CryptoPP::AutoSeededRandomPool rng;
CryptoPP::RSA::PublicKey pubKeyRaw;
CryptoPP::Integer pup_key_cast( static_cast<CryptoPP::Integer> (pupKeyStr.c_str()));
CryptoPP::Integer pup_exp_cast( static_cast<CryptoPP::Integer> (pupExpStr.c_str()));
pubKeyRaw.Initialize(pup_key_cast, pup_exp_cast);
if (!pubKeyRaw.Validate(rng, 3))
{
std::cout << "Error while public key validation" << std::endl;
}
CryptoPP::RSASS<CryptoPP::PSS, CryptoPP::SHA256>::Verifier verifier_sha256(pubKeyRaw);
CryptoPP::StringSource( signatureStr, true,
new CryptoPP::SignatureVerificationFilter(
verifier_sha256, NULL,
CryptoPP::SignatureVerificationFilter::THROW_EXCEPTION
) // SignatureVerificationFilter
); // StringSource
}
catch( CryptoPP::Exception& e )
{
std::cerr << "ERROR: " << e.what() << std::endl;
}
catch( ... )
{
std::cerr << "ERROR: Unknown verify signature error" << std::endl;
}
}
What i have missed?
I will be very grateful for any help!
Thanks in advance!
How it is possible to verify a digital signature with the crypto++ library?
Well, that one is easy when you know where to look. From the Crypto++ wiki on RSA Signature Schemes:
RSA::PrivateKey privateKey = ...;
RSA::PublicKey publicKey = ...;
////////////////////////////////////////////////
// Setup
string message = "RSA-PSSR Test", signature, recovered;
////////////////////////////////////////////////
// Sign and Encode
RSASS<PSSR, SHA1>::Signer signer(privateKey);
StringSource ss1(message, true,
new SignerFilter(rng, signer,
new StringSink(signature),
true // putMessage for recovery
) // SignerFilter
); // StringSource
////////////////////////////////////////////////
// Verify and Recover
RSASS<PSSR, SHA1>::Verifier verifier(publicKey);
StringSource ss2(signature, true,
new SignatureVerificationFilter(
verifier,
new StringSink(recovered),
THROW_EXCEPTION | PUT_MESSAGE
) // SignatureVerificationFilter
); // StringSource
cout << "Verified signature on message" << endl;
cout << "Message: " << recovered << endl;
CryptoPP::RSASS<CryptoPP::PSS, CryptoPP::SHA256>::Verifier verifier_sha256(pubKeyRaw);
A few questions:
Should that be PSS (signature scheme with appendix) or PSSR (signature scheme with recovery)?
Are you certain its not, for example, PKCS1v15?
If it is a recovery scheme, is the signature at the beginning or end of the hex encoded signatureStr?
This original Integer initialization was probably wrong. Crypto++ will attempt to parse the string as a decimal integer, and not a hexadecimal integer because in lacks a 0x prefix and h suffix (one or the other should be present).
You should add the prefix, suffix, or use the byte array constructor. The byte array constructor is shown below.
std::string pupKeyStr ("e0c3851114c758fb...");
string pupKeyBin;
StringSource ss1(pupKeyStr, true,
new HexDecoder(
new StringSink(pupKeyBin)
)
);
CryptoPP::Integer pup_key_cast( (unsigned char*)pupKeyBin.data(), pupKeyBin.size() );
StringSource( signatureStr, true, ...
...
This is probably wrong. You probably need something like:
string signatureBin;
StringSource ss1(signatureStr, true,
new HexDecoder(
new StringSink(signatureBin)
)
);
StringSource ss2(signatureBin, true,
new SignatureVerificationFilter(...
...
I tried the code with the binary signature using both PSSA and PSSR. Neither worked. I also tried with SignatureVerificationFilter's SIGNATURE_AT_BEGIN and SIGNATURE_AT_END. Neither worked. And I tried the combinations with SHA1 and RSASSA_PKCS1v15_SHA_Verifier. Nothing worked.
Can you verify precisely what you have?