Simple AES encryption decryption with openssl library in C - c

I want to encrypt a struct containing few String and then decrypt it. I tried following code. The original code is found from the web and it was working perfectly. I change the input of it to a struct. following is the code.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <openssl/aes.h>
#include <openssl/rand.h>
typedef struct ticket { /* test field */
int ticketId;
char username[20];
char date[20];
} USR_TICKET;
// a simple hex-print routine. could be modified to print 16 bytes-per-line
static void hex_print(const void* pv, size_t len)
{
const unsigned char * p = (const unsigned char*)pv;
if (NULL == pv)
printf("NULL");
else
{
size_t i = 0;
for (; i<len;++i)
printf("%02X ", *p++);
}
printf("\n");
}
// main entrypoint
int main(int argc, char **argv)
{
int keylength;
printf("Give a key length [only 128 or 192 or 256!]:\n");
scanf("%d", &keylength);
/* generate a key with a given length */
unsigned char aes_key[keylength/8];
memset(aes_key, 0, keylength/8);
if (!RAND_bytes(aes_key, keylength/8))
exit(-1);
/* input struct creation */
size_t inputslength = sizeof(USR_TICKET);
USR_TICKET ticket;
ticket.ticketId = 1;
time_t now = time(NULL);
strftime(ticket.date, 20, "%Y-%m-%d", localtime(&now));
strcpy(ticket.username, "ravinda");
printf("Username - %s\n", ticket.username);
printf("Ticket Id - %d\n", ticket.ticketId);
printf("Date - %s\n", ticket.date);
/* init vector */
unsigned char iv_enc[AES_BLOCK_SIZE], iv_dec[AES_BLOCK_SIZE];
RAND_bytes(iv_enc, AES_BLOCK_SIZE);
memcpy(iv_dec, iv_enc, AES_BLOCK_SIZE);
// buffers for encryption and decryption
const size_t encslength = ((inputslength + AES_BLOCK_SIZE) / AES_BLOCK_SIZE) * AES_BLOCK_SIZE;
unsigned char enc_out[encslength];
unsigned char dec_out[inputslength];
memset(enc_out, 0, sizeof(enc_out));
memset(dec_out, 0, sizeof(dec_out));
// so i can do with this aes-cbc-128 aes-cbc-192 aes-cbc-256
AES_KEY enc_key, dec_key;
AES_set_encrypt_key(aes_key, keylength, &enc_key);
AES_cbc_encrypt((unsigned char *)&ticket, enc_out, inputslength, &enc_key, iv_enc, AES_ENCRYPT);
AES_set_decrypt_key(aes_key, keylength, &dec_key);
AES_cbc_encrypt(enc_out, dec_out, encslength, &dec_key, iv_dec, AES_DECRYPT);
printf("original:\t");
hex_print((unsigned char *)&ticket, inputslength);
printf("encrypt:\t");
hex_print(enc_out, sizeof(enc_out));
printf("decrypt:\t");
hex_print(dec_out, sizeof(dec_out));
USR_TICKET * dyc = (USR_TICKET *)dec_out;
printf("Username - %s\n", dyc->username);
printf("Ticket Id - %d\n", dyc->ticketId);
printf("Date - %s\n", dyc->date);
return 0;
}
The problem is only first two members of the struct is decrypting correctly. After that data get currupted. What am I doing wrong here?

