Implementing AES-128 CBC by passing array as input data - c

I am working on AES-128/192/256, basically I am getting data from a broker as string, I just need to encrypt that data and I need to verify that.
I already come across these https://github.com/empyreanx/tiny-AES128-C, https://github.com/kokke/tiny-AES-c links.
My code is:
static void test_encrypt_cbc(void)
{
unsigned char input[] =
"So_letmeknowRuinterested/towork#thiscompany.comElsewilllookother";
//64bits
unsigned char cipher[sizeof input];
printf("size of in:%lu\n",strlen(input));
unsigned char key[] = "Gns7AauH3dnaod=="; //16 bits
unsigned char iv[] = "vhdNaleuTHenaOlL"; //16 bits
AES128_CBC_encrypt_buffer(cipher, input, 64, key, iv);
if(0 == memcmp((char*) cipher, (char*) input, 64))
{
printf("SUCCESS!\n");
}
else
{
printf("FAILURE!\n");
}
}
I also printed cipher text after encryption it is printing some undefined character.
I don't know but I am comparing "cipher" with "input", Its FAILURE finally!
Please anyone can tell me where I am doing wrong.
Thanks in advance.

This is logical to cipher to be different from input, isn't?
To check that encryption worked, you should decrypt the encoded message and check that they are equal:
static void test_encrypt_cbc(void)
{
/* 64 bytes, or 512 bits */
unsigned char input[] =
"So_letmeknowRuinterested/towork#thiscompany.comElsewilllookother";
unsigned char cipher[sizeof input];
unsigned char output[sizeof input];
printf("size of in:%lu\n",strlen(input));
/* 16 bytes or 128 bits */
unsigned char key[] = "Gns7AauH3dnaod==";
unsigned char iv[] = "vhdNaleuTHenaOlL";
/* input --> cipher */
AES128_CBC_encrypt_buffer(cipher, input, 64, key, iv);
/* cipher --> output */
AES128_CBC_decrypt_buffer(output, cipher, 64, key, iv);
if(0 == memcmp((char*) output, (char*) input, 64))
{
printf("SUCCESS!\n");
}
else
{
int i;
printf("FAILURE!\nInput and output are different:\n");
for (i = 0; i < sizeof input; ++i)
{
printf("%02x - %02x\n", input[i], output[i]);
}
}
}

Related

Openssl brute force AES_128 decryption error in C

