Same short encryption result using AES with different keys - c

I have a single plain text which is
unsigned char plaintext[] = "Hi, this is trial number one";
For the keys, instead of using something like:
unsigned char key[16] = "azertyuiopqsdfg";
I decided to use tons of them like "dog", "azkier", "jfieifdragon", ...
My code so far looks like this:
unsigned char *aes_encrypt(unsigned char *plaintext, unsigned char *key)
{
EVP_CIPHER_CTX *ctx;
ctx = EVP_CIPHER_CTX_new();
unsigned char iv[16] = "0000000000000000";
int c_len = strlen(plaintext) + AES_BLOCK_SIZE;
int f_len = 0;
unsigned char *ciphertext = malloc(c_len);
EVP_EncryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv);
EVP_EncryptUpdate(ctx, ciphertext, &c_len, plaintext, strlen(plaintext));
EVP_EncryptFinal_ex(ctx, ciphertext+c_len, &f_len);
EVP_CIPHER_CTX_free(ctx);
return ciphertext;
}
When I compile and run, the output looks something like this:
the key: dog
the plain: Hi, this is trial number one
ciphertext: 157a320
the key: azkier
the plain: Hi, this is trial number one
ciphertext: 157a320
.....
My questions are:
why I always get the same ciphertext even though I'm using different keys?
Also, why the ciphertext is really short? My plaintext is pretty long tho.
Thanks.
Update --> The way I call the aes_encrypt is like this:
unsigned char plaintext[] = "Hi, this is trial number one";
unsigned char *cipher;
cipher = aes_encrypt(plaintext, "dog");
printf("The cipher is: %x\n", cipher);
free(cipher);
unsigned char *cipher;
cipher = aes_encrypt(plaintext, "azkier");
printf("The cipher is: %x\n", cipher);
free(cipher);

In your test code:
printf("The cipher is: %x\n", cipher);
Well, of course that doesn't work -- %x prints the address of cipher as hexadecimal, not its contents. If you want a dump of the contents of cipher, you'll need to loop over each byte yourself.
Additionally, the key parameter to EVP_EncryptInit_ex is a fixed-length buffer, whose size is set based on the cipher you're using. It is not a string. Passing a short string may cause unpredictable behavior, as whatever data happens to be stored after the string ends may be used as part of the key.

Related

AES_128_CBC Encryption/Decryption using OpenSSL