I would almost go so far as to say this is a problem with OpenSSL. It seems that when the length parameter passed to AES_cbc_encrypt is > AES_BLOCK_SIZE but not an integral multiple thereof (i.e. length mod AES_BLOCK_SIZE != 0), then the last block is encrypted using the initial IV and not the previous block of ciphertext as should be the case for CBC mode.
You can fix this in one of two ways:
Copy your struct to a buffer whose size is an integral multiple of AES_BLOCK_SIZE, or encrypt in two parts - the full blocks, followed by a single partial block. The latter has the advantage of avoiding additional memory usage and can be done as follows:
size_t fullBlocks = inputslength - (inputslength % AES_BLOCK_SIZE);
size_t remainingBlock = inputslength - fullBlocks;
AES_cbc_encrypt((unsigned char *)&ticket, enc_out, fullBlocks, &enc_key, iv_enc, AES_ENCRYPT);
AES_cbc_encrypt((unsigned char *)&ticket + fullBlocks, enc_out + fullBlocks, remainingBlock, &enc_key, iv_enc, AES_ENCRYPT);
You should then be able to decrypt as you currently are without issue. It's worth noting however that you should declare dec_out as the same size as enc_out, because you're currently overrunning the dec_out buffer when decrypting.
Edit:
I raised this as a bug in OpenSSL: https://rt.openssl.org/Ticket/Display.html?id=3182&user=guest&pass=guest and whilst there is some argument over whether this is actually a bug, or just (undocumented) undefined behavior, the general consensus is that the EVP routines should be used instead, rather than these low-level functions.

The problem might be in the struct you are using, basically because of the struct padding and member sizes. Try to serialize your input and it must work. in a simple way, try to allocate one char buffer and copy your struct contents to the buffer one by one and try to encrypt that buffer and while decrypting also follow the same method. Post here what you are observing after that. We must be able to comment better on that.

The original code has done the padding for you. The problem is that you passed the wrong plaintext length to AES function. You should pass encslength(padded length) to AES_cbc_encrypt. Just change this line
AES_cbc_encrypt((unsigned char *)&ticket, enc_out, inputslength, &enc_key, iv_enc, AES_ENCRYPT);
to
AES_cbc_encrypt((unsigned char *)&ticket, enc_out, encslength, &enc_key, iv_enc, AES_ENCRYPT);
This should solve your problem.

At least I also think it is not a good practise to use struct and sizeof(a_struct_type) here.
The actual binary sequence of the struct USR_TICKET and the result of sizeof will vary according to different padding and byte alignment implementation.
Here is the test result.
1) Firstly, I download the latest openssl1.0.2c and build it, and test the code here with this library on OS X 10.10.3, the code works fine.
2) And I tried to run the test for 5 times. Each time, even the original plain text will changed due to padding of struct(on my OS, the last 4 bytes will be changed every time).
3) So,the same input to the struct produced different plain text, which finally produced different cipher text. The user might be confused by the different cipher text output, when they try to encrypt the same input info(here raving, 1, 2015-6-25) with the same key and iv.
4) Furthermore, just change the struct internal definition, which will produce the same concern in description (3).
typedef struct ticket { /* test field */
int ticketId;
char username[19]; // here try to change from 20 to 19
char date[20]; // here try to change from 20 to other size
} USR_TICKET;
PS. Some outputs result from above description(2),
Output1:
Give a key length [only 128 or 192 or 256!]:
128
Username - ravinda
Ticket Id - 1
Date - 2015-06-25
original: 01 00 00 00 72 61 76 69 6E 64 61 00 00 00 00 00 00 00 00 00 00 00 00 00 32 30 31 35 2D 30 36 2D 32 35 00 00 00 00 00 00 58 BB 3A 50
encrypt: BA 32 86 CC 71 55 2F 73 ED A1 C9 DE 00 32 1A 20 D9 A5 16 52 8A CD F0 F7 38 04 76 38 5A 47 35 3B A3 07 97 41 C4 C2 05 53 74 93 91 26 7E DE 40 47
decrypt: 01 00 00 00 72 61 76 69 6E 64 61 00 00 00 00 00 00 00 00 00 00 00 00 00 32 30 31 35 2D 30 36 2D 32 35 00 00 00 00 00 00 58 BB 3A 50
Username - ravinda
Ticket Id - 1
Date - 2015-06-25
Output2:
Give a key length [only 128 or 192 or 256!]:
128
Username - ravinda
Ticket Id - 1
Date - 2015-06-25
original: 01 00 00 00 72 61 76 69 6E 64 61 00 00 00 00 00 00 00 00 00 00 00 00 00 32 30 31 35 2D 30 36 2D 32 35 00 00 00 00 00 00 58 0B 10 5A
encrypt: BE 60 0F FC 17 A3 42 4A 95 7C 39 DB BF 2C BA 59 42 DC 0C AD B2 20 76 6A 04 E3 DE 11 3E D0 AF 88 A5 B9 D2 25 D4 AE F0 B7 82 9F 13 39 80 39 61 9D
decrypt: 01 00 00 00 72 61 76 69 6E 64 61 00 00 00 00 00 00 00 00 00 00 00 00 00 32 30 31 35 2D 30 36 2D 32 35 00 00 00 00 00 00 58 0B 10 5A
Username - ravinda
Ticket Id - 1
Date - 2015-06-25

