C++ AES encrypt bigger string than 128bits - c++

AES has maximum block size of 128, and key sizes like 128, 196 & 256.
I have implemented the aes algorithm like so:
int main()
{
unsigned char key[KEY_128] = "very strong key";
unsigned char plaintext[16] = "this is a test";
unsigned char ciphertext[16];
unsigned char decptext[16];
aes_ctx_t *ctx;
virtualAES::Initialize();
ctx = virtualAES::AllocateCTX(key, sizeof(key));
virtualAES::Encrypt(ctx, plaintext, ciphertext);
cout << "encrypted: " << ciphertext << endl;
virtualAES::Encrypt(ctx, ciphertext, decptext);
cout << "decrypted: " << decptext << endl;
return 0;
}
but I want to encrypt larger data than 128bits, for example string that's 512 bits long.
How to achieve?

I posted this answer elsewhere, but as it applies here as well, here you go:
I am more familiar with C#, which has several modes of encryption exposed through the System.Security.Cryptography namespace. However I know how Cipher Block Chaining works. I'll explain it to you, but keep in mind it is really easy to mess up crypto, so this is informational only, and I hope you will find a library that does what you need done.
With cipher block chaining (CBC) here is what you do. Take your data and break it into block sizes. 128 bits is 16 bytes, so there you go. If you have less than 16 bytes in your last block, you must pad. The commonest way I know of is PKCS7 padding, which means for example if you need 3 bytes of padding at the end of your last block, you would add 0x03, 0x03, 0x03 to make it a full block.
So now you are ready to encrypt. You should have an initialization vector (IV) to start off with. Bitwise XOR that IV with your first block of plain text. Then encrypt the result the way you normally would encrypt a single block of data (ECB mode). The result is your first block of cipher text. But it is also equivalent to the IV for the next block you want to encrypt. Bitwise XOR it with the second block and encrypt. Take that encrypted block, record it, and also use it to XOR with the third block. And so on.
This process makes it so that the exact same text appearing, let's say 5 times in a document will look totally different each time it appears. So it adds more security. Despite this, the IV does not need to be kept secret at all. Passwords and salts do, IVs do not.

Related

AES ECB known-text attack

I'm trying to perform known-text attack to obtain 32 byte key.
BlockSize is 16 byte.
Regarding this: https://crypto.stackexchange.com/a/12512
Or this: https://security.stackexchange.com/a/102110
As far as I understood:
1) Encrypt known 15 byte block
2) Encrypt known 256 16 byte blocks with different tailing byte
3) Compare blocks and get one byte of secret
void test() {
unsigned char KnownText[15];
memset(KnownText, 'A', 15);
unsigned char EncryptedText[32];
int result_size = AES_ECB.EncryptBlock(EncryptedText, KnownText, 15);
unsigned char CKnownText[16];
for (int i = 0; i < 256; ++i) {
memset(CKnownText, 'A', 16);
CKnownText[15] = i;
unsigned char Encrypted[32];
int enc_result = AES_ECB.EncryptBlock(Encrypted, CKnownText, 16);
if(memcmp(EncryptedText, Encrypted, 16) == 0) {
//match found
}
}
}
I get only one match when i=0 (suppose because 0 was appended to first 15 byte block) and it is not even any of secret key bytes.
I can encrypt any length of any known data and get encrypted result.
How can I get the key using this attack?
EncryptBlock probably does what it says is does: encrypt one block. The idea of the 15 byte first message is that you then concatenate the secret key block to it. I don't see where this happens (unless EncryptBlock is terribly badly named).
Currently the 16th byte that is encrypted is likely simply set to zero (using zero padding) by the EncryptBlock function. You may need to create a function that mimics what the server should do, including adding the server's secret to the initial message and possibly handle encrypting multiple blocks (assuming that the function doesn't already do this).
Note that this is not about retrieving the key from the block cipher, but retrieving a secret from the plaintext. This secret could have been added as some ill attempt to perform message authentication.

Encrypt and Decrypt a message using raw RSA algorithm in Crypto++?

