I need to put structs from a binary file into an array of structs, one struct per key.
Here is my struct:
struct candidate{
char inscr[10];
char name[44];
int year;
int position;
char curse[30];
};
typedef struct candidate Candidate;
Here's what I tried to do:
void ordenafile(char fname[13]){
FILE *f = fopen (fname, "rb");
if(f==NULL){
printf("Error.");
return;
}
fseek(f, 0, SEEK_END);
int sz = ftell(f);
Candidate *p, *aux,*arr[sz/sizeof(Candidate)];
p=(Candidate*)malloc(sizeof(Candidate));
int i = 0;
while(fread(p,sizeof(candidate),1,f)>0){
arr[i]=p;
i++;
}
Having found the end of the file with fseek(), you need to rewind before reading from it.
This part of the code doesn't do what you want:
Candidate *p, *aux,*arr[sz/sizeof(Candidate)];
p=(Candidate*)malloc(sizeof(Candidate));
int i = 0;
while(fread(p,sizeof(candidate),1,f)>0){
arr[i]=p;
i++;
}
You have an array of structure pointers, and you allocate one structure, pointed at by p. Your loop then reads a value into the one structure, and copies the pointer into an element of the array of pointers. So, all the elements of the array point to the same structure. The variable aux is also unused.
You need one of two solutions:
Candidate arr[sz/sizeof(Candidate)];
int i;
for (i = 0; fread(&arr[i], sizeof(Candidate), 1, f) == 1; i++)
;
This assumes you are going to be able to use the array in the current function and functions it calls, and don't need to return it to the calling code.
Alternatively:
Candidate *arr = malloc(sz);
if (arr == 0)
return 0;
int i;
for (i = 0; fread(&arr[i], sizeof(Candidate), 1, f) == 1; i++)
;
return arr;
You can return this array from the function.
Working code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct candidate
{
char inscr[10];
char name[44];
int year;
int position;
char curse[30];
};
typedef struct candidate Candidate;
int write_sample_data(const char *filename);
Candidate *read_sample_data(const char *filename, int *number);
void print_sample_data(int num, Candidate *candidates);
int main(void)
{
const char filename[] = "practice.data";
if (write_sample_data(filename) != 0)
fprintf(stderr, "Failed to write sample data\n");
else
{
int number = 0;
Candidate *clist = read_sample_data(filename, &number);
if (number == 0)
fprintf(stderr, "Failed to read sample data\n");
else
{
print_sample_data(number, clist);
free(clist);
}
}
return 0;
}
int write_sample_data(const char *filename)
{
FILE *fp = fopen(filename, "wb");
if (fp == NULL)
{
fprintf(stderr, "Failed to open file %s for writing\n", filename);
return -1;
}
Candidate c;
for (int i = 0; i < 5; i++)
{
char inscr[10];
char name[40];
char curse[30];
sprintf(inscr, "I-%.4d", i);
sprintf(name, "Name %.4d Surname %.4d", rand() % 1000, rand() % 1000);
sprintf(curse, "Curse %.2d", rand() % 100);
// Using null-filling property of strncpy()
strncpy(c.inscr, inscr, sizeof(c.inscr));
strncpy(c.name, name, sizeof(c.name));
strncpy(c.curse, curse, sizeof(c.curse));
c.year = 2010 + i;
c.position = 1000 * i + (99 - i);
if (fwrite(&c, sizeof(Candidate), 1, fp) != 1)
{
fclose(fp);
fprintf(stderr, "Failed to write candidate %d\n", i);
return -1;
}
}
fclose(fp);
return 0;
}
Candidate *read_sample_data(const char *filename, int *number)
{
FILE *fp = fopen(filename, "rb");
if (fp == NULL)
{
fprintf(stderr, "Failed to open file %s for reading\n", filename);
return 0;
}
fseek(fp, 0, SEEK_END);
size_t sz = ftell(fp);
rewind(fp);
Candidate *arr = malloc(sz);
if (arr == 0)
{
fprintf(stderr, "Failed to allocate %zu bytes memory\n", sz);
return 0;
}
int i;
for (i = 0; fread(&arr[i], sizeof(Candidate), 1, fp) == 1; i++)
;
*number = i;
return arr;
}
void print_sample_data(int number, Candidate *clist)
{
for (int i = 0; i < number; i++)
{
printf("%-10s %-30s %.4d %.4d %s\n",
clist[i].inscr, clist[i].name, clist[i].year,
clist[i].position, clist[i].curse);
}
}
Note that this produces the same data each time it is run, despite using the pseudo-random numbers from rand(). Note too that the code deliberately exploits the behaviour of strncpy() that pads a field with null bytes to the full length so that the data in the file doesn't have any extraneous matter.
Sample output:
I-0000 Name 0249 Surname 0807 2010 0099 Curse 73
I-0001 Name 0930 Surname 0658 2011 1098 Curse 72
I-0002 Name 0878 Surname 0544 2012 2097 Curse 23
I-0003 Name 0440 Surname 0709 2013 3096 Curse 65
I-0004 Name 0042 Surname 0492 2014 4095 Curse 87
Hex dump of data file:
0x0000: 49 2D 30 30 30 30 00 00 00 00 4E 61 6D 65 20 30 I-0000....Name 0
0x0010: 32 34 39 20 53 75 72 6E 61 6D 65 20 30 38 30 37 249 Surname 0807
0x0020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x0030: 00 00 00 00 00 00 00 00 DA 07 00 00 63 00 00 00 ............c...
0x0040: 43 75 72 73 65 20 37 33 00 00 00 00 00 00 00 00 Curse 73........
0x0050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x0060: 49 2D 30 30 30 31 00 00 00 00 4E 61 6D 65 20 30 I-0001....Name 0
0x0070: 39 33 30 20 53 75 72 6E 61 6D 65 20 30 36 35 38 930 Surname 0658
0x0080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x0090: 00 00 00 00 00 00 00 00 DB 07 00 00 4A 04 00 00 ............J...
0x00A0: 43 75 72 73 65 20 37 32 00 00 00 00 00 00 00 00 Curse 72........
0x00B0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x00C0: 49 2D 30 30 30 32 00 00 00 00 4E 61 6D 65 20 30 I-0002....Name 0
0x00D0: 38 37 38 20 53 75 72 6E 61 6D 65 20 30 35 34 34 878 Surname 0544
0x00E0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x00F0: 00 00 00 00 00 00 00 00 DC 07 00 00 31 08 00 00 ............1...
0x0100: 43 75 72 73 65 20 32 33 00 00 00 00 00 00 00 00 Curse 23........
0x0110: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x0120: 49 2D 30 30 30 33 00 00 00 00 4E 61 6D 65 20 30 I-0003....Name 0
0x0130: 34 34 30 20 53 75 72 6E 61 6D 65 20 30 37 30 39 440 Surname 0709
0x0140: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x0150: 00 00 00 00 00 00 00 00 DD 07 00 00 18 0C 00 00 ................
0x0160: 43 75 72 73 65 20 36 35 00 00 00 00 00 00 00 00 Curse 65........
0x0170: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x0180: 49 2D 30 30 30 34 00 00 00 00 4E 61 6D 65 20 30 I-0004....Name 0
0x0190: 30 34 32 20 53 75 72 6E 61 6D 65 20 30 34 39 32 042 Surname 0492
0x01A0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x01B0: 00 00 00 00 00 00 00 00 DE 07 00 00 FF 0F 00 00 ................
0x01C0: 43 75 72 73 65 20 38 37 00 00 00 00 00 00 00 00 Curse 87........
0x01D0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x01E0:
There are 4 bytes of padding in the structures; 2 after the name and 2 at the end, so its length is a convenient 96 bytes, which just happens to be a multiple of 16, so the hex dump aligns nicely.
Related
Given a byte array buff of length n:
unsigned char buff[n] = "....." // len n
I want to delete m characters at position pos,
0 < pos, m, pos + m < n
I tried using memmove:
memmove(buff + pos, buff + pos + m, n - (pos + m) + 1);
But this doesn't work for byte array as we don't have '\0' terminator for this buff (but we know its length)
How do I delete bytes in between? Anyone please help
Edit: Sample input,
Pos Data
0000 03 00 02 ef 02 f0 80 64 00 08 03 eb 70 82 e0 40
0010 00 ff 30 00 00 00 00 b3 47 43 00 00 00 00 00 00
0020 00 1e 00 c4 00 00 00 00 00 00 00 44 00 65 00 66
0030 00 61 00 75 00 6c 00 74 00 41 00 6c 00 74 00 53
Say I want to delete the highlighted bytes from packet.
New paket,
Pos Data
0000 03 00 02 ef 02 f0 80 64 00 08 03 00 00 00 00 00
0010 00 00 44 00 65 00 66 00 61 00 75 00 6c 00 74 00
0020 41 00 6c 00 74 00 53
This would erase m chars in an array without terminating null character.
int main()
{
int pos = 1, m = 3;
unsigned char arr[8] = {1,2,3,4,5,6,7,8};
memmove(arr + pos, arr + pos + m, sizeof(arr)/sizeof(arr[0]) - pos - m);
// if required to zero-out the remaining elements
memset(arr + sizeof(arr)/sizeof(arr[0]) - m, 0, m);
for (int i = 0; i < sizeof(arr)/sizeof(arr[0]); i++)
printf("%hhu ", arr[i]);
return 0;
}
Output: 1 5 6 7 8 0 0 0
You probably want something like this:
#include <stdio.h>
#include <string.h>
void Display(const char buff[], int nb)
{
for (int i = 0; i < nb; i++)
printf("%d ", buff[i]);
printf("\n");
}
int main()
{
unsigned char buff[20] = { 0,1,2,3,4,5 };
// buff has room for 20 elements
int nbelements = 6; // but there are only 6 meaningful elements
Display(buff, nbelements);
int pos = 1; // delete from element 1
int nbtodelete = 2; // delete 2 elements
memmove(buff + pos, buff + pos + nbtodelete, nbelements - pos - 1);
nbelements -= nbtodelete;
Display(buff, nbelements);
}
Output:
0 1 2 3 4 5
0 3 4 5
It's pretty self explanatory.
I'm having a problem.
I'm trying to create a file and then reading it again, saving the values in a new structure. But when I try to print the values I just get garbaje after 7 values.
What am I doing wrong?
Or maybe there is a fwrite limit
#include<stdio.h>
#include<stdlib.h>
struct estructura_salida
{
int num_art;
int exist;
};
int main (void)
{
fflush(stdin);
int i,j;
long reg;
struct estructura_salida listado[100];
struct estructura_salida ventas[100];
struct estructura_salida listadol[100];
struct estructura_salida ventasl[100];
for(i=0;i<100;i++)
{
listado[i].num_art = i+1;
listado[i].exist = i+20;
ventas[i].num_art = i+1;
ventas[i].exist = i+10;
}
printf("\ncargados\n");
for(i=0;i<100;i++)
{
printf("\n%i\t%i\t%i",listado[i].num_art,listado[i].exist,ventas[i].exist);
}
FILE *fp1;
FILE *fp2;
fp1 = fopen("C://stock.dbf","wt");
fp2 = fopen("C://ventas.dbf","wt");
fwrite(listado,sizeof(struct estructura_salida),200,fp1);
fwrite(ventas,sizeof(struct estructura_salida),200,fp2);
fclose(fp1);
fclose(fp2);
printf("\nleyendo el archivo");
fp1 = fopen("C://stock.dbf","rt");
fp2 = fopen("C://ventas.dbf","rt");
while(!feof(fp1))
{
fread(listadol,sizeof(listadol),1,fp1);
}
while(!feof(fp2))
{
fread(ventasl,sizeof(ventasl),1,fp2);
}
fclose(fp1);
fclose(fp2);
printf("\narchivo leido\n");
for(i=0;i<100;i++)
{
printf("\n%i\t%i\t%i",listadol[i].num_art,listadol[i].exist,ventasl[i].exist);
}
return 0;
}
this is how the console looks, I just get garbaje.
console
Thank you!!
Diagnosis
I believe you are almost certainly working on a Windows system because you used "wt" in the fopen() mode. The t is not recognized by the C standard or most Unix systems. And also because you used fflush(stdin) which is essentially meaningless on non-Windows systems but is defined to do a more or less useful task on Windows systems.
Your primary problem is that you use "wt" to open a text file for writing, but when you use fwrite(), you are writing binary data to a text file. That means that entries containing 10 or 13 are likely to cause chaos.
Use "wb" (and "rb" when reading). This is supported by the C standard and indicates that you are doing binary I/O, not text I/O, and prevents the I/O system from wreaking havoc on your data.
You are also writing 200 records when you only have arrays containing 100 records (as pointed out by R Sahu in their answer) — this is not a recipe for happiness, either.
Your loops using while (!feof(fp1)) are wrong; using while (!feof(file)) is always wrong. You keep reading over the same elements — listadol[0] and ventasl[0], because you simply pass the array name to fread(). You could read all the records back in one fread() operation per file, or you need to index the array correctly (passing &listadol[i] for example).
Strictly, you should verify that the fopen() calls (in particular) are successful. Arguably, you should do the same for the fread() and fwrite() calls. The ultra-fanatic would check the fclose() calls. If the data file is crucial, you should do that, just in case there wasn't enough space on disk, or something else goes radically wrong.
Prescription
Putting the changes together, and using NUM_ENTRIES to identify the number of entries (and changing it from 100 to 10 for compactness of output), I get:
#include <stdio.h>
#include <stdlib.h>
struct estructura_salida
{
int num_art;
int exist;
};
enum { NUM_ENTRIES = 10 };
int main(void)
{
struct estructura_salida listado[NUM_ENTRIES];
struct estructura_salida ventas[NUM_ENTRIES];
struct estructura_salida listadol[NUM_ENTRIES];
struct estructura_salida ventasl[NUM_ENTRIES];
for (int i = 0; i < NUM_ENTRIES; i++)
{
listado[i].num_art = i + 1;
listado[i].exist = i + 20;
ventas[i].num_art = i + 1;
ventas[i].exist = i + 10;
}
printf("\ncargados\n");
for (int i = 0; i < NUM_ENTRIES; i++)
{
printf("%i\t%i\t%i\n", listado[i].num_art, listado[i].exist, ventas[i].exist);
}
const char name1[] = "stock.dbf";
const char name2[] = "ventas.dbf";
FILE *fp1 = fopen(name1, "wb");
FILE *fp2 = fopen(name2, "wb");
if (fp1 == NULL)
{
fprintf(stderr, "Failed to open file %s for reading\n", name1);
exit(EXIT_FAILURE);
}
if (fp2 == NULL)
{
fprintf(stderr, "Failed to open file %s for reading\n", name2);
exit(EXIT_FAILURE);
}
fwrite(listado, sizeof(struct estructura_salida), NUM_ENTRIES, fp1);
fwrite(ventas, sizeof(struct estructura_salida), NUM_ENTRIES, fp2);
fclose(fp1);
fclose(fp2);
printf("\nleyendo el archivo");
fp1 = fopen(name1, "rb");
fp2 = fopen(name2, "rb");
if (fp1 == NULL)
{
fprintf(stderr, "Failed to open file %s for reading\n", name1);
exit(EXIT_FAILURE);
}
if (fp2 == NULL)
{
fprintf(stderr, "Failed to open file %s for reading\n", name2);
exit(EXIT_FAILURE);
}
int n;
for (n = 0; fread(&listadol[n], sizeof(listadol[n]), 1, fp1) == 1; n++)
;
int m;
for (m = 0; fread(&ventasl[m], sizeof(ventasl[m]), 1, fp2) == 1; m++)
;
fclose(fp1);
fclose(fp2);
printf("\narchivo leido\n");
if (n != m)
{
fprintf(stderr, "Read different numbers of records (%d from %s, %d from %s)\n",
n, name1, m, name2);
exit(EXIT_FAILURE);
}
for (int i = 0; i < n; i++)
{
printf("%i\t%i\t%i\n", listadol[i].num_art, listadol[i].exist, ventasl[i].exist);
}
return 0;
}
It would be better to use a function to open the files which checks for failure and reports the error and exits — an exercise for the reader.
The output from that is:
cargados
1 20 10
2 21 11
3 22 12
4 23 13
5 24 14
6 25 15
7 26 16
8 27 17
9 28 18
10 29 19
leyendo el archivo
archivo leido
1 20 10
2 21 11
3 22 12
4 23 13
5 24 14
6 25 15
7 26 16
8 27 17
9 28 18
10 29 19
A hex dump program shows that the two data files contain what you'd expect:
stock.dbf:
0x0000: 01 00 00 00 14 00 00 00 02 00 00 00 15 00 00 00 ................
0x0010: 03 00 00 00 16 00 00 00 04 00 00 00 17 00 00 00 ................
0x0020: 05 00 00 00 18 00 00 00 06 00 00 00 19 00 00 00 ................
0x0030: 07 00 00 00 1A 00 00 00 08 00 00 00 1B 00 00 00 ................
0x0040: 09 00 00 00 1C 00 00 00 0A 00 00 00 1D 00 00 00 ................
0x0050:
ventas.dbf:
0x0000: 01 00 00 00 0A 00 00 00 02 00 00 00 0B 00 00 00 ................
0x0010: 03 00 00 00 0C 00 00 00 04 00 00 00 0D 00 00 00 ................
0x0020: 05 00 00 00 0E 00 00 00 06 00 00 00 0F 00 00 00 ................
0x0030: 07 00 00 00 10 00 00 00 08 00 00 00 11 00 00 00 ................
0x0040: 09 00 00 00 12 00 00 00 0A 00 00 00 13 00 00 00 ................
0x0050:
There aren't any printable characters except the odd CR or LF in that, so the information on the right isn't all that informative. (Tested on a Mac running macOS 10.13.6 High Sierra, using GCC 8.2.0.)
Problem 1
fwrite(listado,sizeof(struct estructura_salida),200,fp1);
fwrite(ventas,sizeof(struct estructura_salida),200,fp2);
You are trying to write 200 objects while you have only 100. That causes undefined behavior.
Problem 2
Use of while(!feof(fp1)) is not right. See Why is “while ( !feof (file) )” always wrong?.
Change the code to read the data to:
int n = fread(listadol, sizeof(listadol[0]), 100, fp1);
// Now you can be sure that n objects were successfully read.
Problem 3
When using fread/fwrite, open the files in binary mode, not text mode.
fp1 = fopen("C://stock.dbf", "wb");
fp2 = fopen("C://ventas.dbf", "wb");
and
fp1 = fopen("C://stock.dbf", "rb");
fp2 = fopen("C://ventas.dbf", "rb");
I'm trying to understand the OpenSSL library in more detail. So rather than using the set of higher-level EVP functions, I've been trying to use the AES_* functions. Following the general set of calls in this question (though I'm using CBC instead of counter mode), I've come up with this code:
void ctr(log_t* log)
{
unsigned char ivec[16];
/* Out buffer for ciphertext */
unsigned char outBuf[16];
blockReader_t* br = blockReaderInit(log, "./input.txt", 128);
int outFD;
if ((outFD = open("out.bin", O_WRONLY)) == -1)
{
logPrint(br->log, LOG_ARGS, LOG_ERR, "open: %s", strerror(errno));
logExit(br->log, LOG_ARGS, EXIT_FAILURE);
}
memset(ivec, 0, 16);
unsigned char* ivec2 = ivec + 8;
unsigned long* ivec3 = (unsigned long*) ivec2;
*ivec3 = (unsigned long) 0xfd0;
AES_KEY aesKey;
char* myKey = "Pampers baby-dry";
int res;
if (!(res = AES_set_encrypt_key((unsigned char*) myKey, 16, &aesKey)))
{
logPrint(log, LOG_ARGS, LOG_ERR, "AES_set_encrypt_key: returned %d", res);
logExit(log, LOG_ARGS, EXIT_FAILURE);
}
unsigned char* buf;
while ((buf = blockReaderGet(br)) != NULL)
{
logPrint(log, LOG_ARGS, LOG_INFO, "ivec =");
logHexdump(log, LOG_ARGS, LOG_INFO, (char*) ivec, 16);
logPrint(log, LOG_ARGS, LOG_INFO, "buf =");
logHexdump(log, LOG_ARGS, LOG_INFO, (char*) buf, 16);
AES_cbc_encrypt(buf, outBuf, 16, &aesKey, ivec, 1);
logPrint(log, LOG_ARGS, LOG_INFO, "outBuf =");
logHexdump(log, LOG_ARGS, LOG_INFO, (char*) outBuf, 16);
int res = write(outFD, outBuf, 16);
if (res == -1)
{
logPrint(log, LOG_ARGS, LOG_ERR, "write: %s", strerror(errno));
logExit(log, LOG_ARGS, EXIT_FAILURE);
}
else if (res < 16)
{
logPrint(log, LOG_ARGS, LOG_WARN, "Unexpectedly wrote < 16 bytes");
}
}
if ((close(outFD)) == -1)
{
logPrint(log, LOG_ARGS, LOG_ERR, "close: %s", strerror(errno));
logExit(log, LOG_ARGS, EXIT_FAILURE);
}
}
The log_t struct and calls to log*() are my own logging framework which I am using to help debug this code. blockReader_t is another framework for reading files in sets of bytes. blockReaderGet() simply fills the destination buffer with the predetermined number of bytes of data (in this case 128 bits/16 bytes).
Contents of input.txt:
$ hexdump -C input.txt
00000000 4d 69 64 6e 69 67 68 74 5f 4d 61 72 6c 69 6e 05 |Midnight_Marlin.|
00000010 52 69 63 68 61 72 64 52 69 63 68 61 72 64 06 07 |RichardRichard..|
00000020
Output (ran in GDB):
(gdb) run
Starting program: /home/adam/crypto/openssl/aes/aes_128
[ 0.000020] <aes_128.c:83> "main" INFO: Log library started (v1.9.0)
...
[ 0.000054] <aes_128.c:50> "ctr" INFO: ivec =
[ 0.000057] <aes_128.c:51> "ctr" INFO: HEX (16 bytes)
---BEGIN_HEX---
00000000 00 00 00 00 00 00 00 00 d0 0f 00 00 00 00 00 00 |................|
00000010
---END_HEX---
[ 0.000069] <aes_128.c:53> "ctr" INFO: buf =
[ 0.000071] <aes_128.c:54> "ctr" INFO: HEX (16 bytes)
---BEGIN_HEX---
00000000 4d 69 64 6e 69 67 68 74 5f 4d 61 72 6c 69 6e 05 |Midnight_Marlin.|
00000010
---END_HEX---
Program received signal SIGSEGV, Segmentation fault.
_x86_64_AES_encrypt_compact () at aes-x86_64.s:170
170 xorl 0(%r15),%eax
I'm using an OpenSSL from GitHub that I've built myself and linked against locally; specifically the OpenSSL_1_0_2e tag, which I gather is the latest stable version.
The Perl file that generates this assembly file uses the $key variable to name what r15 represents. But given that AES_set_encrypt_key() returns success, I'm not sure what's wrong.
Could anyone please offer any pointers to what might be wrong here?
EDIT:
Despite compiling OpenSSL with -g3 instead of -O3, the backtrace isn't useful:
(gdb) bt
#0 _x86_64_AES_encrypt_compact () at aes-x86_64.s:170
#1 0x0000000000402b6b in AES_cbc_encrypt () at aes-x86_64.s:1614
#2 0x00007fffffffe0a0 in ?? ()
#3 0x000080007dfc19a0 in ?? ()
#4 0x00007fffffffe050 in ?? ()
#5 0x0000000000635080 in ?? ()
#6 0x00007fffffffe1a0 in ?? ()
#7 0x0000000000000010 in ?? ()
#8 0x00007ffff7bdf9a0 in ?? ()
#9 0x00007fffffffe1b0 in ?? ()
#10 0x00007fff00000001 in ?? ()
#11 0x00007ffff7bdf4c8 in ?? ()
#12 0x00007fffffffda40 in ?? ()
#13 0x0000000000000000 in ?? ()
EDIT 2:
CFLAG has been changed:
CFLAG= -DOPENSSL_THREADS -D_REENTRANT -DDSO_DLFCN -DHAVE_DLFCN_H -Wa,--noexecstack -m64 -DL_ENDIAN -O0 -ggdb -Wall -DOPENSSL_IA32_SSE2 -DOPENSSL_BN_ASM_MONT -DOPENSSL_BN_ASM_MONT5 -DOPENSSL_BN_ASM_GF2m -DSHA1_ASM -DSHA256_ASM -DSHA512_ASM -DMD5_ASM -DAES_ASM -DVPAES_ASM -DBSAES_ASM -DWHIRLPOOL_ASM -DGHASH_ASM -DECP_NISTZ256_ASM
Note the -O0 -ggdb. Backtrace is the same:
(gdb) bt
#0 _x86_64_AES_encrypt_compact () at aes-x86_64.s:170
#1 0x0000000000402b6b in AES_cbc_encrypt () at aes-x86_64.s:1614
#2 0x00007fffffffe0a0 in ?? ()
#3 0x000080007dfc19a0 in ?? ()
#4 0x00007fffffffe050 in ?? ()
#5 0x0000000000635080 in ?? ()
#6 0x00007fffffffe1a0 in ?? ()
#7 0x0000000000000010 in ?? ()
#8 0x00007ffff7bdf9a0 in ?? ()
#9 0x00007fffffffe1b0 in ?? ()
#10 0x00007fff00000001 in ?? ()
#11 0x00007ffff7bdf4c8 in ?? ()
#12 0x00007fffffffda40 in ?? ()
#13 0x0000000000000000 in ?? ()
EDIT: MCVE example
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <openssl/aes.h>
unsigned char input[] = {0x4du, 0x69u, 0x64u, 0x6eu, 0x69u, 0x67u, 0x68u, 0x74u,
0x5fu, 0x4du, 0x61u, 0x72u, 0x6cu, 0x69u, 0x6eu, 0x05u,
0x52u, 0x69u, 0x63u, 0x68u, 0x61u, 0x72u, 0x64u, 0x52u,
0x69u, 0x63u, 0x68u, 0x61u, 0x72u, 0x64u, 0x06u, 0x07u};
int main()
{
unsigned char ivec[16];
/* ivec[0..7] is the IV, ivec[8..15] is the big endian counter. */
unsigned char outBuf[16];
int outFD;
if ((outFD = open("out.bin", O_WRONLY)) == -1)
{
perror("open");
return EXIT_FAILURE;
}
memset(ivec, 0, 16);
unsigned char* ivec2 = ivec + 8;
unsigned long* ivec3 = (unsigned long*) ivec2;
*ivec3 = (unsigned long) 0xfd0;
AES_KEY aesKey;
char* myKey = "Pampers baby-dry";
int res;
if (!(res = AES_set_encrypt_key((unsigned char*) myKey, 16, &aesKey)))
{
fprintf(stderr, "AES_set_encrypt_key: returned %d", res);
return EXIT_FAILURE;
}
for (int i = 0; i < 32; i += 16)
{
printf("ivec = ");
for (int j = 0; j < 16; j++)
printf("%.02hhx ", ivec[j]);
putchar('\n');
printf("input = ");
for (int j = i; j < (i + 16); j++)
printf("%.02hhx ", input[j]);
putchar('\n');
AES_cbc_encrypt(&input[i], outBuf, 16, &aesKey, ivec, 1);
printf("outBuf = ");
for (int j = 0; j < 16; j++)
printf("%.02hhx ", outBuf[j]);
putchar('\n');
int res = write(outFD, outBuf, 16);
if (res == -1)
{
perror("write");
return EXIT_FAILURE;
}
else if (res < 16)
{
printf("Warning: unexpectedly wrote < 16 bytes");
}
}
if ((close(outFD)) == -1)
{
perror("close");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
So there are several major bugs here. I'll go through all the ones I caught, but there may be more, as I didn't do a thorough code review.
You are using sentinel values everywhere (ie: the 16 integer literals. Swap these out with a preprocessor macro, or even better, a const int).
The output buffer needs to be at least as big as your input buffer, and should be rounded up the the nearest multiple of the block size, plus one more block.
You are looping through each element of the the input data and trying to encrypt one byte at a time. Unless you are implementing some obscure layer on top of AES, this is wrong. You iterate over blocks of data, not individual bytes. The loop is completely unnecessary.
Your input data buffer appears to be bigger than your output data buffer. With your current implementation, the last 16 bytes I think will be truncated/lost, since the input buffer has 32 bytes of data, but the output buffer is 16 bytes. In your specific example, input should be 32 bytes, output should be 32+1.
In addition to the loop being unnecessary, with some modifications it would run (incorrectly, corrupting data), and eventually access invalid memory (ie: pointing to near the end of the input buffer, and telling the encrypt function to ask for 16 bytes of data after that point).
I've provided an updated code listing and sample output that should get you on the right track. Here's a working example that should also guide you along.
Good luck!
Modified Code Listing
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <openssl/aes.h>
#define BLOCK_SIZE (128)
unsigned char input[BLOCK_SIZE] = {
0x4du, 0x69u, 0x64u, 0x6eu, 0x69u, 0x67u, 0x68u, 0x74u,
0x5fu, 0x4du, 0x61u, 0x72u, 0x6cu, 0x69u, 0x6eu, 0x05u,
0x52u, 0x69u, 0x63u, 0x68u, 0x61u, 0x72u, 0x64u, 0x52u,
0x69u, 0x63u, 0x68u, 0x61u, 0x72u, 0x64u, 0x06u, 0x07u};
int main()
{
unsigned char ivec[BLOCK_SIZE];
/* ivec[0..7] is the IV, ivec[8..15] is the big endian counter. */
unsigned char outBuf[BLOCK_SIZE+1];
int outFD;
if ((outFD = open("out.bin", O_CREAT | O_RDWR)) == -1)
{
perror("open");
return EXIT_FAILURE;
}
memset(ivec, 0, BLOCK_SIZE);
unsigned char* ivec2 = ivec + 8;
unsigned long* ivec3 = (unsigned long*) ivec2;
*ivec3 = (unsigned long) 0xfd0;
AES_KEY aesKey;
char* myKey = "Pampers baby-dry";
int res;
if ((res = AES_set_encrypt_key((unsigned char*) myKey, BLOCK_SIZE, &aesKey)) < 0)
{
fprintf(stderr, "AES_set_encrypt_key: returned %d", res);
return EXIT_FAILURE;
}
int i = 0;
//for (int i = 0; i < 32; i += BLOCK_SIZE)
{
printf("ivec = ");
for (int j = 0; j < BLOCK_SIZE; j++)
printf("%.02hhx ", ivec[j]);
putchar('\n');
printf("input = ");
for (int j = i; j < (i + BLOCK_SIZE); j++)
printf("%.02hhx ", input[j]);
putchar('\n');
putchar('\n');
putchar('\n');
putchar('\n');
AES_cbc_encrypt(input, outBuf, BLOCK_SIZE, &aesKey, ivec, AES_ENCRYPT);
printf("outBuf = ");
for (int j = 0; j < BLOCK_SIZE; j++)
printf("%.02hhx ", outBuf[j]);
putchar('\n');
int res = write(outFD, outBuf, BLOCK_SIZE);
if (res == -1)
{
perror("write");
return EXIT_FAILURE;
}
else if (res < BLOCK_SIZE)
{
printf("Warning: unexpectedly wrote < %d bytes.\n", BLOCK_SIZE);
}
}
if ((close(outFD)) == -1)
{
perror("close");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
Build Command
gcc -O0 -ggdb test.c --std=c99 -lssl -lcrypto && ./a.out
Sample Output
ivec = 00 00 00 00 00 00 00 00 d0 0f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
input = 4d 69 64 6e 69 67 68 74 5f 4d 61 72 6c 69 6e 05 52 69 63 68 61 72 64 52 69 63 68 61 72 64 06 07 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
outBuf = 81 ee 91 c0 9f f6 40 db 3c 6d 32 dd 5e 86 6f f8 4e 7b aa 15 38 36 b8 20 bc 04 bd 4f 6c 53 0e 02 72 c2 b7 e8 79 35 f2 b2 e1 c1 6e 1e 3b 1e 75 81 6a 56 43 d8 9d 9c 4c 1e 04 bd 99 29 3a 55 c9 a4 90 48 20 13 5e 51 4a 0c 4b 35 bc db da 54 f1 2b 66 f6 1b 1a 42 25 33 30 0e 35 87 9d 4b 1f d5 3a 5d 3a 8e 8c c8 48 c0 52 72 c0 4e b3 b8 f5 37 03 1c 87 15 61 3b 64 2b 06 5e 12 8f c7 b5 21 98 06
I am trying to convert a hexadecimal data coming from a port( stored in a buffer) into integer format using C program. Before converting from buffer, I wanted to test my code by giving some input in the program. The following is the program I am using from a online source.
#include <stdio.h>
#include <stdlib.h>
int hexToInt(char s[]) {
int hexdigit, i, inhex, n;
i=0;
if(s[i] == '0') {
++i;
if(s[i] == 'x' || s[i] == 'X'){
++i;
}
}
n = 0;
inhex = 1;
for(; inhex == 1; ++i) {
if(s[i] >= '0' && s[i] <= '9') {
hexdigit = s[i] - '0';
} else if(s[i] >= 'a' && s[i] <= 'f') {
hexdigit = s[i] - 'a' + 10;
} else if(s[i] >= 'A' && s[i] <= 'F') {
hexdigit = s[i] - 'A' + 10;
} else {
inhex = 0;
}
if(inhex == 1) {
n = 16 * n + hexdigit;
}
}
return n;
}
int main(int argc, char** argv) {
char hex[] = "93 BC";
int digit = hexToInt(hex);
printf("The Integer is %d", digit);
return 0;
}
When I run this program, it converts one input of hexadecimal into a integer. But if I had to convert an array of hex input as listed below:
00 00 00 05 00 00 00 01 93 BC C0 06 00 00 00 00 ................
00 28 17 00 FC 26 CC 62 00 00 00 07 00 00 00 01 .(...&.b........
00 00 00 D0 00 E3 37 19 00 00 00 1D 00 00 01 00 ......7.........
AB B6 CD 14 00 11 1F 3C 00 00 00 1D 00 00 00 00 .......<........
00 00 00 02 00 00 00 01 00 00 00 90 00 00 00 01 ................
00 00 05 EE 00 00 00 04 00 00 00 80 F0 92 1C 48 ...........�...H
C2 00 00 0E 0C 30 C7 C7 08 00 45 00 05 DC 32 70 .....0....E...2p
40 00 2D 06 41 C8 2D 3A 4A 01 93 BC C8 EC 01 BB #.-.A.-:J.......
C1 58 C5 8D 53 88 05 72 46 E6 80 10 00 53 DC 34
Then how I can convert it into corresponding integer values?
"to convert of array of hex input", modify hexToInt() to hexToInt(const char *s, char **endptr) and have it set *endptr to where the parsing stopped. If no parsing occurred, have *endptr = s.
int main(void) {
char hex[] = "93 BC";
char *p = hex;
while (*p) {
char *endptr;
int digit = hexToInt(p, &endptr);
if (p == endptr) break;
printf("The Integer is %d", digit);
p = endptr;
}
return 0;
}
I am trying to write a program that will talk to a XBee Pro S2B over serial from a PIC16 and I have some odd memory stuff going on...
I am a bit weak when it comes to pointers in C so I have been writing a test program using GCC to get it to work before I move it over to the PIC microcontroller. The biggest thing to note with the PIC is the memory constraints. So for this I would like to avoid adding any external libraries unless I absolutely have to (and avoid having to use malloc/free).
Here is my code:
#include <stdio.h>
#define FALSE 0
#define TRUE 1
void printPacketArray(unsigned char *packetArray, int packetSize){
printf("OUTPUT PACKET: ");
for(int i = 0; i < packetSize; i++){
printf("%02X ", packetArray[i]);
}
printf("\n");
}
/**
* This function builds all of the frames to be wrapped into a packet
*/
int buildFrame(
unsigned char frameType,
unsigned char requestResponse,
unsigned char *destinationAddress64Bit,
unsigned char *destinationAddress16Bit,
unsigned char *rfPacketData,
int destinationAddress64BitSize,
int destinationAddress16BitSize,
int rfDataSize,
unsigned char **frameArray,
int **frameArraySize){
// printf("Entering buildFrame\n");
// FT RESP (Optional Dest Addr x64) + (Optional Dest Addr x16) Packet
int outputPacketSize = (1 + 1 + destinationAddress64BitSize + destinationAddress16BitSize + rfDataSize);
// printf("Packet Size: %d\n", outputPacketSize);
unsigned char outputPacketArray[outputPacketSize];
// Add the frame type
outputPacketArray[0] = frameType;
// printf("Frame type: %02X\n", frameType);
// Request response
outputPacketArray[1] = requestResponse;
// printf("Response: %02X\n", requestResponse);
int arrayCount = 2;
// Add the destination address (64 bit)
if(destinationAddress64Bit != 0x00){
for(int i = 0; i < 8; i++){
outputPacketArray[arrayCount] = destinationAddress64Bit[i];
// printf("outputPacketArray[%d] = %02X\n", arrayCount, destinationAddress64Bit[i]);
arrayCount++;
}
}
// Ad the destination address (16 bit)
if(destinationAddress16Bit != 0x00){
for(int i = 0; i < 2; i++){
outputPacketArray[arrayCount] = destinationAddress16Bit[i];
// printf("outputPacketArray[%d] = %02X\n", arrayCount, destinationAddress16Bit[i]);
arrayCount++;
}
}
// Add the packet data
for(int i = 0; i < rfDataSize; i++){
outputPacketArray[arrayCount] = rfPacketData[i];
// printf("outputPacketArray[%d] = %02X\n", arrayCount, rfPacketData[i]);
arrayCount++;
}
*frameArray = outputPacketArray;
// printf("*frameArray = %p\n", outputPacketArray);
*frameArraySize = &outputPacketSize;
// printf("*frameArraySize = %p\n", &outputPacketSize);
// printf("Packet: ");
// for(int i = 0; i < outputPacketSize; i++){
// printf("%02X ", outputPacketArray[i]);
// }
// printf("\n");
// printf("Exiting buildFrame\n");
return TRUE;
}
/**
* This function wraps the frame data into the packet.
*/
int buildPacket(
unsigned char *frameData,
int frameDataSize,
unsigned char **packetArrayPtr,
int **packetArraySizePtr){
// 7E MSB LSB Packet Checksum
int outputPacketSize = (1 + 1 + 1 + frameDataSize + 1);
int checksum = 0;
unsigned char outputPacketArray[outputPacketSize];
// Add the start delimiter
outputPacketArray[0] = 0x7E;
// Add the MSB (should always be 0x00)
outputPacketArray[1] = 0x00;
// Add the LSB (size of frameData)
outputPacketArray[2] = frameDataSize;
// Add the frame data
int arrayCount = 3;
for(int i = 0; i < frameDataSize; i++){
// printf("CNT: %d\n", arrayCount);
outputPacketArray[arrayCount] = frameData[i];
checksum += frameData[i];
arrayCount++;
}
// Add the checksum
outputPacketArray[arrayCount] = (0xFF - (checksum & 0xFF));
// printf("CNT: %d\n", arrayCount);
// printf("Packet: ");
// for(int i = 0; i < outputPacketSize; i++){
// printf("%02X ", outputPacketArray[i]);
// }
// printf("\n");
*packetArrayPtr = outputPacketArray;
*packetArraySizePtr = &outputPacketSize;
return TRUE;
}
int sendAPICommand(unsigned char* inputFrameData, int inputFrameDataLength){
unsigned char destinationAddress64Bit[] = {0x00, 0x13, 0xA2, 0x00, 0x40, 0x9C, 0x26, 0xE1};
unsigned char destinationAddress16Bit[] = {0xFF, 0xFE};
unsigned char *frameArrayPtr = 0x00;
int *frameArraySizePtr = 0x00;
// printf("COMPARE: 7E 00 13 10 01 00 13 A2 00 40 9C 26 E1 FF FE 00 00 01 02 03 04 05 4A\n");
// We need to add in the radius and options before the data
unsigned char frameData[(inputFrameDataLength + 2)];
frameData[0] = 0x00; // Radius
frameData[1] = 0x00; // Options
for(int i = 0; i < inputFrameDataLength; i++){
frameData[(i + 2)] = inputFrameData[i];
}
if(buildFrame(0x10, 0x01, destinationAddress64Bit, destinationAddress16Bit, frameData, 8, 2, (inputFrameDataLength + 2), &frameArrayPtr, &frameArraySizePtr) == TRUE){
printf("COMPARE: 10 01 00 13 A2 00 40 9C 26 E1 FF FE 00 00 01 02 03 04 05\n");
printPacketArray(frameArrayPtr, *frameArraySizePtr);
// The building of the frame was a success
if(buildPacket(frameArrayPtr, *frameArraySizePtr, &frameArrayPtr, &frameArraySizePtr) == TRUE){
printf("COMPARE: 7E 00 13 10 01 00 13 A2 00 40 9C 26 E1 FF FE 00 00 01 02 03 04 05 4A\n");
printPacketArray(frameArrayPtr, *frameArraySizePtr);
return TRUE;
}
}
return FALSE;
}
int main(){
unsigned char packetData[] = {0x01, 0x02, 0x03, 0x04, 0x05};
sendAPICommand(packetData, 5);
return 0;
}
When I run it, I cannot seem to find out why the results are not consistent. Using the Eclipse debugger, I get the following error:
frameData.15 Error: Multiple errors reported.\ Failed to execute MI command: -var-create - * frameData.15 Error message from debugger back end: mi_cmd_var_create: unable to create variable object\ Failed to execute MI command: -var-create - * frameData.15 Error message from debugger back end: mi_cmd_var_create: unable to create variable object\ Failed to execute MI command: -data-evaluate-expression frameData.15 Error message from debugger back end: No symbol "frameData" in current context.\ Failed to execute MI command: -var-create - * frameData.15 Error message from debugger back end: mi_cmd_var_create: unable to create variable object\ Unable to create variable object
on this line of code:
if(buildFrame(0x10, 0x01, destinationAddress64Bit, destinationAddress16Bit, frameData, 8, 2, (inputFrameDataLength + 2), &frameArrayPtr, &frameArraySizePtr) == TRUE){
When I run the program completely (it silently fails) and this is my text output:
COMPARE: 10 01 00 13 A2 00 40 9C 26 E1 FF FE 00 00 01 02 03 04 05
OUTPUT PACKET: 01 00 00 00 00 00 00 00 D8 8C 28 03 01 00 00 00 B0 8A 97 5C FF 7F 00 00 08 00 00 00 00 00 00 00 00 8A 97 5C 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 FF 00 00 00 00 00 00 00 00 00 00 FF 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 10 00 00 00 30 00 00 00 90 8A 97 5C FF 7F 00 00 90 89 97 5C FF 7F 00 00 00 00 00 00 00 00 00 00
I suspect the problem is I have a bad pointer (or pointers) in returning the size or the pointer to the character array but I don't know that for sure (or know how to get the program to fail in a way I can determine it).
In buildFrame:
unsigned char outputPacketArray[outputPacketSize];
outputPacketArray is a local variable. Its lifetime ends when you leave the function. However you assign a pointer to it to an output parameter of the function:
*frameArray = outputPacketArray;
(Same for outputPacketSize)
These pointers do not point to valid memory anymore when you leave the function. You need to dynamically allocate the array:
unsigned char* outputPacketArray = malloc(outputPacketSize);
and then free it later. Alternatively you could provide an appropriately sized array to the function, but then you would need to calculate the size already in main.
For the size you don't need a pointer to pointer at all, just return it from the function, or use a simple pointer (instead of double pointer) as output parameter.