I'm trying to write a C program to brute force AES decryption using openssl. However, when I tried to decrypt the message by passing a key attackKey, I got and error printed from the decrypt() function. The error is as follows
There was an error calling the decrypted final object...: Success
The code is given below, I tried reading the book on Openssl for more information but as it is quite outdated it was not helpful. I also googled and barely found any resources on my issue and yes I am well aware of the fact that brute forcing aes_128 is a pipe dream. I am just testing some things with this library to see if the key is only a few combinations ahead, so can I iterate on the attackKey and try to get the decrypted text.
#include <string.h>
#include <openssl/evp.h>
#include <openssl/aes.h>
#include <stdbool.h>
#include <openssl/err.h>
#define BUFFER_SIZE 64
// void addPadding(unsigned char *buff, );
int encrypt(const unsigned char *plaintext, const int plaintext_len, const unsigned char *key, unsigned char *ciphertext);
int decrypt(const unsigned char *ciphertext, const int ciphertext_len, const unsigned char *key, unsigned char *decryptedtext);
void iterateKey(unsigned char *key, const int length);
bool compareKeys(const unsigned char *key1, const unsigned char *key2, const int length);
void *bruteForceAttack(void *arg);
int main(int argc, char *argv[])
{
OpenSSL_add_all_algorithms(); // load all cipher algorithms
ERR_load_crypto_strings(); // load human readable errors
/* A 256 bit key */
unsigned char key[] = "abcdefghijklmnqp"; // 6 + 1 bytes
unsigned char plaintext[] = "Hello, my name is shaheryar ;)."; // 32 + 1 bytes
/* Buffer to store the ciphertext. The size may be different due to padding. */
unsigned char ciphertext[BUFFER_SIZE];
int ciphertext_len = 0;
/* Encryption. */
ciphertext_len = encrypt(plaintext, strlen((char *)plaintext), key, ciphertext);
printf("Length of text:%d, Ciphertext is:\n", ciphertext_len);
BIO_dump_fp(stdout, (const char *)ciphertext, ciphertext_len);
//----------------MAIN DECRYPTION LOGIC
/* Buffer for the decrypted text for verifying decryption. */
unsigned char decryptedtext[BUFFER_SIZE];
int decryptedtext_len = 0;
unsigned char attackKey[] = "abcdefghijklmnop";
const int attackKey_len = 17;
for (int i = 0; i < 10e2; i++)
{
// printf("Key : %s\n", attackKey);
decryptedtext_len = 0;
decryptedtext_len = decrypt(ciphertext, ciphertext_len, attackKey, decryptedtext);
decryptedtext[decryptedtext_len] = '\0';
if (strcmp((const char *)attackKey, (const char *)key) == 0)
{
printf("\nLength of text: %d, Decryptedtext is: %s\n", decryptedtext_len, decryptedtext);
}
iterateKey(attackKey, attackKey_len);
}
//------------END OF DECRYPTION PHASE
if (strncmp((const char *)plaintext, (const char *)decryptedtext, decryptedtext_len))
{
printf("FAIL: enc/dec failed for \"%s\"\n", decryptedtext);
}
else
{
printf("OK: enc/dec ok for \"%s\"\n", plaintext);
}
return 0;
}
int encrypt(const unsigned char *plaintext, const int plaintext_len, const unsigned char *key, unsigned char *ciphertext)
{
/* The following object is used to keep track of the key and internal states*/
EVP_CIPHER_CTX *ctx = NULL;
int len = 0, ciphertext_len = 0;
/* Create and initialize the context and returns a pointer for success and null for failure*/
if (!(ctx = EVP_CIPHER_CTX_new()))
{
printf("There was an error creating the encryption object...");
}
/* Initialize the encryption operation. */
if (!EVP_EncryptInit_ex(ctx, EVP_aes_128_ecb(), NULL, key, NULL))
{
printf("There was an error loading the encryption object...");
}
if (plaintext)
{
if (!EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len))
{
printf("There was an error creating the update the encryption object...");
}
ciphertext_len = len;
}
if (!EVP_EncryptFinal_ex(ctx, ciphertext + len, &len))
{
printf("There was an error encrypting the final object...");
}
ciphertext_len += len;
/* Clean up */
EVP_CIPHER_CTX_free(ctx);
return ciphertext_len;
}
int decrypt(const unsigned char *ciphertext, const int ciphertext_len, const unsigned char *key, unsigned char *decryptedtext)
{
/* The following object is used to keep track of the key and internal states*/
EVP_CIPHER_CTX *ctx = NULL;
int len = 0, decryptedtext_len = 0;
/* Create and initialize the context and returns a pointer for success and null for failure*/
if (!(ctx = EVP_CIPHER_CTX_new()))
{
printf("There was an error creating the decryption object...");
}
/* Initialize the encryption operation. */
if (!EVP_DecryptInit_ex(ctx, EVP_aes_128_ecb(), NULL, key, NULL))
{
printf("There was an error initializing the cipher object...");
}
if (ciphertext)
{
if (!EVP_DecryptUpdate(ctx, decryptedtext, &len, ciphertext, ciphertext_len))
{
printf("There was an error decrypting the cipher text...");
}
decryptedtext_len = len;
}
if (!EVP_DecryptFinal_ex(ctx, decryptedtext + len, &len))
{
printf("There was an error calling the decrypted final object...");
}
decryptedtext_len += len;
/* Clean up */
EVP_CIPHER_CTX_free(ctx);
return decryptedtext_len;
}
bool compareKeys(const unsigned char *key1, const unsigned char *key2, const int length)
{
for (int i = 0; i < length; i++)
{
if (key1[i] != key2[i])
{
return false;
}
}
return true;
}
void iterateKey(unsigned char *key, const int length)
{
for (int i = 0; i < (length - 1); i++)
{
if (key[length - 2 - i] == 'z')
{
key[length - 2 - i] = 'a';
}
else
{
key[length - 2 - i]++;
return;
}
}
}
void *bruteForceAttack(void *arg)
{
return NULL;
}
Below are the resources I used for implementing the code:
https://www.cs.ucy.ac.cy/courses/EPL326/labs/lab3/aesimplentation.pdf
https://www.oreilly.com/library/view/network-security-with/059600270X/

