AES ECB known-text attack - c++

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.

Related

Reading an array of bytes into UTF-16 characters on a machine with a specific UTF-16 character size

I have a question about utf16_t character interaction and SHA-256 generation with OpenSSL.
The thing is, I'm currently writing code that should deal with password hashing. I've generated a 256-bit hash, and I want to throw it into the database in a UTF-16 encoded character field. In my C++ code, I use char16_t to store such data. However, there is a problem. utf16_t can have more than 16 bytes, depending on the machine it ends up on. And if I use memcpy() to copy bytes from my SHA-256 hash, it may turn out to be a mess on some machines.
What should I do in this situation? Read bytes differently, store hashes in the database differently, maybe something else?
SHA256 generates 256 essentially random bits (32 bytes) of data. It will not always generate valid UTF-16 data.
You need to somehow encode the 32 bytes into more-than-32 utf-16 bytes to store in your database. Or you can convert the database field to a proper 256-bit binary type
One of the easier-to-implement ways to store it in your DB as a string would be to map each byte to a character 1-to-1 (and store 32 bytes of data with 32 bytes of zeroes in between):
unsigned char sha256_hash[256/8];
get_hash(sha256_hash);
// encoding
char16_t db_data[256/8];
for (int i = 0; i < std::size(db_data); ++i) {
db_data[i] = char16_t(sha256_hash[i]);
}
write_to_db(db_data);
char16_t db_data[256/8];
read_from_db(db_data);
// decoding
unsigned char sha256_hash[256/8];
for (int i = 0; i < std::size(sha256_hash); ++i) {
assert((std::uint16_t) db_data[i] <= 0xFF);
sha256_hash[i] = (unsigned char) db_data[i];
}
Be careful if you are using null-terminated strings though. You will need an extra character for the null terminator and map the 0 byte to something else (0x100 would be a good choice).
But if you have additional requirements (like it being readable characters), you might consider base64 or a hexadecimal encoding

OpenSSL in C: after second decryption in application run, the first 16 bytes of result are garbage

I implemented simple file encryption/decryption with OpenSSL in C according to the instructions here. I do not need this to be truly secure (just want the files to not be readily readable on drive), the keys are hardcoded in the application and after reading the encrypted files from drive I decrypt them.
On first call, the decryptFileAsBytes function returns the correct decrypted file as byte vector. On the second call (within the same application run) the first 16 bytes of the result are garbage and the rest is correct. Does this have something to do with the size of the key (128 bits) I am using?
static bool decryptFileAsBytes(std::string filename, unsigned char *ckey, unsigned char *ivec, std::vector<unsigned char> &fileBytes)
{
std::ifstream ifs(filename, std::ios::binary | std::ios::ate);
if (ifs.fail())
return false;
std::ifstream::pos_type pos = ifs.tellg();
fileBytes.resize(pos);
ifs.close();
FILE *ifp;
if (fopen_s(&ifp, filename.c_str(), "rb") != NULL)
return false;
int bytesRead;
unsigned char indata[AES_BLOCK_SIZE];
unsigned char *writePtr = fileBytes.data();
/* data structure that contains the key itself */
AES_KEY key;
/* set the encryption key */
AES_set_encrypt_key(ckey, 128, &key);
/* set where on the 128 bit encrypted block to begin encryption*/
int num = 0;
while (1)
{
bytesRead = fread(indata, 1, AES_BLOCK_SIZE, ifp);
AES_cfb128_encrypt(indata, writePtr, bytesRead, &key, ivec, &num, AES_DECRYPT);
writePtr += bytesRead;
if (bytesRead < AES_BLOCK_SIZE)
break;
}
if (fclose(ifp) != NULL)
return false;
return true;
}
Alternatively to solving this, I welcome suggestions of a simple solution to the problem stated above ('encrypt' file on drive in a not bulletproof way so that it is not readily readable but the application can decrypt it).
The problem is likely that you're not retaining the original initialization vector for subsequent decryption operations.
As the AES encryption/decryption operations transpire, that memory is updated to continue with subsequent frames. If you instrument your code you'll see, with each encrypt/decrypt frame passing through the API, the ivec is changed.
If all you're doing this for is obfuscation (eg. you have a static key in your application) my suggestion is to do the following:
Don't pass the ivec into either the encryptor or decryptor.
Instead, generate a random ivec using RAND_bytes when encrypting. Store the ivec as the first block of data before continuing with the file content.
When decrypting, read the first block of data to prime your ivec.
Then, decrypt the remainder of the file as normal.
The benefits are:
Each encryption of a file will create a different byte representation, dependent on the initial random ivec. Eg. if you encrypt a file twice the resulting encrypted bytes will not be the same
You no longer have to use a static ivec from somewhere else in your code. The file contains it as the first block of data.
Just a suggestion. Unrelated, I prefer the EVP encryption interface, and suggest it worth a look.

C++ AES encrypt bigger string than 128bits

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.

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.