Decrypt of file displays both original and cipher text? - c++

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.

Related

Cryptopp: Decrypt array of char with binary data

I'm almost new in Cryptopp.
This is my encrypted data:
...
char* mDataBuffer = new char[length];
inFile.read((char*)(&mDataBuffer[0]), length);
By reading the inFile, now the mDataBuffer array contains encrypted binary data.
There's no problem with this mDataBuffer (tested carefully!).
Now I need to decrypt this array.
Note that the file (now presented as mDataBuffer array) is encrypted in java or .net in AES/CBC/PKCS7PADDING.
The decrypted data should be in char type (or could be converted to it!)
Here's my c++ code for decryption:
byte mkey[] = "12345678"; // note that the key is only 8 chars
CBC_Mode< AES >::Decryption decryptor;
decryptor.SetKeyWithIV(mkey, 16, mkey); // IV and key are same. I used 16 bytes and I think it causes Cryptopp to use PKCS#7 padding (Am I write?!)
char* decryptedBytes = new char[length];
Then I've tried many things, for example:
Try 1:
std::string plain;
StreamTransformationFilter stf(decryptor, new CryptoPP::StringSink(plain));
for (int i = 0; i < length; i++) {
stf.Put(mDataBuffer[i], sizeof(mDataBuffer[i]));
}
stf.MessageEnd();
With this code I get this error message:
CryptoPP::InvalidCiphertext at memory location
The mDataBuffer is binary data and contains 0x00 data (or '\0').
Try 2:
ArraySink cs((byte*)&decryptedBytes[0], length);
StreamTransformationFilter stf(decryptor, new Redirector(cs));
ArraySource((const char*)(&mDataBuffer[0]), true,
new StreamTransformationFilter(d, new Redirector(cs)));
With this code I get this error message:
CryptoPP::InvalidCiphertext at memory location
Note: I cant use FileSource (maybe I'm wrong!). Because the file has extra data and this data is removed manually after it has been read to mDataBuffer (for simplicity I didn't include the code here)
I wonder how I stock to this!
Thanks any help or hint.

Passing a key to AES decryption in Crypto++

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

String to SecByteBlock Conversion Issues

I'm having an issue with allocating a new key for 3 key Triple DES in crypto++.
I've generated a new key as a string but need to allocate it to SecByteBlock for use in Crypto++.
Currently I generate a random key using the PRNG at the start, but when I attempt to change the key using string output from DES_EDE3, it appears to use the same key.
I think the issue is with the conversion between string and SecByteBlock, or the allocation to SecByteBlock as shown below.
Any help would be greatly appreciated!
SecByteBlock GENERATOR::setKey(string keyString){
SecByteBlock replacementKey(24);
replacementKey= SecByteBlock(reinterpret_cast<const byte*>(keyString.data()), keyString.size());
return newKey = replacementKey;
}
I attempt to change the key using string output from DES_EDE3, it appears to use the same key
It almost sounds like you are trying to use 3-DES as a PRF keyed with a password. If so, use HKDF. Its designed for these types of expand-then extract operations.
HKDF is available in Crypto++ 5.6.3 and above. If you need it for a downlevel client, then copy the header where you need it.
SecByteBlock GENERATOR::setKey(string keyString){
SecByteBlock replacementKey(24);
replacementKey= SecByteBlock(reinterpret_cast<const byte*>(keyString.data()), keyString.size());
return newKey = replacementKey;
}
Though you size replacementKey to 24, it could be resized by the assignment replacementKey= SecByteBlock(...).
You might want to try the following:
SecByteBlock GENERATOR::setKey(const string& keyString)
{
SecByteBlock key((const byte*)keyString.data(), keyString.size());
if(key,size() < DES_EDE3::KEYLENGTH)
key.CleanGrow(DES_EDE3::KEYLENGTH);
else
key.resize(DES_EDE3::KEYLENGTH);
return key;
}
CleanGrow sizes the memory block to DES_EDE3::KEYLENGTH and backfills the block with 0's as needed. resize will truncate to DES_EDE3::KEYLENGTH if its too large.
You could also do something like:
SecByteBlock key(DES_EDE3::KEYLENGTH);
size_t s = STDMIN(key.size(), keyString.size());
memcpy(key.data(), keyString.data(), s);
if(s < DES_EDE3::KEYLENGTH)
memset(key.data()+s, 0, DES_EDE3::KEYLENGTH-s);
-----
To combine the first two, you might consider this:
SecByteBlock GENERATOR::setKey(const string& keyString)
{
// Block is unintialized
SecByteBlock key(DES_EDE3::KEYLENGTH);
HKDF<SHA256> kdf;
kdf.Derivekey(key.data(), key.size(), (const byte*)keyString.data(), keyString.size(), NULL, 0);
return key;
}
-----
You can output a SecByteBlock with code like:
SecByteBlock b = GENERATOR::setKey(...);
...
cout << "Derived key: "
ArraySource as(b.data(), b.size(), true, new HexEncoder(new FileSink(cout)));
cout << endl;
The following with encode it using Base64:
ArraySource as(b.data(), b.size(), true, new Base64Encoder(new FileSink(cout)));