How to use tiny-aes 128 library in c?

I would like to encrypt using tiny AES library (https://github.com/kokke/tiny-AES-c) in C for AES128.
My code is as below:
unsigned char cipher[64];
unsigned char in[] = "THJmaoeuf2jsn4jebc7ak3mUdnyHeklOYopdna/OOndu3bis/E7jTd/enasduR3h"; //64 bits
printf("Size of AES input msg: %d \n", sizeof(in));
unsigned char key[] = "Gns7AauH3dnaod=="; //16 bits
unsigned char IV[] = "vhdNaleuTHenaOlL"; //16 bits
printf("cipher(before): %x \n", cipher);
AES128_CBC_encrypt_buffer(cipher, in, 64, key, IV);
for(int n=0; n<64; n++){
printf("cipher[%d]: %x \n", n, cipher);
}
The function I am using from tiny AES 128 library is this :
void AES128_CBC_encrypt_buffer(uint8_t* output, uint8_t* input, uint32_t length, const uint8_t* key, const uint8_t* iv)
However, the last line of printing 'cipher' is empty. I believe it should print the cipher text of the original input after encryption. Is this the correct way to use the library? Thank you.
EDIT: I updated the code here, in which 'cipher' is now printing characters but in a strange way. It prints the same thing before and after encryption, which should not be the case. This is the same case even when I changed the 'key' and 'IV' to be 16 bits and input message 'in' as 64 bits. Here is a part of the output:
cipher(before): 20003A34
cipher[0]: 20003A34
cipher[1]: 20003A34
cipher[2]: 20003A34
.
.
cipher[63]: 20003A34
Your code has undefined behavior.
This:
unsigned char *cipher = "";
makes cipher into a pointer to a single byte with the value 0 (the string terminator). It's a bit fishy since string literals are not guaranteed to be unsigned char (they're just char which is either signed or unsigned) but I think it will build.
This doesn't give you any writeable space, since string literals are read-only, so trying to write an entire encrypted block in there will give you undefined behavior.
To fix it you need:
unsigned char in[] = "THJmaoeuf2jsn4jebc7ak3mUdnyHeklOYopdna/OOndu3bis/E7jTd/enasduR3h"; //64 bits
unsigned char cipher[sizeof in];
Also, the encrypted data is very likely not a valid C string, it can contain 0-bytes and thus won't print correctly using printf("%s", ...); anyway.
in the line:
printf("cipher[%d]: %x \n", n, cipher);
change that to be:
printf("cipher[%d]: %x \n", n, cipher[n]);
That way, each byte of the cipher is outputted instead of the address of cipher which is what you are getting.
in aes.h select 128 by
#define AES128 1
and below is a sample for Encryption & Decryption
struct AES_ctx ctx;
uint8_t key[] = "aaaaaaaaaaaaaaaa";
uint8_t iv[] = "bbbbbbbbbbbbbbbb";
uint8_t str[] = "This a sample text, Length eq 32";
printf("\n raw buffer \n");
for (int i = 0; i < 32; ++i) {
printf("%.2x", str[i]);
}
AES_init_ctx_iv(&ctx, key, iv);
AES_CBC_encrypt_buffer(&ctx, str, 32);
printf("\n Encrypted buffer\n");
for (int i = 0; i < 32; ++i) {
printf("%.2x", str[i]);
}
printf("\n Decrypted buffer\n");
AES_init_ctx_iv(&ctx, key, iv);
AES_CBC_decrypt_buffer(&ctx, str, 32);
for (int i = 0; i < 32; ++i) {
printf("%.2x", str[i]);
}
printf("\n");
*Note: there is no padding is provided so for CBC and ECB, All buffers should be multiples of 16 bytes.