I am currently trying to develop a C program to implement AES_128_CBC using the OpenSSL library. When I compile and run the program the first time, I get blocks of ciphertext and then my plaintext shows as being decrypted. This seems to be running smoothly. My problem is when I compile and run again. My blocks of ciphertext grow (by about 3x in size), yet my decryption remains the same. I would expect that if I was using the same key and IV, my cipher text would remain the same no matter how many times I compile and run the program. Can anyone see why this may be happening?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/aes.h>
#define BUFSIZE 1024
/* AES key for Encryption and Decryption */
const static unsigned char aes_key[]= {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF};
unsigned char iv[] = {0x98,0x76,0x54,0x32,0x10,0xFE,0xDC,0xBA,0x98,0x76,0x54,0x32,0x10,0xFE,0xDC,0xBA};
/* Print Encrypted and Decrypted data packets */
void print_data(const char *tittle, const void* data, int len);
int main( )
{
/* Input data to encrypt */
unsigned char aes_input[BUFSIZE];
strcpy(aes_input, "Testing");
fprintf(stderr, "%s\n", aes_input);
/* Init vector */
memset(iv, 0x00, AES_BLOCK_SIZE);
/* Buffers for Encryption and Decryption */
unsigned char enc_out[sizeof(aes_input)];
unsigned char dec_out[sizeof(aes_input)];
unsigned char *e = enc_out;
/* AES-128 bit CBC Encryption */
AES_KEY enc_key, dec_key;
AES_set_encrypt_key(aes_key, sizeof(aes_key)*8, &enc_key);
AES_cbc_encrypt(aes_input, enc_out, sizeof(aes_input), &enc_key, iv, AES_ENCRYPT);
fprintf(stderr, "Encrypted:");
while (*e) printf(" [%02x]", *e++);
printf("\n");
/* AES-128 bit CBC Decryption */
memset(iv, 0x00, AES_BLOCK_SIZE); // don't forget to set iv vector again, else you can't decrypt data properly
AES_set_decrypt_key(aes_key, sizeof(aes_key)*8, &dec_key); // Size of key is in bits
AES_cbc_encrypt(enc_out, dec_out, sizeof(aes_input), &dec_key, iv, AES_DECRYPT);
fprintf(stderr, "The Plaintext After Decryption is: %s\n", dec_out);
return 0;
}
You have overlooked a few things in your code.
First, you have declared your aes_input array without initializing it:
/* Input data to encrypt */
unsigned char aes_input[BUFSIZE];
Since you have not initialized this array, it may hold any value after this. Different compilers will do different things here. One way to initialize the entire array to a predictable value is by filling it with zeroes, like this:
unsigned char aes_input[BUFSIZE] = {0};
After this, the output should be predictable, no matter how many times you run it.
The contents of this entire array are relevant, because you are asking OpenSSL to encrypt the entire array, since you pass sizeof(aes_input) as the size of the plaintext to be encrypted when invoking the AES_cbc_encrypt() function:
AES_cbc_encrypt(aes_input, enc_out, sizeof(aes_input), &enc_key, iv, AES_ENCRYPT);
Since your input is largely uninitialized (except for the first eight bytes, which contain the string "Testing"), the output of this function can not be predicted.
Now when you print that output as follows:
while (*e) printf(" [%02x]", *e++);
you will only see the bytes up to the first byte that has the value of 0. This is a mistake, because the cipher text could easily (and does) contain bytes with the value of 0. You are treating the ciphertext as if it is a zero-terminated string, which it is not. Instead of stopping when encountering a 0 value, you should loop over all bytes in the ciphertext.

AES encryption using openssl

