Passing a key to AES decryption in Crypto++ - c++

I have searched a lot for this issue but did not find any solution. In my current project, I have to work on encrypting images with a sender receiver form. So i have to generate a key in the sender part to encrypt the file, and i have to use the same key (which is passed as an argument to the main) to get the original data, to continue program execution.
I save the key on a text file:
void GetKeyAndIv() {
// Initialize the key and IV
prng.GenerateBlock( key, key.size() );
prng.GenerateBlock(iv, iv.size());
};
/*********************Begin of the Function***********************/
//Function encrypt a file (original file) and store the result in another file (encrypted_file)
void Encrypt(std::string original_file, std::string encrypted_file_hex,string encrypted_file,string binary) {
ofstream out;
out.open("Key.txt");
out.clear();
out<<"key = "<< key<<endl;
out<<"iv = "<< iv<<endl;
string cipher, encoded;
//Getting the encryptor ready
CBC_Mode< CryptoPP::AES >::Encryption e;
e.SetKeyWithIV( key, key.size(), iv );
try
{
ifstream infile(original_file.c_str(), ios::binary);
ifstream::pos_type size = infile.seekg(0, std::ios_base::end).tellg();
infile.seekg(0, std::ios_base::beg);
//read the original file and print it
string temp;
temp.resize(size);
infile.read((char*)temp.data(), temp.size());
infile.close();
// Encryption
CryptoPP::StringSource ss( temp, true,
new CryptoPP::StreamTransformationFilter( e,
new CryptoPP::StringSink( cipher )//,
//CryptoPP::BlockPaddingSchemeDef::NO_PADDING
) // StreamTransformationFilter
); // StringSource
std::ofstream outfile1(encrypted_file.c_str(),ios::out | ios::binary);
outfile1.write(cipher.c_str() , cipher.size());
}
catch( const CryptoPP::Exception& e )
{
cout <<"Encryption Error:\n" <<e.what() << endl;
system("pause");
exit(1);
}
Then i pass it to the client side using the following code:
int main(int argc, char* argv[])
{
.....
string s1=argv[7];
SecByteBlock b1(reinterpret_cast<const byte*>(&s1[0]), s1.size());
string s2=argv[8];
SecByteBlock iv1(reinterpret_cast<const byte*>(&s2[0]), s2.size());
.....
}
I got an error while trying to decrypt the file, using the following code
void Decrypt(std::string encrypted_file,SecByteBlock key,SecByteBlock iv,string decrypted_file) {
string recovered;
try
{
// Read the encrypted file contents to a string as binary data.
std::ifstream infile(encrypted_file.c_str(), std::ios::binary);
const std::string cipher_text((std::istreambuf_iterator<char>(infile)),
std::istreambuf_iterator<char>());
infile.close();
CBC_Mode< CryptoPP::AES >::Decryption d;
d.SetKeyWithIV( key, key.size(), iv );
Decryption Error:
StreamTransformationFilter: invalid PKCS #7 block padding found
Which means i have different key during decryption process. Why this happened, and if anyone can help solving this issue.

It happen if the key used for decryption in not the same as the key that has been used for encryption.
During decryption, in PKCS#7 mode, just after decrypting the last block of 16 bytes, there is a check of padding bytes in order to know the original length of the message (which is not necessary a multiple of 16 bytes) : the last byte should be 0x01, or the last two bytes should be equal to 0x02, or the last three bytes should be equal to 0x03, ... When the decryption key is not the same as the encryption key, the padding bytes are not decrypted correctly and this implies a PKCS#7 block padding error when decrypting.

I change the CBC_Mode to another modes instead, ODB_Mode work for me

Related

Invalid PKCS #7 block padding found when using Crypto++

We are using the code below with the Crypto++ library. We need to encrypt and decrypt char*. Encryption is working fine without any issue and we are able to get the cipher text. But getting an error while decrypting as "invalid pkcs #7 block padding found". What could be the issue...?
Encryption Block:
char* cspl_crypto::encrypt_rijndael(byte key[], byte iv[], int keysize, char plainText[], int plainTextSize)
{
vector<byte> cipher;
std::vector<byte> plain(plainText, plainText + plainTextSize);
CBC_Mode<AES>::Encryption enc;
enc.SetKeyWithIV(key, keysize, iv, keysize);
// Make room for padding
cipher.resize(plain.size()+AES::BLOCKSIZE);
ArraySink cs(&cipher[0], cipher.size());
ArraySource(plain.data(), plain.size(), true,
new StreamTransformationFilter(enc, new Redirector(cs)));
// Set cipher text length now that its known
cipher.resize(cs.TotalPutLength());
char returnValue[cipher.size()];
copy(cipher.begin(), cipher.end(), returnValue);
return returnValue;
}
Decyption Block:
char* cspl_crypto::decrypt_rijndael(byte key[], byte iv[], int keysize, char cipher[], int size )
{
std::vector<byte> v(cipher, cipher + size);
vector<byte> recover;
CBC_Mode<AES>::Decryption dec;
dec.SetKeyWithIV(key, keysize, iv, keysize);
// Recovered text will be less than cipher text
recover.resize(v.size());
ArraySink rs(&recover[0], recover.size());
ArraySource(v.data(), v.size(), true,
new StreamTransformationFilter(dec, new Redirector(rs)));
// Set recovered text length now that its known
recover.resize(rs.TotalPutLength());
char returnValue[recover.size()];
copy(recover.begin(), recover.end(), returnValue);
return returnValue;
}

How encrypt and decrypt several values in a row

In my programm I use crypto++ library.
I have so struct:
struct crypt_struct{
//consists of encrypted data
string name1;
string name2;
string name3;
}
struct decrypt_struct{
//consists of decrypted data
int name1;
string name2;
double name3;
}
I have encrypt function:
crypt_struct encrypt(decrypt_struct struct_in) {
//Key and IV setup
//AES encryption uses a secret key of a variable length (128-bit, 196-bit or 256-
//bit). This key is secretly exchanged between two parties before communication
//begins. DEFAULT_KEYLENGTH= 16 bytes
byte key[CryptoPP::AES::DEFAULT_KEYLENGTH], iv[CryptoPP::AES::BLOCKSIZE];
memset(key, 0x00, CryptoPP::AES::DEFAULT_KEYLENGTH);
memset(iv, 0x00, CryptoPP::AES::BLOCKSIZE);
//output encrypt struct
crypt_struct struct_out;
//encrypt text
string ciphertext;
CryptoPP::AES::Encryption aesEncryption(key, CryptoPP::AES::DEFAULT_KEYLENGTH);
CryptoPP::CBC_Mode_ExternalCipher::Encryption cbcEncryption(aesEncryption, iv);
CryptoPP::StreamTransformationFilter stfEncryptor(cbcEncryption, new CryptoPP::StringSink(ciphertext));
//int name1
stfEncryptor.Put(reinterpret_cast<const unsigned char*> ((to_string(struct_in.name1)).c_str()), (to_string(struct_in.name1)).length() + 1);
stfEncryptor.MessageEnd();
struct_out.name1 = ciphertext;
cout << ciphertext << endl;
ciphertext.clear();
//string name2
stfEncryptor.Put(reinterpret_cast<const unsigned char*> (struct_in.name2.c_str()), struct_in.name2.length() + 1);
stfEncryptor.MessageEnd();
struct_out.name2 = ciphertext;
cout << ciphertext << endl;
ciphertext.clear();
//double name3
stfEncryptor.Put(reinterpret_cast<const unsigned char*> ((to_string(struct_in.name3)).c_str()), (to_string(struct_in.name3)).length() + 1);
stfEncryptor.MessageEnd();
struct_out.name3 = ciphertext;
cout << ciphertext << endl;
ciphertext.clear();
return struct_out;
}
And decrypt function:
decrypt_struct decrypt(crypt_struct struct_in)
{
//Key and IV setup
//AES encryption uses a secret key of a variable length (128-bit, 196-bit or 256-
//bit). This key is secretly exchanged between two parties before communication
//begins. DEFAULT_KEYLENGTH= 16 bytes
byte key[CryptoPP::AES::DEFAULT_KEYLENGTH], iv[CryptoPP::AES::BLOCKSIZE];
memset(key, 0x00, CryptoPP::AES::DEFAULT_KEYLENGTH);
memset(iv, 0x00, CryptoPP::AES::BLOCKSIZE);
//
// Decrypt
//
decrypt_struct struct_out;
string decryptedtext;
CryptoPP::AES::Decryption aesDecryption(key, CryptoPP::AES::DEFAULT_KEYLENGTH);
CryptoPP::CBC_Mode_ExternalCipher::Decryption cbcDecryption(aesDecryption, iv);
CryptoPP::StreamTransformationFilter stfDecryptor(cbcDecryption, new CryptoPP::StringSink(decryptedtext));
stfDecryptor.Put(reinterpret_cast<const unsigned char*>(struct_in.name1.c_str()), struct_in.name1.length());
struct_out.name1= atoi(decryptedtext.c_str());
stfDecryptor.MessageEnd();
decryptedtext.clear();
stfDecryptor.Put(reinterpret_cast<const unsigned char*>(struct_in.name2.c_str()), struct_in.name2.length());
struct_out.name2= atoi(decryptedtext.c_str());
stfDecryptor.MessageEnd();
decryptedtext.clear();
stfDecryptor.Put(reinterpret_cast<const unsigned char*>(struct_in.name3.c_str()), struct_in.name3.length());
struct_out.name3= atoi(decryptedtext.c_str());
stfDecryptor.MessageEnd();
decryptedtext.clear();
return struct_out;
}
If I try encrypt only one variable, then everything is decrypted correctly. But if I try to encrypt several variables at the same time, then an error occurs. And moreover, when encrypting the variable int type, the same error occurs. With what it can be connected, is there anyone's idea?
It seems to me that perhaps the reason is that at a time this function can only encrypt one line.
The problem was this:
The matter is that in the source code of this library, when decrypting, the c_str() function is used. Those:
stfDecryptor.Put(reinterpret_cast<const unsigned char*> (struct_in.name1.c_str()), struct_in.name1.size());
The official documentation says:
The pointer obtained from c_str() may only be treated as a pointer to a null-terminated character string if the string object does not contain other null characters.
In the encryption function, a zero character is added to the string, and when we try to decrypt, by the c_str() function, we trim our string with the first zero character.
But, in the standard with с++ 11, an analogous function was added that performs the same action as the data() function, except that it does not take into account the null character.
As a result, I received:
stfDecryptor.Put(reinterpret_cast<const unsigned char*> (struct_in.name1.data()), struct_in.name1.size());
Also, it was important if you encrypt first name1, then name2, and name3. That and decrypt you should in the same sequence.

Decrypt of file displays both original and cipher text?

I am working to encrypt and decrypt files using Crypto++. In encryption, key and random IV are generated and hexencoded where as text from file is encrypted. Both IV and cipher text are written to the same file.
In decryption, key is generated using same criteria as encryption and random IV is extracted from the file and hexdecoded. Text after iv length is stored in a string and decrypted.
What happens is I can see the original file so I know that it is working but it also displays cipher text after the original file text. Does any one how to solve it?
//some code to declare variables, read from file and so on
unsigned char * inputContent = (unsigned char *) malloc(fileSize * sizeof(char)); //create char array of same size as file content
//inputContent is for storing file data
string rawString(reinterpret_cast<char*>(inputContent), fileSize); //convert char array to string
//extract iv, key and cipher from rawString
string rawIV;
rawIV = rawString.substr(0, 32);
//code to hexdecode iv
string cipher;
cipher = rawString.substr(32, fileSize - 32);
string recovered;
CBC_Mode< AES >::Decryption d;
d.SetKeyWithIV(key, sizeof(key), iv);
StringSource s_recover(cipher, true,
new StreamTransformationFilter(d,
new StringSink(recovered)
)
);
const char * writeContent = recovered.c_str();
if(pwrite(fd, writeContent, recovered.length(), 0) <= 0)
{
return -1; //error
}
Thanks in advance. ☺
You might try something like this. But its hard to say if it will actually work since its not clear what you are actually doing or where the problem lies.
FileSource fs("<filename>", false /*pumpAll*/);
SecByteBlock key(AES::DEFAULT_KEYLENGTH), iv(AES::BLOCKSIZE);
// Fetch key from somewhere
key = ...;
// Fetch IV from file
fs.Detach(new HexDecoder(new ArraySink(iv, iv.size()));
fs.Pump(32);
CBC_Mode< AES >::Decryption dec;
dec.SetKeyWithIV(key, key.size(), iv, iv.size());
string recovered;
fs.Detach(new HexDecoder(new StreamTransformationFilter(dec, new StringSink(recovered))));
fs.PumpAll();
You can also use the following if you get the SecByteBlockSink patch:
SecByteBlock recovered;
fs.Detach(new HexDecoder(new StreamTransformationFilter(dec, new SecByteBlockSink(recovered))));
fs.PumpAll();
rawString isn't needed below:
//create char array of same size as file content
unsigned char * inputContent = (unsigned char *) malloc(fileSize * sizeof(char));
//inputContent is for storing file data
//convert char array to string
string rawString(reinterpret_cast<char*>(inputContent), fileSize);
Maybe you should try:
ArraySource as(inputContent, fileSize, false /*pumpAll*/);
Using the ArraySource means you don't make a copy of the data (the string copies the data), and its ready to go for Crypto++.
Also, since you're already into C++ code, use an unique_ptr and new rather than malloc. The unique_ptr will handle cleanup for you. (Or, use a std::vector).
unique_ptr<byte[]> buffer(new byte[fileSize]);
I don't know how you are going to make a file descriptor work in the grand scheme of things. Crypto++ is a C++ library, and C++ uses I/O streams. Maybe this will help: How to construct a c++ fstream from a POSIX file descriptor?
Also see Retrieving file descriptor from a std::fstream and Getting a FILE* from a std::fstream.

Encrypt unsigned int value in form of bits stream by AES_CFB mode

I have c++ code that encrypts a string as a plaintext using AES_CFB and generates a same size ciphertext, but the problem is the data type of input and output, So could anyone help me to let it encrypts an unsigned int number and generates unsigned int number ciphertext withe keeping the same length for the plaintext and chipertext (length of bits ).
string ENCRYPTOR(const std::string& PlainText)
{
byte key[16]= "1234ff";// byte key[ CryptoPP::AES::DEFAULT_KEYLENGTH ];
byte iv[16]= "123456";//byte iv[ CryptoPP::AES::BLOCKSIZE ];
std::string CipherText;
// Encryptor
CryptoPP::CFB_Mode< CryptoPP::AES >::Encryption encryptor( key, sizeof(key), iv);
// Encryption
CryptoPP::StringSource( PlainText, true,
new CryptoPP::StreamTransformationFilter( encryptor,
new CryptoPP::StringSink( CipherText ) ) );
return (CipherText);
}
string DECRYPTOR(const string& CipherText)
{
byte key[16]= "1234ff";
byte iv[16]= "123456";
std::string RecoveredText;
// Decryptor
CryptoPP::CFB_Mode< CryptoPP::AES >::Decryption decryptor( key, sizeof(key), iv );
// Decryption
CryptoPP::StringSource( CipherText, true,
new CryptoPP::StreamTransformationFilter( decryptor,
new CryptoPP::StringSink( RecoveredText ) ) );
return (RecoveredText);
}
int main()
{
string ciphertext;
string plaintext = "3555";
ciphertext= ENCRYPTOR(plaintext);
string retrivdat = DECRYPTOR(ciphertext);
cout<<"The plaintext data is: "<<plaintext<<endl;
cout<<"The ciphertextdata is: "<<ciphertext<<endl;
Coot<<"The retrieved data is: "<<retrivdat<<end;
return 0;
}
The output is
The plaintext data is: 3555
The chepertext data is: ï¥R_
The retrieved data is: 3555
Encrypt unsigned int value in form of bits stream by AES_CFB mode
Igor and Owlstead raised some valid points about size of integers and endianess. The easiest solution to avoid them is probably encode the integer as a string:
unsigned int n = ...;
ostringstream oss;
oss << n;
string plainText = oss.str();
Later, you can convert it back with:
string recovered = ...;
istringstream iss(recovered);
unsigned int n;
iss >> n;
byte key[16]= "1234ff";// byte key[ CryptoPP::AES::DEFAULT_KEYLENGTH ];
byte iv[16]= "123456";//byte iv[ CryptoPP::AES::BLOCKSIZE ];
Your key and IV are too small. You should be getting compiler warnings because of it. AES::DEFAULT_KEYLENGTH is 16, so you need at least 16 characters for the key. AES::BLOCKSIZE is 16, so you need at least 16 characters for the initialization vector.
If the code above happens to work, then its purely because of luck. You should probably visit CFB Mode on the Crypto++ wiki. It has a working example.
Alternately, use PBKDF to stretch the short key and short IV. You can find an example at Crypto++ pbkdf2 output is different than Rfc2898DeriveBytes (C#) and crypto.pbkdf2 (JavaScript) on Stack Overflow.
The chepertext data is: ï¥R_
You can make this printable with:
string encoded;
HexEncoder hexer(new StringSink(encoded));
hexer.Put((byte*)cipherText.data(), cipherText.size());
hexer.MessageEnd();
cout << encoded << endl;
Alternately, you can use the following (with pipelines):
string encoded;
StringSource ss(cipherText, true,
new HexEncoder(
new StringSink(encoded)));
cout << encoded << endl;
HexEncoder and HexDecoder are discussed on the Crypto++ wiki, too.
So you can:
encode the number into the minimum number of x bytes, for instance using an unsigned big endian number
encrypt with CFB, resulting in the same number of x bytes
decrypt the number
decode the number from the resulting x bytes (using the same encoding scheme of course)
If you want to see the ciphertext as number you'll have to decode the ciphertext as if it was a (signed or unsigned) number.
Note that you will still have to deal with the uniqueness of the IV. If you need to store the IV then there will be significant overhead.

Creation of ECDSA private key given curve and private exponent?

I am new to cryptopp and have been struggling for a while with the creation of private keys for ECDSA signing.
I have a hex encoded private exponent E4A6CFB431471CFCAE491FD566D19C87082CF9FA7722D7FA24B2B3F5669DBEFB. This is stored as a string.
I want to use this to sign a text block using ECDSA. My code looks a bit like this
string Sig::genSignature(const string& privKeyIn, const string& messageIn)
{
AutoSeededRandomPool prng;
ECDSA<ECP, SHA256>::PrivateKey privateKey;
privateKey.AccessGroupParameters().Initialize(ASN1::secp256r1());
privateKey.Load(StringSource(privKeyIn, true, NULL).Ref());
ECDSA<ECP, SHA256>::Signer signer(privateKey);
// Determine maximum size, allocate a string with that size
size_t siglen = signer.MaxSignatureLength();
string signature(siglen, 0x00);
// Sign, and trim signature to actual size
siglen = signer.SignMessage(prng, (const byte *) messageIn.data(), (size_t) messageIn.length(), (byte*)signature.data());
signature.resize(siglen);
cout << signature.data() << endl;
return signature;
}
This code generates the following error in Visual studio on the when I try to do privateKey.load(...)
First-chance exception at 0x7693C42D in DLLTest.exe: Microsoft C++ exception: CryptoPP::BERDecodeErr at memory location 0x0033EEA8.
Unhandled exception at 0x7693C42D in DLLTest.exe: Microsoft C++ exception: CryptoPP::BERDecodeErr at memory location 0x0033EEA8.
I am guessing I am doing something a bit stupid... any help would be great???
PS I had a similar issue using ECDH for GMAC generation but got round this by saving the key as a SECByteBlock but this 'trick' doesnt seem to work in this case.
DLLTest.exe: Microsoft C++ exception: CryptoPP::BERDecodeErr ...
You have a private exponent, and not a private key. So you should not call Load on it. That's causing the Crypto++ BERDecodeErr exception.
The answer is detailed on the ECDSA wiki page, but its not readily apparent. You need to perform the following to initialize the privateKey given the curve and exponent::
string exp = "E4A6CFB431471CFCAE491FD566D19C87082CF9FA7722D7FA24B2B3F5669DBEFB";
exp.insert(0, "0x");
Integer x(exp.c_str());
privateKey.Initialize(ASN1::secp256r1(), x);
Prepending the "0x" ensures the Integer class will parse the ASCII string correctly. You can also append a "h" character to the string. You can see the parsing code for Integer class at Integer.cpp around line 2960 in the StringToInteger function.
Here's another way to do the same thing:
string exp = "E4A6CFB431471CFCAE491FD566D19C87082CF9FA7722D7FA24B2B3F5669DBEFB";
HexDecoder decoder;
decoder.Put((byte*)exp.data(), exp.size());
decoder.MessageEnd();
Integer x;
x.Decode(decoder, decoder.MaxRetrievable());
privateKey.Initialize(ASN1::secp256r1(), x);
The HexDecoder will perform the ASCII to binary conversion for you. The buffer held by the HexDecoder will then be consumed by the Integer using its Decode (BufferedTransformation &bt, size_t inputLen, Signedness=UNSIGNED) method.
And here is another way using HexDecoder (Crypto++ is as bad as scripting languages at times :)...
string exp = "E4A6CFB431471CFCAE491FD566D19C87082CF9FA7722D7FA24B2B3F5669DBEFB";
StringSource ss(exp, true /*punpAll*/, new HexDecoder);
Integer x;
x.Decode(ss, ss.MaxRetrievable());
privateKey.Initialize(ASN1::secp256r1(), x);
After initializing the key, you should validate it:
bool result = privateKey.Validate( prng, 3 );
if( !result ) { /* Handle error */ }
This will output binary data:
cout << signature.data() << endl;
If you want something printable/readable, run it though a Crypto++ HexEncoder.
for others looking for this later
string genSignature(const string& privKeyIn, const string& messageIn)
{
CryptoPP::Integer secretNumber(genSecretNumber(privKeyIn, messageIn));
AutoSeededRandomPool secretNumberGenerator;
if (encryptBase::debug)
{
cout << "secret number: " << secretNumber << endl;
}
SecByteBlock message(convertHexStrToSecByteBlock(messageIn));
ECDSA<ECP, SHA256>::PrivateKey privateKey;
string exp(privKeyIn);
exp.insert(0, "0x");
Integer x(exp.c_str());
privateKey.Initialize(ASN1::secp256r1(), x);
AutoSeededRandomPool prng;
if (!privateKey.Validate(prng, 3))
{
cout << "unable to verify key" << endl;
return "failed to verify key";
}
ECDSA<ECP, SHA256>::Signer signer(privateKey);
size_t siglen = signer.MaxSignatureLength();
string signature(siglen, 0x00);
siglen = signer.SignMessage(secretNumberGenerator, message.BytePtr(), message.size(), (byte*)signature.data());
signature.resize(siglen);
string encoded;
HexEncoder encoder;
encoder.Put((byte *) signature.data(), signature.size());
encoder.MessageEnd();
word64 size = encoder.MaxRetrievable();
if (size)
{
encoded.resize(size);
encoder.Get((byte*)encoded.data(), encoded.size());
}
return encoded;
}