I am using Crypto++ library for cryptography related works. And sub-part of task is to encrypt and decrypt a text. The message can be up to 256 character long containing alphanumeric number spaces dot and special characters.
This piece of code is working for text length is less than or equal to 8. But after that it fails to decrypt the encrypted text.
// g++ -std=c++1y crypto.cpp -I /home/shravan40/cryptopp/build -lcryptopp
#include <iostream>
#include <cryptopp/rsa.h>
#include <cryptopp/integer.h>
#include <cryptopp/osrng.h>
int main(){
// Keys
CryptoPP::Integer n("0xbeaadb3d839f3b5f"), e("0x11"), d("0x21a5ae37b9959db9");
CryptoPP::RSA::PrivateKey privKey;
privKey.Initialize(n, e, d);
CryptoPP::RSA::PublicKey pubKey;
pubKey.Initialize(n, e);
// Encryption
std::string message = "Shravan Kumar";
CryptoPP::Integer m((const byte *)message.data(), message.size());
std::cout << "m: " << m << std::endl;
// m: 126879297332596.
CryptoPP::Integer c = pubKey.ApplyFunction(m);
std::cout << "c: " << std::hex << c << std::endl;
// c: 3f47c32e8e17e291h
// Decryption
CryptoPP::AutoSeededRandomPool prng;
CryptoPP::Integer r = privKey.CalculateInverse(prng, c);
std::cout << "r: " << std::hex << r << std::endl;
// r: 736563726574h
std::string recovered;
recovered.resize(r.MinEncodedSize());
r.Encode((byte *)recovered.data(), recovered.size());
std::cout << "recovered: " << recovered << std::endl;
// recovered: Expected : (Shravan Kumar), Received -> y5��dqm0
return 0;
}
Richard Critten is correct in his comment that usually hybrid encryption is used (an asymmetric cipher such as RSA with a symmetric cipher such as AES).
For these kind of insecure examples though you are usually simply required to split up the plaintext into parts the same size as the modulus n. So in your case just put every 8 bytes / characters together and use it for a (big endian) number. As the input seems to be ASCII the highest bit of those 8 bytes will always be set to zero, so you should not have any problems encrypting/decrypting. The input for RSA must of course always be less than n.
You may of course have to think up a smart way of handling the last part of the string.
Notes:
In case it hasn't been told (yet): raw RSA without padding is not secure either. So it is not just the key size that would be a problem if this example would be implemented in the field.
I haven't got a clue what you're doing with regard to decryption. You should have a look at your textbook again I suppose.
Integer m((const byte *)message.data(), message.size());
If you use message.size()+1, then the message will include the trailing NULL. You can use it during decryption to determine where the recovered string ends. Otherwise, you are going to need to track length of the message.
You might also be interested in Raw RSA from the Crypto++ wiki. But as Maarten cautined, its tricky to get right and build into a scheme.
You might consider something using RSA encryption with OAEP or PKCS v1.5 padding. Also see RSA Encryption Schemes on the Crypto++ wiki.
I believe this is undefined behavior:
std::string recovered;
recovered.resize(r.MinEncodedSize());
r.Encode((byte *)recovered.data(), recovered.size());
I think you need to use &recovered[0] to get the non-const pointer. It may be causing your problem.

C++ AES How to encrypt data block by block

AES has maximum block size of 128, and key sizes like 128, 196 & 256.
I have implemented the aes algorithm like so:
int main()
{
unsigned char key[KEY_128] = "very strong key";
unsigned char plaintext[16] = "this is a test";
unsigned char ciphertext[16];
unsigned char decptext[16];
aes_ctx_t *ctx;
virtualAES::Initialize();
ctx = virtualAES::AllocateCTX(key, sizeof(key));
virtualAES::Encrypt(ctx, plaintext, ciphertext);
cout << "encrypted: " << ciphertext << endl;
virtualAES::Encrypt(ctx, ciphertext, decptext);
cout << "decrypted: " << decptext << endl;
return 0;
}
but I want to encrypt larger data than 128bits, for example string that's 512 bits long. I need somekind of a loop that splits the strings into 128bit blocks and then encrypts & joins them again, but I have hard time doing this. Could someone provide an example?
I am more familiar with C#, which has several modes of encryption exposed through the System.Security.Cryptography namespace. However I know how Cipher Block Chaining works. I'll explain it to you, but keep in mind it is really easy to mess up crypto, so this is informational only, and I hope you will find a library that does what you need done.
With cipher block chaining (CBC) here is what you do. Take your data and break it into block sizes. 128 bits is 16 bytes, so there you go. If you have less than 16 bytes in your last block, you must pad. The commonest way I know of is PKCS7 padding, which means for example if you need 3 bytes of padding at the end of your last block, you would add 0x03, 0x03, 0x03 to make it a full block.
So now you are ready to encrypt. You should have an initialization vector (IV) to start off with. Bitwise XOR that IV with your first block of plain text. Then encrypt the result the way you normally would encrypt a single block of data (ECB mode). The result is your first block of cipher text. But it is also equivalent to the IV for the next block you want to encrypt. Bitwise XOR it with the second block and encrypt. Take that encrypted block, record it, and also use it to XOR with the third block. And so on.
This process makes it so that the exact same text appearing, let's say 5 times in a document will look totally different each time it appears. So it adds more security. Despite this, the IV does not need to be kept secret at all. Passwords and salts do, IVs do not.