I'm trying to encrypt using openssl AES encryption function.
here's my code:
#include <stdio.h>
#include <openssl/aes.h>
#include <string.h>
const static unsigned char aes_key[]={"passwordpasswor"}; //15 characters + \0
void print_data(const char *tittle, const void* data, int len);
int main() {
unsigned char aes_input[]="#!/bin/bash\necho hello world";
unsigned char iv[AES_BLOCK_SIZE];
memset (iv,0x00,AES_BLOCK_SIZE);
unsigned char enc_out[sizeof(aes_input)];
unsigned char dec_out[sizeof(aes_input)];
AES_KEY enc_key,dec_key;
AES_set_encrypt_key(aes_key,sizeof(aes_key)*8,&enc_key);
AES_cbc_encrypt(aes_input,enc_out,sizeof(aes_input),&enc_key,iv,AES_ENCRYPT);
//decryption
memset(iv,0x00,AES_BLOCK_SIZE);
AES_set_decrypt_key(aes_key,sizeof(aes_key)*8,&dec_key);
AES_cbc_encrypt(enc_out,dec_out,sizeof(aes_input),&dec_key,iv,AES_DECRYPT);
//verify
printf("original %s\n",aes_input);
printf("encrypted %s\n",enc_out);
printf("decrypted %s\n",dec_out);
return 0;
}
the code produces the following output (with an extra newline between each for clarity):
original #!/bin/bash
echo hello world
encrypted ���jv�.)��$I���b�:dmPvTQޜ�#!/bin/bash
echo hello world
decrypted #!/bin/bash
echo hello world
I've tried other messages, it seems that the encryption message will show the original message if used with printf.
You're trying to dump non-printable data to a terminal device, and specifically doing so using a library call that expects null-termination. The output of an AES encryption can contain bytes of any value (including embedded nullchar values)
You need the following:
Properly size your output buffer size. By default AES_cbc_encrypt uses pkcs padding and will use up to one full additional block for padding data.
Dump your output using an alternative mechanism, such as a trivial hexdump routine.
Both of the above are done below:
#include <stdio.h>
#include <openssl/aes.h>
#include <string.h>
static hex_print(const void *pv, size_t len)
{
static const char alpha[] = "0123456789abcdef";
const unsigned char *beg = pv, *end = beg+len;
for (; beg != end; ++beg)
{
putc(alpha[(*beg >> 4) & 0xF], stdout);
putc(alpha[*beg & 0xF], stdout);
}
putc('\n', stdout);
}
const static unsigned char aes_key[]={"passwordpasswor"}; //15 characters + \0
void print_data(const char *tittle, const void* data, int len);
int main() {
unsigned char aes_input[]="#!/bin/bash\necho hello world";
unsigned char enc_out[AES_BLOCK_SIZE * ((sizeof(aes_input) + AES_BLOCK_SIZE)/AES_BLOCK_SIZE)];
unsigned char dec_out[sizeof(aes_input)];
unsigned char iv[AES_BLOCK_SIZE] = {0};
AES_KEY enc_key,dec_key;
AES_set_encrypt_key(aes_key,sizeof(aes_key)*8,&enc_key);
AES_cbc_encrypt(aes_input,enc_out,sizeof(aes_input),&enc_key,iv,AES_ENCRYPT);
//decryption
memset(iv,0x00,AES_BLOCK_SIZE);
AES_set_decrypt_key(aes_key,sizeof(aes_key)*8,&dec_key);
AES_cbc_encrypt(enc_out,dec_out,sizeof(aes_input),&dec_key,iv,AES_DECRYPT);
//verify
printf("original %s\n",aes_input);
hex_print(enc_out, sizeof enc_out);
printf("decrypted %s\n",dec_out);
return 0;
}
Output
original #!/bin/bash
echo hello world
e389c96a76d708b42e29b4b4052449f1ffc762db3a646d1650765451de9c1dd0
decrypted #!/bin/bash
echo hello world
Note in particular the last byte of the encryption. It isn't 00, which means the printf call you were incorrectly using was marching beyond that buffer and into the land of undefined behavior. In fact, there are no nullchar bytes in that string (it is a different, yet closely-related problem when there is an embedded 00 in the middle of your data, in which case printf would have stopped prematurely.
In this case, I can speculate (with little value; such is the nature of undefined behavior) that the march took printf into the next automatic variable on the stack, which was the decrypted array.
Modifying the output sequence to use all hex output will demonstrate the difference between plaintext and encrypted data. For example, changing the last three functional lines of your program to:
//verify
hex_print(aes_input, sizeof(aes_input));
hex_print(enc_out, sizeof enc_out);
hex_print(dec_out, sizeof(dec_out));
will deliver the following output:
23212f62696e2f626173680a6563686f2068656c6c6f20776f726c6400
e389c96a76d708b42e29b4b4052449f1ffc762db3a646d1650765451de9c1dd0
23212f62696e2f626173680a6563686f2068656c6c6f20776f726c6400
which makes sense. if you walk the bytes (two digits per) in the original and decrypted strings you can see they're (a) equal, (b) not equal to the cipher text, and (c), a little time in an ascii table will show you they are indeed the original text message.
Best of luck.
You have encrypted the terminating nul of the string by using the argument
sizeof(aes_input)
You are consistent, so it gets decrypted too. Unfortunately the encrypted string no longer has a nul terminator, since it was encrypted too. So I recommend
strlen(aes_input)
for the arguments (but not for the string allocation). You must also terminate the two strings enc_out[] and dec_out[].

Encrypted string is not the same as test vector