Segmentation fault in EVP_DecryptFinal_ex when using AES-128/CBC

This is a continuation of my previous question: Intermittent decryption failures in EVP_DecryptFinal_ex when using AES-128/CBC.
I am trying to encrypt and decrypt using the C OpenSSL EVP library. After I received an answer to my question above, I updated my code accordingly:
This variable:
int len = outlen1 + outlen2;
Stores the number of bytes encrypted in the encrypt function. I then pass that variable to the decrypt function (the passing is not shown in the code below) which then uses what is supposedly the actual number of bytes.
However on some input strings, I get segmentation faults at the EVP_DecryptFinal_ex() function.
Something is obviously wrong with the number of bytes encrypted/decrypted or padding. I just don't know what that is.
char* encrypt(char *key, char *s) {
unsigned char iv[16] = {[0 ... 15 ] = 0};
unsigned char outbuf[1024] = {[0 ... 1023] = 0};
int outlen1, outlen2;
EVP_CIPHER_CTX ctx;
EVP_CIPHER_CTX_init(&ctx);
EVP_EncryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, key, iv);
if (EVP_EncryptUpdate(&ctx, outbuf, &outlen1, s, strlen(s)) == 1) {
if (EVP_EncryptFinal_ex(&ctx, outbuf + outlen1, &outlen2) == 1) {
EVP_CIPHER_CTX_cleanup(&ctx);
len = outlen1 + outlen2;
return strdup(outbuf);
}
}
EVP_CIPHER_CTX_cleanup(&ctx);
return NULL;
}
char* decrypt(char *key, char *s, int len) {
unsigned char iv[16] = {[0 ... 15 ] = 0};
unsigned char outbuf[1024] = {[0 ... 1023] = 0};
int outlen1, outlen2;
printf("len: %d\n", len);
printf("strlen(s): %d\n", strlen(s));
EVP_CIPHER_CTX ctx;
EVP_CIPHER_CTX_init(&ctx);
EVP_DecryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, key, iv);
if (EVP_DecryptUpdate(&ctx, outbuf, &outlen1, s, len) == 1) {
printf("After update\n");
if (EVP_DecryptFinal_ex(&ctx, outbuf + outlen1, &outlen2) == 1) {
printf("After final\n");
EVP_CIPHER_CTX_cleanup(&ctx);
return strdup(outbuf);
}
}
EVP_CIPHER_CTX_cleanup(&ctx);
return NULL;
}
NOTE:
I was able to fix the problems I previously had where decrypt final would fail to decrypt certain strings. Those strings can be decrypted fine now. However, some other strings are facing the same problem but this time I am getting seg faults.
You cannot use string functions on binary data. This is especially the case if that binary data is indistinguishable from random. Random binary data may contain null characters anywhere, or not at all. strdup uses strcpy internally, which relies on the null character to be present.

AES encryption and base64 encoding of cipher