Decryption results in gibberish with Rijndael and 256 block size [duplicate]

This question already has an answer here:
256-bit Rijndael blocksize?
(1 answer)
Closed 7 years ago.
so i have some old messages encrypted with this old code:
'the ecryption algorithm with specific settings
Dim myRijndael As New RijndaelManaged
myRijndael.Padding = PaddingMode.Zeros
myRijndael.Mode = CipherMode.CBC
myRijndael.KeySize = 256
myRijndael.BlockSize = 256
'declared byte arrays for the message string and the key and IV for the encryption algorithm
Dim encrypted() As Byte
Dim toEncrypt() As Byte
Dim key() As Byte
Dim IV() As Byte
'populating the arryas with the needed bytes for the encryption algorithm
key = System.Text.Encoding.ASCII.GetBytes(prm_key)
IV = System.Text.Encoding.ASCII.GetBytes(prm_iv)
'the actual instance of the ecryption algorithm
Dim encryptor As ICryptoTransform = myRijndael.CreateEncryptor(key, IV)
'streams for the encrypted byte array
Dim msEncrypt As New MemoryStream()
Dim csEncrypt As New CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write)
toEncrypt = System.Text.Encoding.ASCII.GetBytes(text_to_encrypt)
csEncrypt.Write(toEncrypt, 0, toEncrypt.Length)
'make sure we have all the blocks
csEncrypt.FlushFinalBlock()
'turn encrypted stream into byte array
encrypted = msEncrypt.ToArray()
'return a base 64 string so we can upload it to the server
Return (Convert.ToBase64String(encrypted))
and i am trying to decrypt it with Crypto++
this is the code that i came up with:
std::string coded = "pCyWPA5Enc3F0NAkowrt206brSfMrOgKMTXI1pKhCUY=";
//std::string coded = "F9uvtbK3Ue67Gbe9si5yvDn8a50bYnTovjfWali+Xjo=";
std::string coded2;
std::string ciphertext;
std::string decryptedtext;
CryptoPP::StringSource sss(coded, true,
new CryptoPP::Base64Decoder(
new CryptoPP::StringSink(ciphertext)
) // Base64Decoder
); // StringSource
CryptoPP::AES::Decryption aesDecryption(key, CryptoPP::AES::MAX_KEYLENGTH);
CryptoPP::CBC_Mode_ExternalCipher::Decryption cbcDecryption( aesDecryption, iv );
CryptoPP::StreamTransformationFilter stfDecryptor(cbcDecryption, new CryptoPP::StringSink( decryptedtext ),CryptoPP::BlockPaddingSchemeDef::ZEROS_PADDING);
stfDecryptor.Put( reinterpret_cast<const unsigned char*>( ciphertext.c_str() ), ciphertext.size() );
stfDecryptor.MessageEnd();
//
// Dump Decrypted Text
//
std::cout << "Decrypted Text: " << std::endl;
std::cout << decryptedtext;
std::cout << std::endl << std::endl;
but all i get in return is gibberish. The padding modes are set, the key is correct. I'm out of ideas.
The commented out "coded" string actually get decrypted, but it was encrypted with c++ and crypto++. The text is identical. so why are the Base64 encrypted stings different?
Im thinking that maybe since VB code encrypted bytes in ASCII that that might be the issue. but i don't know how to make crypto++ use ASCII encoding.
Can someone please point out the issue here?
AES uses a 128 bit block size. The VB code uses Rijndael with 256 bit block size.

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.