How encrypt and decrypt several values in a row - c++

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.

Related

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

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;
}

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.

InvalidCiphertext exception when decrypting ciphertext

I'm working in a new protocol for secure communication and I'm having problems to decrypt the ciphertext.
The data packet is saved in a uint8_t* variable and encrypted. Until this part is all going well. But when I try to decrypt I got the followings problems:
1) If I send the vector and the size (it's really 20 but I just want to decrypt the last 16 bytes):
CBC_Mode< AES >::Decryption decryptor;
decryptor.SetKeyWithIV( key, CryptoPP::AES::DEFAULT_KEYLENGTH, iv );
CryptoPP::StringSource ss( vector+4, 16 , true,
new CryptoPP::StreamTransformationFilter( decryptor,
new CryptoPP::StringSink( decryptedtext ) ) );
I get this:
terminate called after throwing an instance of 'CryptoPP::InvalidCiphertext'
what(): StreamTransformationFilter: invalid PKCS #7 block padding found
2) If I just send the vector without size:
CryptoPP::StringSource ss( vector+4, true,
new CryptoPP::StreamTransformationFilter( decryptor,
new CryptoPP::StringSink( decryptedtext ) ) );
The programs runs but I just get all 00:
Text Encrypted (20 bytes)
8c 97 b7 d8 74 80 3d 9f 9f 62 2e 93 38 c7 d1 b de a4 21 80
Text Decrypted (16 bytes)
0 0 0 0 0 0 0 0 68 0 0 0 0 0 0 0 0 0 0 0
I read that it could be that the key is not generated correctly, but I'm working with a size of 16 and here is how I do it:
byte key[ CryptoPP::AES::DEFAULT_KEYLENGTH ], iv[ CryptoPP::AES::BLOCKSIZE ];
memset( key, 0x00, CryptoPP::AES::DEFAULT_KEYLENGTH );
memset( iv, 0x00, CryptoPP::AES::BLOCKSIZE );
3) I also tried to cast the vector to char and send it like an string:
CryptoPP::StringSource ss( reinterpret_cast<const unsigned char*>( (vector + 4) ), 16, true,
new CryptoPP::StreamTransformationFilter( decryptor,
new CryptoPP::StringSink( decryptedtext ) ) );
But again I get the same thing:
terminate called after throwing an instance of 'CryptoPP::InvalidCiphertext'
what(): StreamTransformationFilter: invalid PKCS #7 block padding found
Please help, I have tried for days to figure out what's wrong. This is taking me too long and I can't find the solutions.
Does anyone have any idea on what might be happening?
Let me know if you need further details, code or anything.
Edit:
4) One more thing that I tried was (another way to construct the decrypter):
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*>( (vector + 4) ), 16 );
stfDecryptor.MessageEnd();
But I get the same:
terminate called after throwing an instance of 'CryptoPP::InvalidCiphertext'
what(): StreamTransformationFilter: invalid PKCS #7 block padding found
Edit2:
The vector is created with this line (the way the vector is fulled is a quite complicated to put it here because I am using a platform for network encoding) :
uint8_t* vector;
Edit3:
This is how I encrypt the vector.
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 ) );
stfEncryptor.Put( reinterpret_cast<const unsigned char*>( (vector + 4) ), 16 );
stfEncryptor.MessageEnd();
And after that I put the ciphertext again in the vector:
std::cout << std::endl << std::endl;
for(int i=0;i < 16; i++){
*(vector+ i + 4) = (ciphertext[i]) ;
}
terminate called after throwing an instance of CryptoPP::InvalidCiphertext'
what(): StreamTransformationFilter: invalid PKCS #7 block padding found
This is easy enough to fix. Catch a Crypto++ InvalidCiphertext exception. See the InvalidCiphertext Class Reference.
-----
If I just send the vector without size:
CryptoPP::StringSource ss( vector+4, true, ...
I think this might be matching the following StringSource constructor, which means the length is true, which probable means 1. To add insult to injury the attached StreamTransformationFilter is being coerced into the bool pumpAll:
StringSource (const byte *string, size_t length, bool pumpAll, BufferedTransformation *attachment=NULL)
You should probably enable warnings to catch these sorts of things. -Wall -Wextra are good choices. (Nothing will help the coercion of the pointer to the bool, though. See, for example, No pointer conversion warning for "bool" in C/C++ on the GCC mailing list).
-----
If I send the vector and the size (it's really 20 but I
just want to decrypt the last 16 bytes):
...
CryptoPP::StringSource ss( vector+4, 16 , true, ...
I don't think this is going to work as expected. CBC mode is not a random access mode (but I may not be parsing things correctly):
CBC_Mode< AES >::Encryption enc;
cout << "Random access: " << enc.IsRandomAccess() << endl;
Results in:
Random access: 0
I'm fairly certain its not going to work at byte sizes. You might be able to do it by adding a layer above the decryptor, but you will have to manage the initialization vector, then decrypt a block, and finally return the offest into the block.
-----
You should probably do something like the following. Its not efficient because it copes a string to a vector, but I wanted to try an use vectors since you seem to be using them.
encrypted.CopyTo(f2) is where you put your socket code. Your code will not need encrypted.CopyTo(f2).
// Creates the memory block and zero's it.
SecByteBlock key(AES::DEFAULT_KEYLENGTH), iv(AES::BLOCKSIZE);
/////////////////////////////////////////////////////////////
string m1;
vector<char> v1;
m1 = "Now is the time for all good men to come to the aide of their country";
copy(m1.begin(), m1.end(), back_inserter(v1));
CBC_Mode< AES >::Encryption enc;
enc.SetKeyWithIV(key, key.size(), iv, iv.size());
ByteQueue encrypted;
StreamTransformationFilter f1(enc, new Redirector(encrypted));
f1.PutWord32((uint32_t)v1.size(), BIG_ENDIAN_ORDER);
f1.Put((const unsigned char *) &v1[0], v1.size());
f1.MessageEnd();
/////////////////////////////////////////////////////////////
string m2;
vector<char> v2;
CBC_Mode< AES >::Decryption dec;
dec.SetKeyWithIV(key, key.size(), iv, iv.size());
ByteQueue decrypted;
StreamTransformationFilter f2(dec, new Redirector(decrypted));
encrypted.CopyTo(f2);
f2.MessageEnd();
uint32_t len;
decrypted.GetWord32(len, BIG_ENDIAN_ORDER);
v2.resize(len);
decrypted.Get((unsigned char *) &v2[0], v2.size());
copy(v2.begin(), v2.end(), back_inserter(m2));
/////////////////////////////////////////////////////////////
cout << "Message: " << m1 << endl;
cout << "Decrypted: " << m2 << endl;
It produces the expected results:
$ ./cryptopp-test.exe
Message: Now is the time for all good men to come to the aide of their country
Decrypted: Now is the time for all good men to come to the aide of their country
-----
Regarding your use of vector + 4: once the cipher text is decrypted, you can seek in it, and do things like read a length from it. That's what this does:
// Ciphertext is already decrypted
uint32_t len;
decrypted.GetWord32(len, BIG_ENDIAN_ORDER);
If you just want to discard the value, then try:
decrypted.Skip(4);
But then you'll have to figure out how to size your vector.
-----
I'm working in a new protocol for secure communication
Secure communications usually provides both confidentiality and authenticity assurances. You seem to be missing the latter since CBC mode only provides confidentiality.
It might be a good idea to use something that already exists, like IPSec (preferred) or TLS (will do in a pinch). Also, key agreement is going to be a pain point. Its another reason to consider using something like IPSec or TLS.
If you can't use something already available, then you should use an Authenticated Encryption mode so you get confidentiality and authenticity combined into a single mode. Try EAX, GCM or CCM mode.
If you do, then then change is fairly trivial:
EAX< AES >::Encryption enc;
enc.SetKeyWithIV(key, key.size(), iv, iv.size());
ByteQueue encrypted;
AuthenticatedEncryptionFilter f1(enc, new Redirector(encrypted));
And:
EAX< AES >::Decryption dec;
dec.SetKeyWithIV(key, key.size(), iv, iv.size());
ByteQueue decrypted;
AuthenticatedDecryptionFilter f2(dec, new Redirector(decrypted));
-----
You can print the cipher text by copying it to an encoder. Copying is non-destructive (unlike moving it with TransferTo):
string encoded;
HexEncoder encoder(new StringSink(encoded));
encrypted.CopyTo(encoder);
encoder.MessageEnd();
Fox CBC mode (less secure):
Encrypted: 7F9FFCAB00704EC79BB5F19C48FE7C668033B16F52E7E00671A38A06F4A7426E7FE31
95CA6A83C7414A76C250B42E63143C93E7A6B97B6304C5782DE3E62BD545706A9F62CD7AD57BC374
19B7510EBED
For EAX mode (more secure):
Encrypted: B75347EB75DF8E1F0424979E91CEECD455F5727B506A8AA932AF07E1DF6A7B037A245
FEC7A2270BFAB8110226769E1C0A12E95C455E9C714AF28DA330A2B01B3F2D541D4E68276193C018
7BA0246166AD26624E848EC8330D3
The extra bytes in EAX mode are the authentication tag. Its used to detect accidental and malicious tampering.
The problem was that I was encoding with padding and trying to decrypt it without. So I add not only in the encryption but in the descryption that it should work without padding.
Creation of the Key and IV:
CBC_Mode< AES >::Encryption encryptor;
encryptor.SetKeyWithIV( key, CryptoPP::AES::DEFAULT_KEYLENGTH, iv );
Encryption:
CryptoPP::StringSource ss( vector + 4 , 16, true,
new CryptoPP::StreamTransformationFilter( encryptor,
new CryptoPP::StringSink( ciphertext ),
CryptoPP::StreamTransformationFilter::NO_PADDING
) // StreamTransformationFilter
); // StringSource
Decryption:
CBC_Mode< AES >::Decryption decryptor;
decryptor.SetKeyWithIV( key, CryptoPP::AES::DEFAULT_KEYLENGTH, iv );
CryptoPP::StringSource ss( reinterpret_cast<const unsigned char*>( (vector + 4) ), 16, true,
new CryptoPP::StreamTransformationFilter( decryptor,
new CryptoPP::StringSink( decryptedtext ), CryptoPP::StreamTransformationFilter::NO_PADDING) );
I did this because I don't want to work with padding anymore.

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.