I am trying to use the bottom posted code to encrypt using openssl EVP_aes_256_cbc(), I have tested the below code and it is working fine. what I am looking forward to is getting the cipher and then perform base64 encoding and return the same.
I know of the below command:
openssl enc -aes-256-cbc -a -in /u/zsyed10/T.dat -out /u/zsyed10/T_ENC.dat
but not sure if there is any EVP function which would return base64 encoded cipher.
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <openssl/evp.h>
#include <openssl/aes.h>
/**
* Create an 256 bit key and IV using the supplied key_data. salt can be added for taste.
* Fills in the encryption and decryption ctx objects and returns 0 on success
**/
int aes_init(unsigned char *key_data, int key_data_len, unsigned char *salt, EVP_CIPHER_CTX *e_ctx,
EVP_CIPHER_CTX *d_ctx)
{
int i, nrounds = 5;
unsigned char key[32], iv[32];
/*
* Gen key & IV for AES 256 CBC mode. A SHA1 digest is used to hash the supplied key material.
* nrounds is the number of times the we hash the material. More rounds are more secure but
* slower.
*/
i = EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha1(), salt, key_data, key_data_len, nrounds, key, iv);
if (i != 32) {
printf("Key size is %d bits - should be 256 bits\n", i);
return -1;
}
EVP_CIPHER_CTX_init(e_ctx);
EVP_EncryptInit_ex(e_ctx, EVP_aes_256_cbc(), NULL, key, iv);
EVP_CIPHER_CTX_init(d_ctx);
EVP_DecryptInit_ex(d_ctx, EVP_aes_256_cbc(), NULL, key, iv);
return 0;
}
/*
* Encrypt *len bytes of data
* All data going in & out is considered binary (unsigned char[])
*/
unsigned char *aes_encrypt(EVP_CIPHER_CTX *e, unsigned char *plaintext, int *len)
{
/* max ciphertext len for a n bytes of plaintext is n + AES_BLOCK_SIZE -1 bytes */
int c_len = *len + AES_BLOCK_SIZE, f_len = 0;
unsigned char *ciphertext = malloc(c_len);
/* allows reusing of 'e' for multiple encryption cycles */
EVP_EncryptInit_ex(e, NULL, NULL, NULL, NULL);
/* update ciphertext, c_len is filled with the length of ciphertext generated,
*len is the size of plaintext in bytes */
EVP_EncryptUpdate(e, ciphertext, &c_len, plaintext, *len);
/* update ciphertext with the final remaining bytes */
EVP_EncryptFinal_ex(e, ciphertext+c_len, &f_len);
*len = c_len + f_len;
return ciphertext;
}
/*
* Decrypt *len bytes of ciphertext
*/
unsigned char *aes_decrypt(EVP_CIPHER_CTX *e, unsigned char *ciphertext, int *len)
{
/* because we have padding ON, we must allocate an extra cipher block size of memory */
int p_len = *len, f_len = 0;
unsigned char *plaintext = malloc(p_len + AES_BLOCK_SIZE);
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;
}
int main(int argc, char **argv)
{
/* "opaque" encryption, decryption ctx structures that libcrypto uses to record
status of enc/dec operations */
EVP_CIPHER_CTX en, de;
/* 8 bytes to salt the key_data during key generation. This is an example of
compiled in salt. We just read the bit pattern created by these two 4 byte
integers on the stack as 64 bits of contigous salt material -
ofcourse this only works if sizeof(int) >= 4 */
unsigned int salt[] = {12345, 54321};
unsigned char *key_data;
int key_data_len, i;
char *input[] = {"a", "abcd", "this is a test", "this is a bigger test",
"\nWho are you ?\nI am the 'Doctor'.\n'Doctor' who ?\nPrecisely!",
NULL};
/* the key_data is read from the argument list */
key_data = (unsigned char *)argv[1];
key_data_len = strlen(argv[1]);
/* gen key and iv. init the cipher ctx object */
if (aes_init(key_data, key_data_len, (unsigned char *)&salt, &en, &de)) {
printf("Couldn't initialize AES cipher\n");
return -1;
}
/* encrypt and decrypt each input string and compare with the original */
for (i = 0; input[i]; i++) {
char *plaintext;
unsigned char *ciphertext;
int olen, len;
/* The enc/dec functions deal with binary data and not C strings. strlen() will
return length of the string without counting the '\0' string marker. We always
pass in the marker byte to the encrypt/decrypt functions so that after decryption
we end up with a legal C string */
olen = len = strlen(input[i])+1;
ciphertext = aes_encrypt(&en, (unsigned char *)input[i], &len);
plaintext = (char *)aes_decrypt(&de, ciphertext, &len);
if (strncmp(plaintext, input[i], olen))
printf("FAIL: enc/dec failed for \"%s\"\n", input[i]);
else
printf("OK: enc/dec ok for \"%s\"\n", plaintext);
free(ciphertext);
free(plaintext);
}
EVP_CIPHER_CTX_cleanup(&en);
EVP_CIPHER_CTX_cleanup(&de);
return 0;
}
Thanks for the information on BIO filters, etc.
Also could someone please explain the usage of:
EVP_EncryptInit_ex(e, NULL, NULL, NULL, NULL);
as it appears before EVP_EncryptUpdate() and after:
EVP_EncryptInit_ex(e_ctx, EVP_aes_256_cbc(), NULL, key, iv);
Is it not overwriting the key and IV with NULL values rendering the usage of key and IV obsolete.
I understand that it is resetting so that the context could be used again but would have made more sense if it appeared after EVP_EncryptUpdate()

