Concatenate unsigned char * inside a loop - c

I'm using the library OpenSSL for encrypting through AES. Since AES is a block cipher, I need to split the data in chunks of 16 bytes. Thus, if I want to recover the message, I need to unite the chunks at the end of the program.
This is my code:
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <openssl/aes.h>
char key[] = "secretkey123";
int main() {
unsigned char text_slice[128];
unsigned char enc_slice[128];
unsigned char dec_slice[128];
unsigned char in[160];
unsigned char enc_out[160] = "";
unsigned char dec_out[160] = "";
int i;
int k = 10;
for (i = 0; i < 16 * k; i++) {
in[i] = 'A' + (rand() % 26);
}
in[160] = '\0';
printf("IN:%s\n", in);
AES_KEY enc_key, dec_key;
AES_set_encrypt_key(key, 128, &enc_key);
AES_set_decrypt_key(key, 128, &dec_key);
for (i = 0; i < k; i++) {
text_slice[0] = '\0';
enc_slice[0] = "\0";
dec_slice[0] = "\0";
memcpy(&text_slice[0], &in[15 * i], 15);
text_slice[16] = "\0";
printf("TEXT SLICE: %s \n", text_slice);
AES_encrypt(text_slice, enc_slice, &enc_key);
memcpy(&enc_out[16 * i], &enc_slice[0], 16);
}
printf("ENC:%s\n", enc_out);
for (i = 0; i < k; i++) {
text_slice[0] = '\0';
enc_slice[0] = "\0";
dec_slice[0] = "\0";
memcpy(enc_slice, &enc_out[16 * i], 16);
enc_slice[16] = "\0";
AES_decrypt(enc_slice, dec_slice, &dec_key);
printf("Dec slice:%s \n", dec_slice);
memcpy(&dec_out[16 * i], &dec_slice[0], 16);
}
printf("DEC OUT:%s\n", dec_out);
return 0;
}
The output of the program is the following:
IN:NWLRBBMQBHCDARZOWKKYHIDDQSCDXRJMOWFRXSJYBLDBEFSARCBYNECDYGGXXPKLORELLNMPAPQFWKHOPKMCOQHNWNKUEWHSQMGBBUQCLJJIVSWMDKQTBXIXMVTRRBLJPTNSNFWZQFJMAFADRRWSOFSBCNUVQHFF
TEXT SLICE: NWLRBBMQBHCDARZ
TEXT SLICE: OWKKYHIDDQSCDXR
TEXT SLICE: JMOWFRXSJYBLDBE
TEXT SLICE: FSARCBYNECDYGGX
TEXT SLICE: XPKLORELLNMPAPQ
TEXT SLICE: FWKHOPKMCOQHNWN
TEXT SLICE: KUEWHSQMGBBUQCL
TEXT SLICE: JJIVSWMDKQTBXIX
TEXT SLICE: MVTRRBLJPTNSNFW
TEXT SLICE: ZQFJMAFADRRWSOF
ENC:j�Q���
𢨫�7֡���*n���R ��m7�zI#4��=v�#�(��V7��ח9.R�q����:C�%��_��!q��(��l��j�3�1�h��
Dec slice:NWLRBBMQBHCDARZ
Dec slice:OWKKYHIDDQSCDXR
Dec slice:JMOWFRXSJYBLDBE
Dec slice:FSARCBYNECDYGGX
Dec slice:XPKLORELLNMPAPQ
Dec slice:FWKHOPKMCOQHNWN
Dec slice:KUEWHSQMGBBUQCL
Dec slice:JJIVSWMDKQTBXIX
Dec slice:MVTRRBLJPTNSNFW
Dec slice:ZQFJMAFADRRWSOF
DEC OUT:NWLRBBMQBHCDARZ
While dec_slice works as expected, dec_out just get a copy of the memory of the first chunk. What is more surprising for me, is that enc_out performs correctly when following the same logic as dec_out. What am I missing?

The key must have at least 16 bytes since you pass a number of bits equal to 128 in:
AES_set_encrypt_key(key, 128, &enc_key);
AES_set_decrypt_key(key, 128, &dec_key);
You have undefined behavior here:
in[160] = '\0';
These lines don't make sense:
enc_slice[0] = "\0";
dec_slice[0] = "\0";
text_slice[16] = "\0";
enc_slice[16] = "\0";
Why do you encode chunks of 15 characters instead of 16?
memcpy(&text_slice[0], &in[15 * i], 15);
Here is a modified version:
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <openssl/aes.h>
char key[] = "secretkey1234567";
int main() {
unsigned char text_slice[128];
unsigned char enc_slice[128];
unsigned char dec_slice[128];
unsigned char in[160];
unsigned char enc_out[160];
unsigned char dec_out[160];
int i, k = 10;
for (i = 0; i < 16 * k; i++) {
in[i] = 'A' + (rand() % 26);
}
printf("IN: \"%.160s\"\n", (char *)in);
AES_KEY enc_key, dec_key;
AES_set_encrypt_key(key, 128, &enc_key);
AES_set_decrypt_key(key, 128, &dec_key);
for (i = 0; i < k; i++) {
memcpy(text_slice, &in[16 * i], 16);
printf("TEXT SLICE: %.16s\n", (char *)text_slice);
AES_encrypt(text_slice, enc_slice, &enc_key);
memcpy(&enc_out[16 * i], enc_slice, 16);
}
printf("ENC:");
for (i = 0; i < 16 * k; i++) {
printf(" %02X\n", enc_out[i]);
}
printf("\n");
for (i = 0; i < k; i++) {
memcpy(enc_slice, &enc_out[16 * i], 16);
AES_decrypt(enc_slice, dec_slice, &dec_key);
printf("Dec slice: %.16s \n", (char *)dec_slice);
memcpy(&dec_out[16 * i], dec_slice, 16);
}
printf("DEC OUT: \"%.160s\"\n", (char *)dec_out);
return 0;
}