So I am trying to encrypt some data with the EVP-API from OpenSSL. But I am not recieving the same result as the test vectors.
This is the main function
#include <stdio.h>
#include <windows.h>
#include <openssl\aes.h>
#include <openssl\evp.h>
int main()
{
unsigned char *to = (unsigned char*)malloc(2056);
ZeroMemory(to,2056);
int *tosize;
unsigned char* key = (unsigned char*)"0000000000000000000000000000000000000000000000000000000000000000";
unsigned char* iv = (unsigned char*)"00000000000000000000000000000000";
unsigned char* plain = (unsigned char*)"00000000000000000000000000000000";
to = AESEncrypt(key,iv,plain,strlen((const char*)plain));
if (to != 0)
{
for (int i = 0; i < strlen((const char*)to);i++)
{
printf("%x02", (int*)UCHAR(to[i]));
}
}
}
And this is the function which I am trying to call. No errors recieved. Every call is true (no error).
unsigned char* AESEncrypt(unsigned char* key, unsigned char*iv, unsigned char*plain, size_t plainsize)
{
EVP_CIPHER_CTX *x = (EVP_CIPHER_CTX*) malloc(sizeof(EVP_CIPHER_CTX));
EVP_CIPHER_CTX_init(x);
if (EVP_EncryptInit(x,EVP_aes_256_cbc(),key,iv))
{
unsigned char* to = (unsigned char*) malloc(plainsize + EVP_CIPHER_CTX_block_size(x));
int tosize = 0;
if(EVP_EncryptUpdate(x,to,&tosize,plain,plainsize))
{
if (EVP_EncryptFinal(x,to,&tosize))
{
return to;
}
}
}
return 0;
}
This is the test vector:
KEY = 0000000000000000000000000000000000000000000000000000000000000000
IV = 00000000000000000000000000000000
PLAINTEXT = 80000000000000000000000000000000
CIPHERTEXT = ddc6bf790c15760d8d9aeb6f9a75fd4e
This is what I am recieving:
CIPHERTEXT = 5a0215028e.... and it goes on. As you see it is not correct.
What could I be doing wrong?
CAVS test vectors follow a fairly straight-forward pattern. From test to test they vary to certain degrees, but one thing is eminently consistent:
Hex Strings are BYTE representations; NOT character data
Hence your "test" is entirely wrong. You're using a key, iv, and plain text that is filled with the character '0', not the byte value 0. So obviously no wonder you're getting a different result.
For that specific test your arrays should be:
unsigned char key[64] = {0};
unsigned char iv[16] = {0};
unsigned char plain[16] = {0};
Furthermore, your size sent to your encryption function should be the byte count of your plain text. Finally, your encryption function should ideally take a target buffer AND a modifiable size as the output parameters.
int AESEncrypt256(
unsigned char* key, // key must be 64 bytes wide.
unsigned char *iv, // IV must be 16 bytes wide.
unsigned char *src, // source buffer to encryt
unsigned int src_len, // length of source buffer in bytes
unsigned char *dst, // target buffer to write to
unsigned int *dst_len); // in: size of dst, out: bytes written to dst
And code the function to match those parameters. You'll be glad you did.
CAVS tests vectors are not "text". They are bytes and should be treated as such. You need to get a handle on that now, as the Monte Carlo tests are likely going to cost you some hair if you don't.
Do yourself an enormous favor and write some code now that translates a string of hex digits into an unsigned char byte array. You'll need the same to translate back for result strings. And make these routines solid as you will be using them a lot when writing these tests.
Spoiler Alert
Test the string for an odd number of chars first. If it is odd, the first byte in your translated buffer should be based on 0c, where c is the first char in the input string. From then on (or if the number of chars is even, then from the very start) grab them two-at-a-time when converting the rest of the byte string into real bytes. This means this
123456
results in a byte array of
{ 0x12, 0x34, 0x56 }
while this:
89AB1
should be:
{0x08, 0x9A, 0xB1 }

Make a long string of encrypted substrings in c