Related

How to copy mac-address string in the structure member of type uin8_t

Unexpected MAC-address value obtained using snprintf function
Why do I get "Unexpected mac-address value. I have big string (unsigned char data[DATA_LEN ]) to parse and copy mac address to the structure member. I am getting completely different string. Please help on this, Thank you.
Input data string:
unsigned char data[512] = "its-STRING: 18 22 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 AC 12 00 20 00 00 00 C8 8C DF 9D 57 12 20 00 00 00 29 \n";
Output of the program
Parsed Mac from string = 8C DF 9D 57 12 20
copied MacAddress == 32:30:3a:33:38:00
From the above mentioned string i have to extract the mac-address "8C DF 9D 57 12 20"and then i have to copy this mac-address into the following structure
typedef struct my_stuct_s{
uint8_t mac_addr[18];
}my_stuct_t;
Below is how I have the coded.
#define PARSE_OFFSET 89
#define END_OFFESET 19
#define DATA_LEN 512
#define ADDR_LEN 6
typedef struct my_stuct_s{
uint8_t mac_addr[ADDR_LEN];
uint8_t item;
}my_stuct_t;
int main()
{
unsigned char data[DATA_LEN] = "its-STRING: 18 22 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 AC 12 00 20 00 00 00 C8 8C DF 9D 57 12 20 00 00 00 29 \n";
unsigned char strv6[ADDR_LEN];
unsigned char *data1 = NULL;
my_stuct_t shm_memory;
memset(strv6, 0,sizeof(strv6));
memset(&shm_memory, 0,sizeof(my_stuct_t));
if ((strcmp(data, "") ) != 0)
{
data1 = &data[0];
data1 = data1 + PARSE_OFFSET;
snprintf(strv6, END_OFFESET,"%s\n", data1);
printf("Parsed Mac from string = %s\n", strv6);
snprintf((char *)&shm_memory.mac_addr, ADDR_LEN,
"%02x:%02x:%02x:%02x:%02x:%02x\n",
strv6[0], strv6[1],
strv6[2], strv6[3],
strv6[4], strv6[5]);
printf("copied MacAddress == %02x:%02x:%02x:%02x:%02x:%02x\n ",
shm_memory.mac_addr[0],
shm_memory.mac_addr[1],
shm_memory.mac_addr[2],
shm_memory.mac_addr[3],
shm_memory.mac_addr[4],
shm_memory.mac_addr[5]);
}
else
printf("\n empty string");
return 0;
}
Your parse offset starts at 89 and number of chars to be copied are 18.
#define PARSE_OFFSET 89
#define END_OFFESET 19
should be
#define PARSE_OFFSET 90
#define END_OFFESET 18
Length of the char array which stores the address should be 19.
unsigned char strv6[19];
You need to use sscanf not sprintf as below.
sscanf(strv6, "%02x %02x %02X %02x %02x %02x\n",
&shm_memory.mac_addr[0],
&shm_memory.mac_addr[1],
&shm_memory.mac_addr[2],
&shm_memory.mac_addr[3],
&shm_memory.mac_addr[4],
&shm_memory.mac_addr[5]);

fread why returns 1 for file starting with ff fe read in binary mode

