Converting a struct to a hex string in C - c

I have the following struct
typedef struct __attribute__((packed)) word {
uint16_t value;
uint8_t flag
} Word;
I want to convert it to a hex string. For example if value = 0xabcd and flag = 0x01 I want to get the string 01abcd
if I do some pointer juggling
Word word;
word.value = 0xabcd;
wordk.flag = 0x01;
printf("word: %X\n", *(int *)&word);
I get the output that I want (word: 1ABCD) but this doesn't seem safe
and when I tried to do this after looking at some of the answer here
char ptr[3];
memcpy(ptr, word, 3);
printf("word: %02X%02X%02X\n", ptr[2], ptr[1], ptr[0]);
I got word: 01FFFFFFABFFFFFFCD, for some reason the first two bytes are being extended to a full int

There's no real gain from messing around with pointers or type-punning, if all you want is to output the values of the two structure members. Just print them individually:
printf("word: %02x%04x\n", (unsigned int)word.flag, (unsigned int)word.value);

Use a simple sprintf to convert to a string:
int main(void)
{
Word v = { 0xabcd, 0x01 };
char s[10];
sprintf(s, "%02x%04x", v.flag, v.value);
puts(s);
}

I want to get the string 01abcd
So you want to print the binary representation of the struct on a little endian machine backwards. There's no obvious advantage of using sprintf for this apart from it being quick & dirty to implement.
If you want something with performance, then hacking this out manually isn't rocket science - simply iterate over the struct byte by byte and convert each nibble to the corresponding hex character:
void stringify (const uint8_t* data, size_t size, char* dst)
{
for(size_t i=0; i<size; i++)
{
uint8_t byte = data[size-i-1]; // read starting from the end of the data
dst[i*2] = "0123456789ABCDEF"[ byte >> 4 ]; // ms nibble
dst[i*2+1] = "0123456789ABCDEF"[ byte & 0xF ]; // ls nibble
}
dst[size*2] = '\0';
}
This will give "01ABCD" on a little endian machine and "01CDAB" on a big endian machine.
(Optionally add restrict to data and dst parameters but I doubt it will improve performance since the const correctness already blocks aliasing at some extent.)

Could join them mathematically first.
printf("word: %06lx\n", wordk.flag * 0x10000L + word.value);
Using long in case we are on a 16-bit int machine.

Related

how to write a uint64_t to a char* buffer in C

So I am trying to write a uint64_t return address to a buffer and then verify that the correct return address got written to the correct spot. Here is my code.
uint64_t new_ret = ret - 8 - 32 - 32 - 1001 + (ret_buffer_offset + sizeof(shellcode));
printf("new_ret :%lu\n", new_ret);
snprintf(&buffer[ret_buffer_offset], 8, "%s", new_ret);
// debug code
char buffer_debug[10];
uint64_t* buffer_uint = (uint64_t*)buffer_debug;
bzero(buffer_debug, 10);
strncpy(buffer_debug, &buffer[ret_buffer_offset], 8);
uint64_t ret_debug = *buffer_uint;
printf("ret debug: %lu\n", ret_debug);
the two printfs should output the same thing, but the bottom printf outputs a very different number. I'm not sure if the way I'm writing to the buffer is wrong or if the way I'm getting the value back is wrong. What is the issue here?
Thanks
snprintf(&buffer[ret_buffer_offset], 8, "%s", new_ret);
buffer now contains the string representation of your original value (or at least the first 8 bytes of the string representation). Your code then takes the first 8 bytes of this string and interprets that binary sequence as if it was a uint64_t. Step through this chunk of code in a debugger and you'll see exactly where the value changes.
I'm not sure exactly what this code is trying to do, but it seems like it's doing more copying and conversion than necessary. If you have a pointer to where you want the value to go, you should be able to either do memcpy(ptr, &new_ret, sizeof(new_ret)) or possibly even *(uint64_t*)ptr = new_ret if your platform allows potentially-misaligned writes. To print out the value for debugging, you'd use printf("%"PRIu64, *(uint64_t*)ptr).
I like to use union, but if you make a char pointer (char*) to point to the address of uint64_t it will work.
Using pointer will be:
uint64_t new_ret = ret - 8 - 32 - 32 - 1001 + (ret_buffer_offset + sizeof(shellcode));
buffer = (char*) &new_ret;
Test the code below to use union and pointer:
#include <stdio.h>
#include <stdint.h>
int main(){
union {
uint64_t u64;
char str[8];
} handler;
handler.u64 = 65;
printf("Using union:\n");
printf(" uint64: %ld\n", handler.u64);
printf(" char*: %s\n", handler.str);
uint64_t u64 = 65;
char *str = (char*)&u64;
printf("Using pointer:\n");
printf(" uint64: %ld\n", u64);
printf(" char*: %s\n", str);
return 0;
}

C - ntohl replacing digits with zero's

In the following program on Little and Big Endians:
char *s = "1234";
printf("%08X\n",*(int *)s); //big endian
int little = ntohl(*s);
printf("%08X\n",little);//Little endian
I get the following output:
34333231
31000000
The second line should be the reverse order of the first line. What am I doing wrong?
I have little experience in C, but some experience in other languages.
You need something like this:
int little = ntohl(*((uint32_t*)s));
otherwise you're only passing a char to ntohl, which is why your value is being truncated.
You are confusing strings and integers
uint32_t i = 12345;
printf("%08X\n", i); /* 00003039 */
i = ntohl(i);
printf("%08X\n", i); /* either 00003039 or 39300000 */
Depending on the endianness of your platform, you either get the same output or a bytewise reversed one.

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 }

sprintf is outputting some strange data