Encrypting and decrypting a message with Blowfish

Here is a basic code of encryping and decrypting a message:
#include <stdio.h>
#include <openssl/blowfish.h>
#include <string.h>
//gcc cryptage.c -o cryptage -lcrypto
int main(){
BF_KEY *key = malloc(sizeof(BF_KEY));
unsigned char *crypt_key = "Key of encryption";
const unsigned char *in = "Message to encrypt";
int len = strlen(crypt_key);
unsigned char *out = malloc(sizeof(char)*len);
unsigned char *result = malloc(sizeof(char)*len);
//Defining encryption key
BF_set_key(key, len, crypt_key);
//Encryption
BF_ecb_encrypt(in, out, key, BF_ENCRYPT);
//Décryption
BF_ecb_encrypt(out, result, key, BF_DECRYPT);
fprintf(stdout,"Result: %s\n",result);
return 0;
}
My problem is the result i get. It's always a String of 8 caracters, no more.
Can you please help me encrypt and decrypt the full message?
Thank you!
As #WhozCraig says, do things 8 bytes at a time.
The data to encrypt should be viewed as a byte array and not a C string.
So consider the string to encrypt with the \0 and padded with random data to form a byte array that is a multiple of 8.
Call encrypt multiple times, encrypting 8 bytes per iteration.
To decrypt, call decryption the same number of iterations. Note that the result buffer may need to be sized up to a multiple of 8.
const unsigned char *in = "Message to encrypt";
size_t InSize = strlen(in) + 1;
int KeyLen = strlen(crypt_key);
size_t OutSize = (InSize + 7) & (~7);
unsigned char *out = malloc(Outsize);
unsigned char *outnext = out;
//Defining encryption key
BF_set_key(key, KeyLen, crypt_key);
//Encryption
while (InSize >= 8) {
BF_ecb_encrypt(in, outnext, key, BF_ENCRYPT);
in += 8;
outnext += 8;
InSize -= 8;
}
if (Insize > 0) { // Cope with non-octal length
unsigned char buf8[8];
memcpy(buf8, in, InSize);
for (i=InSize; i<8; i++) {
buf8[i] = rand();
}
BF_ecb_encrypt(buf8, outnext, key, BF_ENCRYPT);
}
//Décryption
unsigned char *result = malloc(OutSize);
unsigned char *resultNext = result;
while (OutSize) {
BF_ecb_encrypt(out, resultNext, key, BF_DECRYPT);
out += 8;
resultNext += 8;
OutSize -= 8;
}
fprintf(stdout,"Result: %s\n",result);
// No need to print the random bytes that were generated.
return 0;
}
Not quite comfortable have a known byte (\0) encoded in the last block. A different length indication may be prudent.

Resources