I'm trying to read UTF file and decided to read it in binary mode and skip non-ASCII as file consists of valid english text basically. I'm stuck at fread returning 1 instead of number of bytes requested. First output of print_hex IMHO shows it has read more than 1 char. I've read some examples of reading binary files in C e.g Read and write to binary files in C?, read about fread e.g. here https://en.cppreference.com/w/c/io/fread and here How does fread really work?, still puzzled why it returns 1. File hexdump, and complete C code and output below.
ADD: compiled by gcc, run on Linux.
File:
00000000 ff fe 41 00 41 00 42 00 61 00 0d 00 0a 00 41 00 |..A.A.B.a.....A.|
00000010 41 00 45 00 72 00 0d 00 0a 00 66 00 73 00 61 00 |A.E.r.....f.s.a.|
00000020 6a 00 0d 00 0a 00 64 00 73 00 61 00 66 00 64 00 |j.....d.s.a.f.d.|
00000030 73 00 61 00 66 00 64 00 73 00 61 00 0d 00 0a 00 |s.a.f.d.s.a.....|
00000040 64 00 66 00 73 00 61 00 0d 00 0a 00 66 00 64 00 |d.f.s.a.....f.d.|
00000050 73 00 61 00 66 00 73 00 64 00 61 00 66 00 0d 00 |s.a.f.s.d.a.f...|
00000060 0a 00 0d 00 0a 00 0d 00 0a 00 |..........|
Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void print_hex(const char *s)
{
while(*s)
printf("%02x ", (unsigned char) *s++);
printf("\n");
}
int main(){
#define files_qty 5
const char* files_array[][2]={{"xx","a"},{"zz","b"},{"xxx","d"},{"d","sd"},{"as","sd"}};
const char* file_postfix = ".txt";
char* file_out_name = "XXX_AD.txt";
FILE* file_out = fopen (file_out_name, "w");
printf ("This app reads txt files with hardcoded names and writes to file %s\n",file_out_name);
/* ssize_t bytes_read = 1; //signed size_t */
size_t n_bytes = 10;
unsigned char* string_in;
char* string_out;
char* file_name;
string_in = (char*) malloc (n_bytes+1);
string_out = (char*) malloc (n_bytes+50);
file_name = (char*) malloc (n_bytes+1); /* more error prone would be to loop through array for max file name length */
int i;
size_t n;
for (i=0;i<files_qty;i++)
{
strcpy (file_name,files_array[i][0]);
FILE* file = fopen (strcat(file_name,file_postfix), "rb");
if (file!= NULL)
{
int k=0;
while (n=fread (string_in, sizeof(char), n_bytes, file)>0)
{
printf("bytes read:%lu\n",(unsigned long) n);
print_hex(string_in);
int j;
for (j=0;j<n;j++)
{
switch (string_in[j])
{
case 0x00:
case 0xff:
case 0xfe:
case 0x0a:
break;
case 0x0d:
string_out[k]=0x00;
fprintf (file_out, "%s;%s;%s\n", files_array[i][0], files_array[i][1], string_out);
k=0;
printf("out:\n");
print_hex(string_out);
break;
default:
string_out[k++]=string_in[j];
}
}
}
fclose (file);
}
else
{
perror (file_name); /* why didn't the file open? */
}
}
free (string_in);
free (string_out);
free (file_name);
return 0;
}
Output:
bytes read:1
ff fe 41
bytes read:1
0d
out:
bytes read:1
72
bytes read:1
61
bytes read:1
73
bytes read:1
61
bytes read:1
0d
out:
72 61 73 61
bytes read:1
61
bytes read:1
73
bytes read:1
61
bytes read:1
0a
You have a precedence problem. Simple assignment has lower precedence than comparison. So the following line:
while(n=fread (string_in, sizeof(char), n_bytes, file)>0)
is evaluated as (extra parenthesis)
while (n=(fread (string_in, sizeof(char), n_bytes, file)>0))
Therefore n is being assigned as 1 because fread is returning a value > 0
Instead, explicitly add parenthesis as:
while((n=fread (string_in, sizeof(char), n_bytes, file))>0)