I'm trying to create a long string that is produced out of encrypted substrings. For the encryption I'm using AES128 and libmcrypt. The code is working, but I get a shorter output then I should and a beeping sound. I guess it's because I'm using strlen, but I have no idea, how I can avoid that. I will be very grateful for some suggestions. Here is my code:
char *Encrypt( char *key, char *message){
static char *Res;
MCRYPT mfd;
char *IV;
int i, blocks, key_size = 16, block_size = 16;
blocks = (int) (strlen(message) / block_size) + 1;
Res = calloc(1, (blocks * block_size));
mfd = mcrypt_module_open(MCRYPT_RIJNDAEL_128, NULL, "ecb", NULL);
mcrypt_generic_init(mfd, key, key_size, IV);
strncpy(Res, message, strlen(message));
mcrypt_generic(mfd, Res, block_size);
//printf("the encrypted %s\n", Res);
mcrypt_generic_deinit(mfd);
mcrypt_module_close(mfd);
return (Res);
}
char *mkline ( int cols) {
int j;
char seed[] = "thesecretmessage", key1[]="dontusethisinput", key2[]="abadinputforthis";
char *encrypted, *encrypted2, *in = malloc(cols * 16);
encrypted = Encrypt(key1, seed);
sprintf(in, "%s", encrypted);
encrypted2= Encrypt(key2, encrypted);
printf("encrypted2 before for-loop %s\n", encrypted2);
printf("encrypted2 before for loop len %d\n", strlen(encrypted2));
for (j=1; j<cols; j++) {
strcat(in, encrypted2);
memmove(encrypted2, Encrypt(key2, encrypted2),strlen(seed));
printf("encrypted2 %s on position %d\n" , encrypted2,j);
printf("encrypted2 len %d\n", strlen(encrypted2));
}
free(encrypted);
free(encrypted2);
return in;
}
int main(int argc, char *argv[]) {
char *line = mkline(15);
printf("line %s\n", line);
printf("line lenght %d\n", strlen(line));
return 0;
}
You get the beep sound because you are printing control character.
Also strlen return the size until the first '\0' character (because strings are zero terminated). That's why you get length less than you expect since the encrypted message may contain zeroes.
You can do something like this to return the result length:
char *Encrypt(const char *key, const char *message, int *result_len)
{
*result_len = blocks * block_size;
}
Also
memmove(encrypted2, Encrypt(key2, encrypted2),strlen(seed));
This line should produce a memory leak since every time you call Encrypt you call calloc (allocate new memory) which you need to free after you are done.
You probably should use memcpy, memmove is primarly used if there is a chance destination and source may overlap.
The encrypted string you are trying to print contains a stream of bytes where the value of the individual byte ranges from 0 to 255. Because you are using a cryptographically secure algorithm, the distribution of values is very close to even.
Since you are trying to print the encrypted string through a console, the console interprets some of the bytes as control characters (see Bell character) that are unprintable but have other effects instead, such as playing beeps.
Furthermore, strlen isn't doing what you think it should be doing because the encrypted string is not null-terminated, but instead contains zeroes amongst other bytes and they have no special meaning unlike in NULL terminated strings. You need to store the length of the string elsewhere.
Simple, you are treating binary output (any byte value) directly as printable text. Any character wit a code point below 32 (hex 20) isn't. E.g. the ASCII value for BELL (look it up) could be meaningful to you. Print the resulting bytes in hexadecimals and you should be ok.
I should like to add that in general it is good practice to clear any memory that held the plaintext/unencrypted message after you encrypt it if you can. This is not good coding practice, but good cryptology practice.
This can be done by:
memset(buffer, 0, length_of_buffer);
Don't worry, that won't be optimized out by your compiler. It's actually not smart enough to tell if you'll be using that area again or not.

Unsigned char to char* and int in C?

Working on some encryption that requires unsigned char's in the functions, but want to convert to a char for use after it's been decrypted. So, I have:
unsigned char plaintext[16];
char *plainchar;
int plainint;
... Code now populates plaintext with data that happens to all be plain text
Now at this point, let's say plaintext is actually a data string of "0123456789". How can I get the value of plaintext into plainchar as "012456789", and at the same time plainint as 123456789?
-- Edit --
Doing this when plaintext is equal to "AAAAAAAAAA105450":
unsigned char plaintext[16];
char *plainchar;
int plainint;
... Code now populates plaintext with data that happens to all be plain text
plainchar = (char*)plaintext;
Makes plainchar equal to "AAAAAAAAAA105450╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠┤∙7" with a sizeof = 51. The encryption code is the rijndael example code, so it should be working fine.
Thanks,
Ben
Your plain text string is not terminated. All strings must have an extra character that tells the end of the string. This character is '\0'.
Declare the plaintext variable as
unsigned char plaintext[17];
and after you are done with the decryption add this
plaintext[last_pos] = '\0';
Change last_pos to the last position of the decrypted text, default to 16 (last index of the array).
I think its simply
plainchar = (char*)plaintext;
sscanf( plainchar, "%d", &plainint );
for unsigned char to char*
plainchar = (char*)plaintext;
for unsigned to int
sscanf( plainchar, "%d", &plainint );

Resources