There are many problems in that code.
The AES_set_encrypt_key and AES_set_decrypt_key are not key derivation functions, the second parameter is supposed to represent the length in bits of the first parameter (userKey).
If you provide an arbitrary string constant like "secretkey123" with a length that is not 128 in bits, it may cause memory corruption or create a very insecure context for your encryption.
In general, for user password based encryption, we generate a key from any password using a key derivation function (for example PBKDF2, or scrypt).
This line is also bad:
in[160] = '\0';
Since the buffer has a size of 160, the last index should be 160 - 1. If you write at index 160, you are actually overflowing.
Also, you must really notice the difference between single quote and double quotes when writing C code.
This is bad:
enc_slice[0] = "\0";
dec_slice[0] = "\0";
If you use double quotes, you are not actually writing the value 0 at the first index of enc_slice and dec_slice. You are writing the address of an empty read-only constant string.
Also this:
unsigned char enc_out[160] = "";
unsigned char dec_out[160] = "";
If you want to have empty buffers, you should just do:
unsigned char enc_out[160] = {0};
unsigned char dec_out[160] = {0};
Hopefully this is a good start to improve your code and make it work.

Related

SHA256 and RIPEMD160HASH in c program

I wrote a c program to perform sha256 hash on a char array and then perform ripemd160 hash on the output of sha256 hash function.
here is my code:
#include <stdio.h>
#include <string.h>
#include <openssl/sha.h>
#include <openssl/ripemd.h>
int main(){
int c;
const unsigned char* rawdata = "046EAF0968AA895ADDFEE599566F0B880242461D1377F4887C9B84631E13067B96DB18C41E0C208F8D12EBCC3F99F2522903AF6105833E4CBADE9D6A1D0F039187";
unsigned long n = strlen(rawdata);
unsigned char *d = SHA256(rawdata, strlen(rawdata), 0);
for (c = 0; c < 32; c++){
printf("%02x", d[c]);
}
putchar('\n');
unsigned char md[32];
unsigned char* pmd = RIPEMD160(d, strlen(d), md);
int i;
for (i = 0; i < 20; i++)
printf("%02x", pmd[i]);
putchar('\n');
return 0;
}
the problem is in this line :
unsigned char *d = SHA256(raw-data, strlen(raw-data), 0);
when I pass the d pointer which is the output of the sha256 function to RIPEMD160 function the resulting hash output of RIPEMD160 function becomes wrong. Can anyone tell me why this is happening? And how can correct my code to print and store my ripems160 hash in a char array?
Here is what I have tried:
the resulting hash output of the string "046EAF0968AA895ADDFEE599566F0B880242461D1377F4887C9B84631E13067B96DB18C41E0C208F8D12EBCC3F99F2522903AF6105833E4CBADE9D6A1D0F039187"
is : 37a0df85d5ccf7cb5f92b53aa3f223d76c115a844ed52d8978deecd2ecb3e406
which is correct.
But the ripemd160 hash of "37a0df85d5ccf7cb5f92b53aa3f223d76c115a844ed52d8978deecd2ecb3e406"
should be
"4ecc9d3eea56b0af96b6db612b76911858dcb40d"
but my is wrong.
here is the output of my code when compiled with this command
"gcc sha256.c -lssl -lcrypto -Wno-deprecated-declarations"
output:
37a0df85d5ccf7cb5f92b53aa3f223d76c115a844ed52d8978deecd2ecb3e406
63bb23be08e2c097008c4c272cc56c14e5656831
the second string "63bb23be08e2c097008c4c272cc56c14e5656831" is ripemd160 hash which is wrong
Your problem is on this line:
unsigned char* pmd = RIPEMD160(d, strlen(d), md);
strlen finds the length of a printable string by looking for the terminating \0. But the data in d is binary data. It is not terminated by \0 and may contain that value as part of the data. You should replace strlen(d) with the actual value for the length of a SHA256 hash (32).
Update:
It seems your "correct" output can be achieved by doing some further processing of the SHA256 output. I don't know where you got your test vector from but it seems the expected input into the RIPEMD160 function is the SHA256 output converted into a printable string - and hashing that string.
These modifications seem to achieve the output that you are expecting:
--- doublehash1.c 2020-03-21 00:50:11.882423750 +0000
+++ doublehash.c 2020-03-21 00:49:36.778485523 +0000
## -9,14 +9,16 ##
const unsigned char* rawdata = "046EAF0968AA895ADDFEE599566F0B880242461D1377F4887C9B84631E13067B96DB18C41E0C208F8D12EBCC3F99F2522903AF6105833E4CBADE9D6A1D0F039187";
unsigned long n = strlen(rawdata);
unsigned char *d = SHA256(rawdata, strlen(rawdata), 0);
+ unsigned char data[65], *p;
- for (c = 0; c < 32; c++){
- printf("%02x", d[c]);
+ for (c = 0, p = data; c < 32; c++, p += 2){
+ sprintf(p, "%02x", d[c]);
}
+ printf("%s", data);
putchar('\n');
unsigned char md[32];
- unsigned char* pmd = RIPEMD160(d, strlen(d), md);
+ unsigned char* pmd = RIPEMD160(data, strlen(data), md);
int i;
for (i = 0; i < 20; i++)

How to dynamically center align text in a char * string to fit in a total of 16 spaces in C?

I am trying to center align strings in a total of 16 spaces to eventually print them on a 16x2 LCD Display. The values are grabbed from a database, and put in a global variable that is constantly being updated.
The values in the database are already in string format.
What I'd like to do is after getting the value from the DB, update the global variable to contain a string centered in 16 spaces.
I understand using global variables may not be best practice but ignoring that is there a way to do this?
char * systemInfoValues[5] = {" "," "," "," "," "}
for(int i=0; i< 5; i++){
systemInfoValues[i] = PQgetvalue(res,i,0); //get the value from db;
int len = strlen(systemInfoValues[i]);
char tmp[20];
sprintf(tmp,"%*s", (17-len)/2 + len, systemInfoValues[i]);
strcpy(systemInfoValues[i],tmp);
}
0 = a blank space
xxxxx = string from db
If the length of the string is odd
I expect the output to be [00xxxxxxxxxxxxx0]
if the length of the string is even
I expect the output to be [00xxxxxxxxxxxx00]
It is simple 6 line function. symetry is giving you the option
char *centerinstring(char *buff, size_t len, const char *str, int symetry)
{
size_t strl = strlen(str);
size_t pos = (len - strl) / 2 + (strl & 1) * !!symetry;
memset(buff,' ', len);
buff[len] = 0;
memmove(buff + pos, str, strl);
return buff;
}
int main()
{
char buff[11];
printf("|%s|\n", centerinstring(buff, 10, "1234567", 1));
printf("|%s|\n", centerinstring(buff, 10, "1234567", 0));
return 0;
}
or with the option to allocate memory for the buff (if you pass NULL
char *centerinstring(char *buff, size_t len, const char *str, int symetry)
{
size_t strl = strlen(str);
size_t pos = strl / 2 + (strl & 1) * !!symetry;
buff = buff ? malloc(len + 1) : buff;
if(buff)
{
memset(buff,' ', len);
buff[len] = 0;
memmove(buff + pos, str, strl);
}
return buff;
}
sprintf()-comfort:
#include <assert.h>
#include <string.h>
#include <stdio.h>
void center(char *dst, char *src, size_t width)
{
assert(dst && src && width);
size_t src_len = strlen(src);
if (src_len >= width) {
*dst = '\0';
return;
}
int right = (int)(width - src_len) / 2;
int left = right + (int)src_len;
right -= (src_len & 1);
sprintf(dst, "%*s%*s", left, src, right, "");
}
int main(void)
{
char destination[17];
center(destination, "12345678901234", sizeof(destination));
printf("\"%s\"\n", destination);
}
You can do it in another way (without using the sprintf function).
I don't know about any interface of the sprintf function that would allow you to do it, but you can solve the problem using simple strcpy of variables.
This is a main program that would solve your problem, it is documented in itself, so you should be able to understand how to apply this to your code:
#include <stdio.h>
#include <string.h>
/* This simple program would transfer the original string that is in the
* out_value to be centralized in this variable. */
int main(void) {
char out_value[17] = "1234567891";
char temp[20] = {0};
int first_index = 0;
int string_length = 0;
/* Copy the string to the temp variable, to modify the chars in
* out_value. */
strcpy(temp, out_value);
/* Find out the index for the first char to be placed in the centralized
* string. */
string_length = strlen(temp);
first_index = (16 - string_length) / 2;
/* Set all the values of the out_value to be the wanted value of space (here
* it is 0 for visualizing, it can be space to not be present). */
memset(out_value, '0', 16);
/* Copy the original string back, moving the start of it, so it would be
* centralized. */
strncpy(&(out_value[first_index]), temp, string_length);
/* Print the string. */
printf("%s", out_value);
}
When modifying your code to work with this, the code would look something like this:
char * systemInfoValues[5] = {NULL}
for(int i=0; i< 5; i++){
systemInfoValues[i] = PQgetvalue(res,i,0); //get the value from db;
int len = strlen(systemInfoValues[i]);
char tmp[20];
int first_index = 0;
strcpy(tmp, systemInfoValues[i]);
first_index = (16 - len) / 2;
memset(systemInfoValues[i], ' ', 16);
strncpy(&(systemInfoValues[i][first_index]), tmp, len);
}
Note that I changed the initializing of the value of systemInfoValues. When you initialized it, you put empty strings there. Note that this is a bad habit. Putting empty strings there (or strings with a single space) would allocate the memory for this string (which you will never use).
You didn't include the definition to the function of PQgetvalue, but assuming that it would return a char pointer, this should work.
But, this code would change the global value as well. If you don't want to change it, you shoudn't put the result there, but copy the result to the string before doing any changes to it.
After modifying the code, it should look like this:
char systemInfoValues[5][17] = {{0}}
for(int i=0; i< 5; i++){
char *global_reference = PQgetvalue(res,i,0); //get the value from db;
int len = strlen(systemInfoValues[i]);
char tmp[20];
int first_index = 0;
strcpy(tmp, global_reference);
first_index = (16 - len) / 2;
memset(systemInfoValues[i], ' ', 16);
strncpy(&(systemInfoValues[i][first_index]), tmp, len);
}
edit: apperently there is an interface for the sprintf function to work (as you originally wanted). To see it, refer to the answer of Swordfish

C - converting hex to string

Following on an old question Converting hex to string in C?
The approved answer suggests to use sprintf to convert each hex to string.
I have two question on this -
1) When i have a hex like 0a i want my string to have 0a too, but following the above solution the result will have a.
2) What am i doing wrong here?
#include <stdio.h>
int main(void)
{
unsigned char readingreg[10];
readingreg[0] = 0x4a;
readingreg[1] = 0xab;
readingreg[2] = 0xab;
readingreg[3] = 0x0a;
readingreg[4] = 0x40;
unsigned char temp[10];
int i = 0;
while (i < 5)
{
sprintf(temp + i, "%x", readingreg[i]);
i++;
}
printf("String: %s\n", temp);
return 0;
}
The o/p seems to - String: 4aaa40
3) Combining both the both questions, i want my result string to be 4aabab0a40
TIA
Your code has several problems.
First unsigned char temp[10]; should be unsigned char temp[11]; to contain a string terminator.
Next is the format spec "%x" should be "%02x" so each value is 2 digits.
Then temp + i should be temp + i*2 so each pair of digits is written in the right place.
Correcting those mistakes:
#include <stdio.h>
int main(void)
{
unsigned char readingreg[10];
readingreg[0] = 0x4a;
readingreg[1] = 0xab;
readingreg[2] = 0xab;
readingreg[3] = 0x0a;
readingreg[4] = 0x40;
unsigned char temp[11];
int i = 0;
while (i < 5)
{
sprintf(temp + i*2, "%02x", readingreg[i]);
i++;
}
printf("String: %s\n", temp);
return 0;
}
Program output is now the required
String: 4aabab0a40