C program Reading Hex values from Fat MBR

I am new to the C language and am trying to create a forensic tool. So far i have this. It reads a dd file which is a dump of a fat16 MBR. I am able to read certain bytes properly but not some.
What i need help with is the SizeOfFat variable needs to get the values of byte 0x16 and 0x17 read in little endian. How would i have it read FB00 and then convert it to 00FB and then print the value ?
char buf[64];
int startFat16 = part_entry[0].start_sect,sectorSize = 512,dirEntrySize=32;
fseek(fp, startFat16*512, SEEK_SET);
fread(buf, 1, 64, fp);
int rootDir = *(int*)(buf+0x11);
int sectorPerCluster = *(int*)(buf+0x0D);
int sizeOfFat = *(int*)(buf+0x16);
int fatCopies = *(int*)(buf+0x10);
printf("\n Phase 2 \n no of sectors per cluster : %d \n",(unsigned char)sectorPerCluster);
printf("size of fat : %d \n",(unsigned char)sizeOfFat);
printf("no of Fat copies : %d \n",(unsigned char)fatCopies);
printf("maximum number of root directories : %d \n",(unsigned char)rootDir);
The hex values im working with here are -
EB 3C 90 4D 53 44 4F 53 35 2E 30 00 02 08 02 00
02 00 02 00 00 F8 FB 00 3F 00 FF 00 3F 00 00 00
E1 D7 07 00 80 00 29 CD 31 52 F4 4E 4F 20 4E 41
With int, you only got the guarantee that it can hold 32-bit signed integers. With your code, you read sizeof(int) bytes for every of your variables, even though they differ in size. There are uint16_t, uint8_t, uint32_t types on most systems. Use those for fixed-width data. Note also that they are unsigned. You don't want negative sectors per cluster, do you?

Not able to remove specific bytes from buffer using memcpy

I m not able to truncate the buffer from the size what I want. I'm bit perplexed why I get wrong results? Even though my usage of memcpy() is right. I read the man page also. I'm doing something wrong here?
What I want to achieve:
Buff: 00 83 00 00 16 0a 44 00 00 00 00 bd 0e 8a 0c 61 01 13 51 24 ad 9a 0b 1c 0e ff ff 00
Copy the bytes which start from bd, that means 12th bytes till the end-
Desired Output should be:
bd 0e 8a 0c 61 01 13 51 24 ad 9a 0b 1c 0e ff ff 00
This is my code:
I'm receiving the response from serial device and I need chop some bytes.
void rx_dev(transport, int addr, const void *buf, unsigned count) {
uint8_t s[1024];
uint8_t *p;
memset (s, 0, sizeof(s));
// This below function does only the hex parsing.
hex_parse(s, sizeof(s), buf, count);
printf("* %02x %s\n", addr, s);
printf("Count: %zu\n", count);
p = s;
printf("p* %s\n", p);
// I'm doing this check to avoid something greater than 14.
if (count > 14) {
memcpy(p, s+11, count-11);
printf("*Trim:%s\n", p);
}
}
EDIT: Added the more details
int hex_parse(char *out, unsigned size, const void *buf, unsigned count)
{
const uint8_t *p = buf;
unsigned i;
int n = 0;
if (count)
{
if (n + 2 < size)
{
out[n+0] = hexchars[(p[0] >> 4) & 15];
out[n+1] = hexchars[p[0] & 15];
}
n += 2;
}
for (i = 1; i < count; i++) {
if (n + 3 < size)
{
out[n+0] = ' ';
out[n+1] = hexchars[(p[i] >> 4) & 15];
out[n+2] = hexchars[p[i] & 15];
}
n += 3;
}
if (n < size)
out[n] = '\0';
else if (size)
out[size-1] = '\0';
return n;
}
My ouutput:
* 01 00 83 00 00 16 0a 44 00 00 00 00 bd 0e 8a 0c 61 01 13 51 24 ad 9a 0b 1c 0e ff ff 00
p* 00 83 00 00 16 0a 44 00 00 00 00 bd 0e 8a 0c 61 01 13 51 24 ad 9a 0b 1c 0e ff ff 00
Here I don't get the correct output, why is it prinitng 28bytes, this is not my desired result I wanted?
Trim: 16 0a 44 00 00 0 44 00 00 00 00 bd 0e 8a 0c 61 01 13 51 24 ad 9a 0b 1c 0e ff ff 00
You can use memmove , as in memcpy the target and the source must not overlap each other, while in memmove it does not matter. So you can do
int offset = 11,size = 28;
memmove(buf, buf+off, size - off);
The source and destination in your memcpy call overlap. From the standard:
If copying takes place between objects that overlap, the behavior
is undefined.
The standard function memmove is like memcpy but defined for overlapping objects, use that instead.
When you're calling memcpy, you're not copying the bytes from the buffer. You're copying the "hex_parsed" string. As that format uses 3 characters per byte (2 digits and a space), chopping 11 characters is chopping about 4 bytes.