I am working an embedded project which involves reading/writing a struct into EEPROM. I am using sprintf to make it easy to display some debugging information.
There are two problems with this code for some reason. The first; sprintf is printing a very strange output. When I print 'addr++' it will follow a pattern '0, 1, 2, 3, 4, 32, ...' which doesn't make sense.
void ee_read(char * buf, unsigned int addr, unsigned int len) {
unsigned int i;
sprintf(bf1, "Starting EEPROM read of %u bytes.\r\n", len); // Debug output
debugr(bf1);
IdleI2C1();
StartI2C1();
WriteI2C1(EE_ADDR | EE_W);
IdleI2C1();
WriteI2C1((unsigned char)addr>>8); // Address to start reading data from
IdleI2C1();
WriteI2C1((unsigned char)addr&0xFF);
IdleI2C1();
RestartI2C1();
WriteI2C1(EE_ADDR | EE_R);
IdleI2C1();
for (i=0; i<len; i++) {
buf[i] = ReadI2C1(); // Read a byte from EEPROM
sprintf(bf1, "Addr: %u Byte: %c\r\n", addr, buf[i]); // Display the read byte and the address
debugr(bf1);
addr++; // Increment address
IdleI2C1();
if (i == len-1) { // This makes sure the last byte gets 'nAcked'
NotAckI2C1();
} else {
AckI2C1();
}
}
StopI2C1();
}
The output from the above is here: https://gist.github.com/3803316 Please note that the about output was taken with %x for the address value (so addr is hex)
The second problem, which you may have noticed with the output, is that it doesn't stop when i > len. It continues further than the output I have supplied, and doesn't stop until the microcontroller's watch dog restarts.
Edit:
Calling the function
Location loc;
ee_read(&loc, 0, sizeof(Location));
Declarations:
struct location_struct {
char lat[12]; // ddmm.mmmmmm
char latd[2]; // n/s
char lon[13]; // dddmm.mmmmmm
char lond[2]; // e/w
char utc[11]; // hhmmss.sss
char fix[2]; // a/v
};
typedef struct location_struct Location;
char bf1[BUFFER_SIZE];
I don't think it's a race condition. I disable the interrupts which use bf1. Even then, it would corrupt the whole debug string if that happened, and it certainly wouldn't be so repeatable.
Edit
The value of addr starts as zero, which can be seen here: https://gist.github.com/3803411
Edit
What this is supposed to do it copy the location structure byte by byte into the EEPROM, and then recall it when it is needed.
Closure
So I never did solve this problem. The project moved away from the EEPROM, and I have since changed OS, compiler and IDE. It's unlikely I will replicate this problem.
I'll tell you one thing wrong with your code, this line:
(unsigned char)addr>>8
doesn't do what you seem to need.
It converts the value in addr into an unsigned char which (assuming 8-bit char and either 16-bit int or only using the lower 16 bits of a wider int), will will always give you the lower eight bits.
If you then right shift that by eight bits, you'll always end up with zero.
If your intent is to get the upper eight bits of the address, you need to use:
(unsigned char)(addr>>8)
so that the shift is done first.

How to convert an Unsigned Character array into a hexadecimal string in C

Is it possible to represent an unsigned character array as a string?
When I searched for it, I found out that only memset() was able to do this (But character by character).
Assuming that is not the correct way, is there a way to do the conversion?
Context: I am trying to store the output of a cryptographic hash function which happens to be an array of unsigned characters.
eg:
unsigned char data[N]; ...
for(i=0;i<N;i++) printf("%x",data[i]);
My goal is to represent the data as a String (%s) rather than access it by each element. Since I need the output of the hash as a String for further processing.
Thanks!
So, based on your update, are you talking about trying to convert a unsigned char buffer into a hexadecimal interpretation, something like this:
#define bufferSize 10
int main() {
unsigned char buffer[bufferSize]={1,2,3,4,5,6,7,8,9,10};
char converted[bufferSize*2 + 1];
int i;
for(i=0;i<bufferSize;i++) {
sprintf(&converted[i*2], "%02X", buffer[i]);
/* equivalent using snprintf, notice len field keeps reducing
with each pass, to prevent overruns
snprintf(&converted[i*2], sizeof(converted)-(i*2),"%02X", buffer[i]);
*/
}
printf("%s\n", converted);
return 0;
}
Which outputs:
0102030405060708090A
In C, a string is an array of char, terminated with a character whose value is 0.
Whether or not char is a signed or unsigned type is not specified by the language, you have to be explicit and use unsigned char or signed char if you really care.
It's not clear what you mean by "representing" an unsigned character array as string. It's easy enough to cast away the sign, if you want to do something like:
const unsigned char abc[] = { 65, 66,67, 0 }; // ASCII values for 'A', 'B', 'C'.
printf("The English alphabet starts out with '%s'\n", (const char *) abc);
This will work, to printf() there isn't much difference, it will see a pointer to an array of characters and interpret them as a string.
Of course, if you're on a system that doesn't use ASCII, there might creep in cases where doing this won't work. Again, your question isn't very clear.
Well a string in C is nothing else than a few chars one after another. If they are unsigned or signed is not much of a problem, you can easily cast them.
So to get a string out of a unsigned char array all you have to do is to make sure that the last byte is a terminating byte '\0' and then cast this array to char * (or copy it into a array of char)
I successfully use this to convert unsigned char array to std:string
unsigned char array[128];
std::stringstream buffer;
for (int i = 0; i < 128; i++)
{
buffer << std::hex << std::setfill('0');
buffer << std::setw(2) << static_cast<unsigned>(array[i]);
}
std::string hexString = buffer.str();
An example as you've asked:
unsigned char arr [SIZE];

Resources