OpenSSL decrypted text length

I am using this simple function for decrypting a AES Encrypted string
unsigned char *aes_decrypt(EVP_CIPHER_CTX *e, unsigned char *ciphertext, int *len)
{
int p_len = *len, f_len = 0;
unsigned char *plaintext = (unsigned char*)malloc(p_len + 128);
memset(plaintext,0,p_len);
EVP_DecryptInit_ex(e, NULL, NULL, NULL, NULL);
EVP_DecryptUpdate(e, plaintext, &p_len, ciphertext, *len);
EVP_DecryptFinal_ex(e, plaintext+p_len, &f_len);
*len = p_len + f_len;
return plaintext;
}
The problem is that len is returning a value that does not match the entire decoded string. What could be the problem ?
When you say "string", I assume you mean a zero-terminated textual string. The encryption process is dependent on a cipher block size, and oftentimes padding. What's actually being encoded and decoded is up to the application... it's all binary data to the cipher. If you're textual string is smaller than what's returned from the decrypt process, your application needs to determine the useful part. So for example if you KNOW your string inside the results is zero-terminated, you can get the length doing a simple strlen. That's risky of course if you can't guarantee the input... probably better off searching the results for a null up to the decoded length...
If you are using cipher in ECB, CBC or some other chaining modes, you must pad plain text to the length, which is multiple of cipher block length. You can see a PKCS#5 standard for example. High-level functions like in OpenSSL can perform padding transparently for programmer. So, encrypted text can be larger than plain text up to additional cipher block size.

Endian-ness in a char array containing binary characters

I'm building some code to read a RIFF wav file and I've bumped into something odd.
The first 4 bytes of the file header are the word RIFF in big-endian ascii coding:
0x5249 0x4646
I read this first element using:
char *fileID = new char[4];
filestream.read(fileID,4);
When I write this to screen the results are as expected:
std::cout << fileID << std::endl;
>> RIFF
Now, the next 4 bytes give the size of the file, but crucially they're little-endian.
So, I write a little function to flip the bytes, based on a union:
int flip4bytes(char* input){
union flip {int flip_int; char flip_char[4];};
flip.flip_char[0] = input[3];
flip.flip_char[1] = input[2];
flip.flip_char[2] = input[1];
flip.flip_char[3] = input[0];
return flip.flip_int;
}
This looks good to me, except when I call it, the value returned is totally wrong. Interestingly, the following code (where the bytes are not reversed!) works correctly:
int flip4bytes(char* input){
union flip {int flip_int; char flip_char[4];};
flip.flip_char[0] = input[0];
flip.flip_char[1] = input[1];
flip.flip_char[2] = input[2];
flip.flip_char[3] = input[3];
return flip.flip_int;
}
This has thoroughly confused me. Is the union somehow reversing the bytes for me?! If not, how are the bytes being converted to int correctly without being reversed?
I think there's some facet of endian-ness here that I'm ignorant to..
You are simply on a little-endian machine, and the "RIFF" string is just a string and thus neither little- nor big-endian, but just a sequence of chars. You don't need to reverse the bytes on a little-endian machine, but you need to when operating on a big-endian.
You need to figure of the endianess of your machine. #include <sys/param.h> will help you do that.
You could also use the fact that network byte order is big ended (if my memory serves me correctly - you need to check). In which case convert to big ended and use the ntohs function. That should work on any machine that you compile the code on.