Output not as expected in fwrite

I am learning fread and fwrite of c and made a basic code to write a structure using fwrite in a file . Output was there on the
#include<stdio.h>
int main()
{
FILE *f;
int i,q=0;
typedef struct {
int a;
char ab[10];
}b;
b var[2];
f=fopen("new.c","w");
printf("Enter values in structure\n");
for(i=0 ; i<2 ; i++)
{
scanf("%d",&var[i].a);
scanf("%s",var[i].ab);
}
fwrite(var,sizeof(var),1,f);
fclose(f);
return 0;
}
The output was not smooth as it contained weird characters inside the file. I opened the file in binary mode too but in vain. Is this some kind of buffer problem?
The "weird" characters inside your file are probably the bytes of the binary integers you're writing out. fwrite is writing the bits of var directly to the file, not converting that into a human readable format. If you want that, use fprintf instead.
Here's an example directly from your code above:
$ ./example
Enter values in structure
5 hello
8 world
$ hexdump -vC new.c
00000000 05 00 00 00 68 65 6c 6c 6f 00 00 00 00 00 00 00 |....hello.......|
00000010 08 00 00 00 77 6f 72 6c 64 00 00 00 00 00 00 00 |....world.......|
00000020
Notice that the first four bytes at offset 0x00 and 0x10 are the numbers entered (little-endian and 32-bit because of my machine), followed by the strings entered, plus a bit of structure padding. All broken down:
File Offset Data (ASCII) Relationship to source
0 05 var[0].a 7:0
1 00 var[0].a 15:8
2 00 var[0].a 23:16
3 00 var[0].a 31:24
4 68 (h) var[0].ab[0]
5 65 (e) var[0].ab[1]
6 6c (l) var[0].ab[2]
7 6c (l) var[0].ab[3]
8 6f (o) var[0].ab[4]
9 00 (NUL) var[0].ab[5]
10 00 (NUL) var[0].ab[6]
11 00 (NUL) var[0].ab[7]
12 00 (NUL) var[0].ab[8]
13 00 (NUL) var[0].ab[9]
14 00 structure padding
15 00 structure padding
16 08 var[1].a 7:0
17 00 var[1].a 15:8
18 00 var[1].a 23:16
19 00 var[1].a 31:24
20 77 (w) var[1].ab[0]
21 6f (o) var[1].ab[1]
22 72 (r) var[1].ab[2]
23 6c (l) var[1].ab[3]
24 64 (d) var[1].ab[4]
25 00 (NUL) var[1].ab[5]
26 00 (NUL) var[1].ab[6]
27 00 (NUL) var[1].ab[7]
28 00 (NUL) var[1].ab[8]
29 00 (NUL) var[1].ab[9]
30 00 structure padding
31 00 structure padding

Resources