How to fill a string with random (hex) characters?

I have a string (unsigned char) and i want to fill it with only hex characters.
my code is
unsigned char str[STR_LEN] = {0};
for(i = 0;i<STR_LEN;i++) {
sprintf(str[i],"%x",rand()%16);
}
Of course, when running this I get segfaulted
string is an array of char-s not unsigned char-s
you are using str[i] (which is of type unsigned char) as a 1st argument to sprintf, but it requires type char * (pointer).
This should be a little better:
char str[STR_LEN + 1];
for(i = 0; i < STR_LEN; i++) {
sprintf(str + i, "%x", rand() % 16);
}
The first argument to sprintf() should be a char*, but str[i] is a char: this is the cause of the segmentation fault. The compiler should have emitted a warning about this. gcc main.c, without specifying a high warning level, emitted the following:
warning: passing argument 1 of sprintf makes pointer from integer without a cast
A hex representation of a character can be 1 or 2 characters (9 or AB for example). For formatting, set the precision to 2 and the fill character to 0. Also need to add one character for the terminating null to str and set the step of the for loop to 2 instead of 1 (to prevent overwriting previous value):
unsigned char str[STR_LEN + 1] = {0};
int i;
for (i = 0; i < STR_LEN; i += 2)
{
sprintf(&str[i], "%02X", rand() % 16);
}
You could try something like this:
#include <stdio.h>
#include <stdlib.h>
#define STR_LEN 20
int main(void)
{
unsigned char str[STR_LEN + 1] = {0};
const char *hex_digits = "0123456789ABCDEF";
int i;
for( i = 0 ; i < STR_LEN; i++ ) {
str[i] = hex_digits[ ( rand() % 16 ) ];
}
printf( "%s\n", str );
return 0;
}
There are several unclarities and problems in your code. I interpret "hex character" to mean "hex digit", i.e. a symbol from {0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f}, not "the hexadecimal value of an ascii character's code point". This might or might not be what you meant.
This should do it:
void hex_fill(char *buf, size_t max)
{
static const char hexdigit[16] = "0123456789abcdef";
if(max < 1)
return;
--max;
for(i = 0; i < max; ++i)
buf[i] = hexdigit[rand() % sizeof hexdigit];
buf[max] = '\0';
}
The above will always 0-terminate the string, so there's no requirement that you do so in advance. It will properly handle all buffer sizes.
My variation on some of answers below; note the time seeded rand function and instead of a char using a const size, I use a vector that is then converted to a string array.
Boost variate generator docs
std::string GetRandomHexString(unsigned int count)
{
std::vector<char> charVect = std::vector<char>(count);
//Rand generator
typedef boost::random::mt19937 RNGType;
RNGType rng(std::time(nullptr) + (unsigned int)clock());
//seeding rng
uniform_int<> range(0, 15); //Setting min max
boost::variate_generator<RNGType, boost::uniform_int<> >generate(rng, range); //Creating our generator
//Explicit chars to sample from
const char hexChars[16] = { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' };
//
for (int i = 0; i < count; i++)
{
charVect[i] = hexChars[generate()];
}
//
return std::string(charVect.begin(), charVect.end());;
}
Examples (count = 32):
1B62C49C416A623398B89A55EBD3E9AC
26CFD2D1C14B9F475BF99E4D537E2283
B8709C1E87F673957927A7F752D0B82A
DFED20E9C957C4EEBF4661E7F7A58460
4F86A631AE5A05467BA416C4854609F8

How do you convert a byte array to a hexadecimal string in C?

I have:
uint8 buf[] = {0, 1, 10, 11};
I want to convert the byte array to a string such that I can print the string using printf:
printf("%s\n", str);
and get (the colons aren't necessary):
"00:01:0A:0B"
Any help would be greatly appreciated.
printf("%02X:%02X:%02X:%02X", buf[0], buf[1], buf[2], buf[3]);
For a more generic way:
int i;
for (i = 0; i < x; i++)
{
if (i > 0) printf(":");
printf("%02X", buf[i]);
}
printf("\n");
To concatenate to a string, there are a few ways you can do this. I'd probably keep a pointer to the end of the string and use sprintf. You should also keep track of the size of the array to make sure it doesn't get larger than the space allocated:
int i;
char* buf2 = stringbuf;
char* endofbuf = stringbuf + sizeof(stringbuf);
for (i = 0; i < x; i++)
{
/* i use 5 here since we are going to add at most
3 chars, need a space for the end '\n' and need
a null terminator */
if (buf2 + 5 < endofbuf)
{
if (i > 0)
{
buf2 += sprintf(buf2, ":");
}
buf2 += sprintf(buf2, "%02X", buf[i]);
}
}
buf2 += sprintf(buf2, "\n");
For completude, you can also easily do it without calling any heavy library function (no snprintf, no strcat, not even memcpy). It can be useful, say if you are programming some microcontroller or OS kernel where libc is not available.
Nothing really fancy you can find similar code around if you google for it. Really it's not much more complicated than calling snprintf and much faster.
#include <stdio.h>
int main(){
unsigned char buf[] = {0, 1, 10, 11};
/* target buffer should be large enough */
char str[12];
unsigned char * pin = buf;
const char * hex = "0123456789ABCDEF";
char * pout = str;
int i = 0;
for(; i < sizeof(buf)-1; ++i){
*pout++ = hex[(*pin>>4)&0xF];
*pout++ = hex[(*pin++)&0xF];
*pout++ = ':';
}
*pout++ = hex[(*pin>>4)&0xF];
*pout++ = hex[(*pin)&0xF];
*pout = 0;
printf("%s\n", str);
}
Here is another slightly shorter version. It merely avoid intermediate index variable i and duplicating laste case code (but the terminating character is written two times).
#include <stdio.h>
int main(){
unsigned char buf[] = {0, 1, 10, 11};
/* target buffer should be large enough */
char str[12];
unsigned char * pin = buf;
const char * hex = "0123456789ABCDEF";
char * pout = str;
for(; pin < buf+sizeof(buf); pout+=3, pin++){
pout[0] = hex[(*pin>>4) & 0xF];
pout[1] = hex[ *pin & 0xF];
pout[2] = ':';
}
pout[-1] = 0;
printf("%s\n", str);
}
Below is yet another version to answer to a comment saying I used a "trick" to know the size of the input buffer. Actually it's not a trick but a necessary input knowledge (you need to know the size of the data that you are converting). I made this clearer by extracting the conversion code to a separate function. I also added boundary check code for target buffer, which is not really necessary if we know what we are doing.
#include <stdio.h>
void tohex(unsigned char * in, size_t insz, char * out, size_t outsz)
{
unsigned char * pin = in;
const char * hex = "0123456789ABCDEF";
char * pout = out;
for(; pin < in+insz; pout +=3, pin++){
pout[0] = hex[(*pin>>4) & 0xF];
pout[1] = hex[ *pin & 0xF];
pout[2] = ':';
if (pout + 3 - out > outsz){
/* Better to truncate output string than overflow buffer */
/* it would be still better to either return a status */
/* or ensure the target buffer is large enough and it never happen */
break;
}
}
pout[-1] = 0;
}
int main(){
enum {insz = 4, outsz = 3*insz};
unsigned char buf[] = {0, 1, 10, 11};
char str[outsz];
tohex(buf, insz, str, outsz);
printf("%s\n", str);
}
Similar answers already exist above, I added this one to explain how the following line of code works exactly:
ptr += sprintf(ptr, "%02X", buf[i])
It's quiet tricky and not easy to understand, I put the explanation in the comments below:
uint8 buf[] = {0, 1, 10, 11};
/* Allocate twice the number of bytes in the "buf" array because each byte would
* be converted to two hex characters, also add an extra space for the terminating
* null byte.
* [size] is the size of the buf array */
char output[(size * 2) + 1];
/* pointer to the first item (0 index) of the output array */
char *ptr = &output[0];
int i;
for (i = 0; i < size; i++) {
/* "sprintf" converts each byte in the "buf" array into a 2 hex string
* characters appended with a null byte, for example 10 => "0A\0".
*
* This string would then be added to the output array starting from the
* position pointed at by "ptr". For example if "ptr" is pointing at the 0
* index then "0A\0" would be written as output[0] = '0', output[1] = 'A' and
* output[2] = '\0'.
*
* "sprintf" returns the number of chars in its output excluding the null
* byte, in our case this would be 2. So we move the "ptr" location two
* steps ahead so that the next hex string would be written at the new
* location, overriding the null byte from the previous hex string.
*
* We don't need to add a terminating null byte because it's been already
* added for us from the last hex string. */
ptr += sprintf(ptr, "%02X", buf[i]);
}
printf("%s\n", output);
Here is a method that is way way faster :
#include <stdlib.h>
#include <stdio.h>
unsigned char * bin_to_strhex(const unsigned char *bin, unsigned int binsz,
unsigned char **result)
{
unsigned char hex_str[]= "0123456789abcdef";
unsigned int i;
if (!(*result = (unsigned char *)malloc(binsz * 2 + 1)))
return (NULL);
(*result)[binsz * 2] = 0;
if (!binsz)
return (NULL);
for (i = 0; i < binsz; i++)
{
(*result)[i * 2 + 0] = hex_str[(bin[i] >> 4) & 0x0F];
(*result)[i * 2 + 1] = hex_str[(bin[i] ) & 0x0F];
}
return (*result);
}
int main()
{
//the calling
unsigned char buf[] = {0,1,10,11};
unsigned char * result;
printf("result : %s\n", bin_to_strhex((unsigned char *)buf, sizeof(buf), &result));
free(result);
return 0
}
Solution
Function btox converts arbitrary data *bb to an unterminated string *xp of n hexadecimal digits:
void btox(char *xp, const char *bb, int n)
{
const char xx[]= "0123456789ABCDEF";
while (--n >= 0) xp[n] = xx[(bb[n>>1] >> ((1 - (n&1)) << 2)) & 0xF];
}
Example
#include <stdio.h>
typedef unsigned char uint8;
void main(void)
{
uint8 buf[] = {0, 1, 10, 11};
int n = sizeof buf << 1;
char hexstr[n + 1];
btox(hexstr, buf, n);
hexstr[n] = 0; /* Terminate! */
printf("%s\n", hexstr);
}
Result: 00010A0B.
Live: Tio.run.
I just wanted to add the following, even if it is slightly off-topic (not standard C), but I find myself looking for it often, and stumbling upon this question among the first search hits. The Linux kernel print function, printk, also has format specifiers for outputting array/memory contents "directly" through a singular format specifier:
https://www.kernel.org/doc/Documentation/printk-formats.txt
Raw buffer as a hex string:
%*ph 00 01 02 ... 3f
%*phC 00:01:02: ... :3f
%*phD 00-01-02- ... -3f
%*phN 000102 ... 3f
For printing a small buffers (up to 64 bytes long) as a hex string with
certain separator. For the larger buffers consider to use
print_hex_dump().
... however, these format specifiers do not seem to exist for the standard, user-space (s)printf.
This is one way of performing the conversion:
#include<stdio.h>
#include<stdlib.h>
#define l_word 15
#define u_word 240
char *hex_str[]={"0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F"};
main(int argc,char *argv[]) {
char *str = malloc(50);
char *tmp;
char *tmp2;
int i=0;
while( i < (argc-1)) {
tmp = hex_str[*(argv[i]) & l_word];
tmp2 = hex_str[*(argv[i]) & u_word];
if(i == 0) { memcpy(str,tmp2,1); strcat(str,tmp);}
else { strcat(str,tmp2); strcat(str,tmp);}
i++;
}
printf("\n********* %s *************** \n", str);
}
Slightly modified Yannith version.
It is just I like to have it as a return value
typedef struct {
size_t len;
uint8_t *bytes;
} vdata;
char* vdata_get_hex(const vdata data)
{
char hex_str[]= "0123456789abcdef";
char* out;
out = (char *)malloc(data.len * 2 + 1);
(out)[data.len * 2] = 0;
if (!data.len) return NULL;
for (size_t i = 0; i < data.len; i++) {
(out)[i * 2 + 0] = hex_str[(data.bytes[i] >> 4) & 0x0F];
(out)[i * 2 + 1] = hex_str[(data.bytes[i] ) & 0x0F];
}
return out;
}
This function is suitable where user/caller wants hex string to be put in a charactee array/buffer. With hex string in a character buffer, user/caller can use its own macro/function to display or log it to any place it wants (e.g. to a file). This function also allows caller to control number of (hex) bytes to put in each line.
/**
* #fn
* get_hex
*
* #brief
* Converts a char into bunary string
*
* #param[in]
* buf Value to be converted to hex string
* #param[in]
* buf_len Length of the buffer
* #param[in]
* hex_ Pointer to space to put Hex string into
* #param[in]
* hex_len Length of the hex string space
* #param[in]
* num_col Number of columns in display hex string
* #param[out]
* hex_ Contains the hex string
* #return void
*/
static inline void
get_hex(char *buf, int buf_len, char* hex_, int hex_len, int num_col)
{
int i;
#define ONE_BYTE_HEX_STRING_SIZE 3
unsigned int byte_no = 0;
if (buf_len <= 0) {
if (hex_len > 0) {
hex_[0] = '\0';
}
return;
}
if(hex_len < ONE_BYTE_HEX_STRING_SIZE + 1)
{
return;
}
do {
for (i = 0; ((i < num_col) && (buf_len > 0) && (hex_len > 0)); ++i )
{
snprintf(hex_, hex_len, "%02X ", buf[byte_no++] & 0xff);
hex_ += ONE_BYTE_HEX_STRING_SIZE;
hex_len -=ONE_BYTE_HEX_STRING_SIZE;
buf_len--;
}
if (buf_len > 1)
{
snprintf(hex_, hex_len, "\n");
hex_ += 1;
}
} while ((buf_len) > 0 && (hex_len > 0));
}
Example:
Code
#define DATA_HEX_STR_LEN 5000
char data_hex_str[DATA_HEX_STR_LEN];
get_hex(pkt, pkt_len, data_hex_str, DATA_HEX_STR_LEN, 16);
// ^^^^^^^^^^^^ ^^
// Input byte array Number of (hex) byte
// to be converted to hex string columns in hex string
printf("pkt:\n%s",data_hex_str)
OUTPUT
pkt:
BB 31 32 00 00 00 00 00 FF FF FF FF FF FF DE E5
A8 E2 8E C1 08 06 00 01 08 00 06 04 00 01 DE E5
A8 E2 8E C1 67 1E 5A 02 00 00 00 00 00 00 67 1E
5A 01
You can solve with snprintf and malloc.
char c_buff[50];
u8_number_val[] = { 0xbb, 0xcc, 0xdd, 0x0f, 0xef, 0x0f, 0x0e, 0x0d, 0x0c };
char *s_temp = malloc(u8_size * 2 + 1);
for (uint8_t i = 0; i < u8_size; i++)
{
snprintf(s_temp + i * 2, 3, "%02x", u8_number_val[i]);
}
snprintf(c_buff, strlen(s_temp)+1, "%s", s_temp );
printf("%s\n",c_buff);
free(s);
OUT:
bbccdd0fef0f0e0d0c
There's no primitive for this in C. I'd probably malloc (or perhaps alloca) a long enough buffer and loop over the input. I've also seen it done with a dynamic string library with semantics (but not syntax!) similar to C++'s ostringstream, which is a plausibly more generic solution but it may not be worth the extra complexity just for a single case.
ZincX's solution adapted to include colon delimiters:
char buf[] = {0,1,10,11};
int i, size = sizeof(buf) / sizeof(char);
char *buf_str = (char*) malloc(3 * size), *buf_ptr = buf_str;
if (buf_str) {
for (i = 0; i < size; i++)
buf_ptr += sprintf(buf_ptr, i < size - 1 ? "%02X:" : "%02X\0", buf[i]);
printf("%s\n", buf_str);
free(buf_str);
}
I'll add the C++ version here for anyone who is interested.
#include <iostream>
#include <iomanip>
inline void print_bytes(char const * buffer, std::size_t count, std::size_t bytes_per_line, std::ostream & out) {
std::ios::fmtflags flags(out.flags()); // Save flags before manipulation.
out << std::hex << std::setfill('0');
out.setf(std::ios::uppercase);
for (std::size_t i = 0; i != count; ++i) {
auto current_byte_number = static_cast<unsigned int>(static_cast<unsigned char>(buffer[i]));
out << std::setw(2) << current_byte_number;
bool is_end_of_line = (bytes_per_line != 0) && ((i + 1 == count) || ((i + 1) % bytes_per_line == 0));
out << (is_end_of_line ? '\n' : ' ');
}
out.flush();
out.flags(flags); // Restore original flags.
}
It will print the hexdump of the buffer of length count to std::ostream out (you can make it default to std::cout). Every line will contain bytes_per_line bytes, each byte is represented using uppercase two digit hex. There will be a space between bytes. And at end of line or end of buffer it will print a newline. If bytes_per_line is set to 0, then it will not print new_line. Try for yourself.
For simple usage I made a function that encodes the input string (binary data):
/* Encodes string to hexadecimal string reprsentation
Allocates a new memory for supplied lpszOut that needs to be deleted after use
Fills the supplied lpszOut with hexadecimal representation of the input
*/
void StringToHex(unsigned char *szInput, size_t size_szInput, char **lpszOut)
{
unsigned char *pin = szInput;
const char *hex = "0123456789ABCDEF";
size_t outSize = size_szInput * 2 + 2;
*lpszOut = new char[outSize];
char *pout = *lpszOut;
for (; pin < szInput + size_szInput; pout += 2, pin++)
{
pout[0] = hex[(*pin >> 4) & 0xF];
pout[1] = hex[*pin & 0xF];
}
pout[0] = 0;
}
Usage:
unsigned char input[] = "This is a very long string that I want to encode";
char *szHexEncoded = NULL;
StringToHex(input, strlen((const char *)input), &szHexEncoded);
printf(szHexEncoded);
// The allocated memory needs to be deleted after usage
delete[] szHexEncoded;
Based on Yannuth's answer but simplified.
Here, length of dest[] is implied to be twice of len, and its allocation is managed by the caller.
void create_hex_string_implied(const unsigned char *src, size_t len, unsigned char *dest)
{
static const unsigned char table[] = "0123456789abcdef";
for (; len > 0; --len)
{
unsigned char c = *src++;
*dest++ = table[c >> 4];
*dest++ = table[c & 0x0f];
}
}
I know this question already has an answer but I think my solution could help someone.
So, in my case I had a byte array representing the key and I needed to convert this byte array to char array of hexadecimal values in order to print it out in one line. I extracted my code to a function like this:
char const * keyToStr(uint8_t const *key)
{
uint8_t offset = 0;
static char keyStr[2 * KEY_SIZE + 1];
for (size_t i = 0; i < KEY_SIZE; i++)
{
offset += sprintf(keyStr + offset, "%02X", key[i]);
}
sprintf(keyStr + offset, "%c", '\0');
return keyStr;
}
Now, I can use my function like this:
Serial.print("Public key: ");
Serial.println(keyToStr(m_publicKey));
Serial object is part of Arduino library and m_publicKey is member of my class with the following declaration uint8_t m_publicKey[32].
If you want to store the hex values in a char * string, you can use snprintf. You need to allocate space for all the printed characters, including the leading zeros and colon.
Expanding on Mark's answer:
char str_buf* = malloc(3*X + 1); // X is the number of bytes to be converted
int i;
for (i = 0; i < x; i++)
{
if (i > 0) snprintf(str_buf, 1, ":");
snprintf(str_buf, 2, "%02X", num_buf[i]); // need 2 characters for a single hex value
}
snprintf(str_buf, 2, "\n\0"); // dont forget the NULL byte
So now str_buf will contain the hex string.
What complex solutions!
Malloc and sprints and casts oh my. (OZ quote)
and not a single rem anywhere. Gosh
How about something like this?
main()
{
// the value
int value = 16;
// create a string array with a '\0' ending ie. 0,0,0
char hex[]= {0,0,'\0'};
char *hex_p=hex;
//a working variable
int TEMP_int=0;
// get me how many 16s are in this code
TEMP_int=value/16;
// load the first character up with
// 48+0 gives you ascii 0, 55+10 gives you ascii A
if (TEMP_int<10) {*hex_p=48+TEMP_int;}
else {*hex_p=55+TEMP_int;}
// move that pointer to the next (less significant byte)<BR>
hex_p++;
// get me the remainder after I have divied by 16
TEMP_int=value%16;
// 48+0 gives you ascii 0, 55+10 gives you ascii A
if (TEMP_int<10) {*hex_p=48+TEMP_int;}
else {*hex_p=55+TEMP_int;}
// print the result
printf("%i , 0x%s",value,hex);
}

Resources