MD4 hash with openssl, save result into char array - c

I wrote a simple example with openssl in C. I wanted to compute MD4 hash from my message but I want to save result into a char array. Heres my code with comments which will help you understand what I want to achieve:
#include <string.h>
#include <openssl/md4.h>
#include <stdio.h>
int main()
{
unsigned char digest[MD4_DIGEST_LENGTH];
char string[] = "hello world";
// run md4 for my msg
MD4((unsigned char*)&string, strlen(string), (unsigned char*)&digest);
// save md4 result into char array - doesnt work
char test[MD4_DIGEST_LENGTH];
sprintf(test, "%02x", (unsigned int)digest);
for(int i = 0; i < MD4_DIGEST_LENGTH; i++)
printf("%02x", test[i]);
printf("\n\n");
// print out md4 result - works, but its not intochar array as I wanted it to be
for(int i = 0; i < MD4_DIGEST_LENGTH; i++)
printf("%02x", digest[i]);
printf("\n\n");
// works but i dont understand why 'mdString' is 33 size
char mdString[33];
for(int i = 0; i < MD4_DIGEST_LENGTH; i++)
// and I also dont get i*2 in this loop
sprintf(&mdString[i*2], "%02x", (unsigned int)digest[i]);
printf("md4 digest: %s\n", mdString);
return 0;
}
The question is, why this code below doesnt work, it shows different md4 value than it should be:
char test[MD4_DIGEST_LENGTH];
sprintf(test, "%02x", (unsigned int)digest);
for(int i = 0; i < MD4_DIGEST_LENGTH; i++)
printf("%02x", test[i]);
printf("\n\n");
and how can I know what size should be mdString and why is there i*2 in the last loop? Can anybody explain this?

Firstly, your call to MD4() provides an incorrect address for the string and digest arrays: by using &, you are getting the array's address (char **), not the address of the first character.
Since you are explicitly casting &string and &digest to unsigned char*, the compiler won't warn you. Remove the casts, and you will receive this warning:
warning: passing argument 1 of 'MD4' from incompatible pointer type
So instead call MD4() this way:
MD4(string, strlen(string), digest);
I personally prefer to avoid explicitly casting pointers unless it is really necessary, that way you will catch incorrect type casting much more easily.
Next, you attempt to use sprintf() to convert digest to a hexadecimal integer: sprintf(test, "%02x", (unsigned int)digest);.
Two things wrong here: (a) since digest is essentially a character pointer, ie: memory address, you're turning this address into an unsigned integer and then turning that integer into a hex; (b) you need to loop over the elements of digest and convert each one into a character, snprintf won't do this for you!
I see that you may be relatively new to C given the mistakes made, but don't dispair, making mistakes is the way to learn! :)
If you can afford the book, I highly recommend "C Primer Plus" by Stephen Prata. It's a great intro for anyone starting out programming and it's a very complete reference for later use when you are already comfortable with the language.
Otherwise, there is plenty of material online, and googling "C pointer tutorial" will return several useful results.
Hope this helps!
EDIT:
Forgot to comment about the other snippet of code that does work, but uses 33 bytes to store the string-ized MD4 hash:
// works but i dont understand why 'mdString' is 33 size
char mdString[33];
for(int i = 0; i < MD4_DIGEST_LENGTH; i++)
// and I also dont get i*2 in this loop
sprintf(&mdString[i*2], "%02x", (unsigned int)digest[i]);
printf("md4 digest: %s\n", mdString);
The openssl manpage for MD4() states that the hash is 16 bytes long.
Knowing this, and the fact that each unsigned char can hold a value from 0 to 255, then the maximum hexadecimal representation for any individual element in digest is 0xFF, in other words, 2 ASCII characters per unsigned char.
The reason the size for msString (33) appears cryptic is because MD4_DIGEST_LENGTH should have been used to calculate the size of the array: you need 2 characters to represent each one of the elements in digest + 1 null terminator ('\0') to end the string:
char mdString[(MD4_DIGEST_LENGTH * 2) + 1];
sprintf will print 2 characters to the mdString array whenever it's fed 1 byte from digest, so you need to advance 2 index positions in mdString for each position in digest, hence the use of i * 2. The following produces the same result as using i * 2:
for(int i = 0, j = 0; i < MD4_DIGEST_LENGTH; i++, j += 2)
sprintf(&mdString[j], "%02x", (unsigned int)digest[i]);

Related

Why am I geting floating point exception?

This program worked fine when i manually iterated over 5 individual variables but when I substituted them for those arrays and for loop, I started getting floating point exceptions. I have tried debugging but i can't find were the error comes out from.
#include <stdio.h>
int main(void) {
long int secIns;
int multiplicadors[4] = {60, 60, 24, 7};
int variables[5];
int i;
printf("insereix un aquantitat entera de segons: \n");
scanf("%ld", &secIns);
variables[0] = secIns;
for (i = 1; i < sizeof variables; i++) {
variables[i] = variables[i - 1]/multiplicadors[i - 1];
variables[i - 1] -= variables[i]*multiplicadors[i - 1];
}
printf("\n%ld segons són %d setmanes %d dies %d hores %d minuts %d segons\n", secIns, variables[4], variables[3], variables[2], variables[1], variables[0]);
return 0;
}
The problem is you're iterating past the ends of your arrays. The reason is that your sizeof expression isn't what you want. sizeof returns the size in bytes, not the number of elements.
To fix it, change the loop to:
for (i = 1; i < sizeof(variables)/sizeof(*variables); i++) {
On an unrelated note, you might consider changing secIns from long int to int, since it's being assigned to an element of an int array, so the added precision isn't really helping.
Consider this line of code:
for (i = 1; i < sizeof variables; i++) {
sizeof isn't doing what you think it's doing. You've declared an array of 5 ints. In this case, ints are 32-bit, which means they each use 4 bytes of memory. If you print the output of sizeof variables you'll get 20 because 4 * 5 = 20.
You'd need to divide the sizeof variables by the size of its first element.
As mentioned before, sizeOf returns the size of bytes the array holds.
Unlike java's .length that returns the actual length of the array. Takes a little bit more of knowledge with bytes when it comes to C.
https://www.geeksforgeeks.org/data-types-in-c/
This link tells you a bit more about data types and the memory(bytes) they take up.
You could also do sizeOf yourArrayName/sizeOf (int). sizeOf(datatype) returns the size of bytes the data type takes up.
sizeof will give the size (in bytes) of the variables and will yield different results depending on the data type.
Try:
for (i = 1; i < 5; i++) {
...
}

Copy 16 bits hash on 32 bits array

I have a problem with my use of sprintf and strcat. Here's my code :
unsigned char hashResults[8][16];
unsigned char tmp[2];
unsigned char hash[8][32];
transformation("toto", 4, hashResults);
for (int k = 0; k < 8; ++k)
{
for (int i = 0; i < 16; ++i)
{
sprintf(tmp,"%2.2x",hashResults[k][i]);
strcat(hash[k],tmp);
}
printf("%d \n%s\n", strlen(hash[k]), hash[k]);
}
printf("Test : %s\n", hash[3]);
The function transformation() gives me 8 hashes on 16 bits.
I use sprintf and strcat to get hash on 32 bits. When I try to read all hash[k], strlen(hash[8]) returns to me 32 (it's correct), and the string is correct too.
But, when I try to read hash[3] outside the loop it contains all values after it.
For example, the output of my program :
32 - 4a18e332afba75b9734e875323f452f8
32 - b96833277faf31a5915c769f44634506
32 - f89f6dd8cd5aee79de3b2c0c27cafe2e
32 - c9f629472c862c1e7542f4cb2835d02b
32 - 09fc12cfb0a81a38513dbd5edff19e52
32 - 35564354793555a3ae1382f647044445
Test : b96833277faf31a5915c769f44634506f89f6dd8cd5aee79de3b2c0c27cafe2ec9f629472c862c1e7542f4cb2835d02b09fc12cfb0a81a38513dbd5edff19e5235564354793555a3ae1382f647044445
Does anyone see the problem? I wish to use these hashes to compare them to others hashes.
You should increase unsigned char tmp[2] to unsigned char tmp[3] and unsigned char hash[8][32] to unsigned char hash[8][33];
One problem is sprintf(tmp,"%2.2x",hashResults[k][i]), because it writes two characters + '\0' which takes three elements in the array tmp.
But the biggest problem is strcat(hash[k],tmp);.
At the end of every inner for loop you have written in the hash[k] arrays 33 characters(32 chars + '\0'). What happens is when you populate one of the hash[k] arrays in the inner for loop you also write \0' to the first element in the next array, that's why printf("%d \n%s\n", strlen(hash[k]), hash[k]); prints correct results. That misleads you to believing you have null terminated the hash[k] arrays. Now when you enter the next inner for loop you override the null you have written to this array the previous time you exited the inner for loop, no longer terminating the previous array.
So you null terminate your hash[k] array by writing zero to the first element of the hash[k+1] array on the exit of the inner for loop. Then you override this null value every time you enter the inner for loop.
In the end you have no terminating nulls in your arrays and only the final null on the last array is there.
I wonder how do you even get this to work every time, because you write the terminating null beyond the array size which leads to undefined behavior.
Making tmp[3] and hash[8][33] should fix your problem.
In order for the strcat() function to work properly you have to have at least one null in the array you are concatenating to, because otherwise it wouldn't know where to concatenate to. You have to add hash[k][0] = 0; before entering every inner loop:
for (int k = 0; k < 8; ++k)
{
hash[k][0] = 0;
for (int i = 0; i < 16; ++i)
{
sprintf(tmp,"%2.2x",hashResults[k][i]);
strcat(hash[k],tmp);
}
printf("%d \n%s\n", strlen(hash[k]), hash[k]);
}

strtol result mismatch while string conversion

After checking out this question I did not found required solution, so I've tried to use strtol in following manner:
in = (unsigned char *)malloc(16);
for(size_t i = 0; i < (size_t)strlen(argv[2]) / 2; i+=2 )
{
long tmp = 0;
tmp = strtol((const char *)argv[2] + i, &argv[2] + 2, 16);
memcpy(&in[i], &tmp, 1);
}
This code produced several intermediate values:
Can someone please explain me why entire in array gets filled by 0xFF(255) bytes and why tmp is not equal it's estimated value?
Tips about how to improve above code to fill in array with correct hex values also welcome.
Your code is erroneous for multiple counts and the casts hide the problems:
Casting the return value of malloc is not necessary in C and can potentially hide an unsafe conversion if you forget to include <stdlib.h>:
in = (unsigned char *)malloc(16);
Casting the return value of strlen to (size_t) is useless, even redundant as strlen is defined to return a size_t. Again you might have forgotten to include <string.h>...
for (size_t i = 0; i < (size_t)strlen(argv[2]) / 2; i += 2) {
long tmp = 0;
strtol takes a const pointer to char, which argv[2] + i will convert to implicitly. The cast (const char*) is useless. The second argument is the address of a char*. You pass the address of the fifth element of argv, in other terms &argv[4], most certainly not what you indent to do, although your loop's purpose is quite obscure...
tmp = strtol((const char *)argv[2] + i, &argv[2] + 2, 16);
Copying the long value in tmp with memcpy would require to copy sizeof(tmp) bytes. Copying the first byte only has an implementation defined effect, depending on the size of char and the endianness of the target system:
memcpy(&in[i], &tmp, 1);
}
You should post a complete compilable example that illustrates your problem, a code fragment is missing important context information, such as what header files are included, how variables are defined and what code is executed before the fragment.
As written, your code does not make much sense, trying to interpret its behavior is pointless.
Regarding the question in reference, your code does not even remotely provide a solution for converting a string of hexadecimal characters to an array of bytes.

Incorrect result for %p when implementation printf

I'm working on my own printf code and I got 2 problems that I hoped you might be able to help me with.
The first one is with the %p option :
This option gives me the pointer address of a void* in hex form.
So what I'm doing is this :
void printp(void *thing)
{
dectohex((long)&thing, 1);
}
where dectohex is just a function converting a decimal to hex.
The result will always be correct, except for the last 3 characters. Always. For example :
me : 0x5903d8b8 , printf : 0x5903da28.
And these characters don't change very often, whereas the other part changes at each call like its supposed to.
The other problem I have is with the %O option. I can't manage to convert a signed int to an unsigned int. printf prints huge numbers for negative int's, and no casts seems to work since I wouldn't have the place to store it anyways.
EDIT:
Thanks sooo much for the answers, so apparently for the first problem i was just a little stupid. For the second question i'm gonna try the different solutions you gave me and update you if i manage to do it.
Again thanks so much for your time and patience, and sorry for the delay in my response, i checked the email alert for any answer but it doesn't work apparently.
REEDIT: After reading your answers to my second question more carefully, i think some of you think i asked about %o or %0. I was really talking about %O as in %lo i think. In the man it tells me "%O : The long int argument is converted to unsigned octal". My problem is before converting the long int to octal, i need to convert it to something unsigned.
If uintptr_t/intmax_t is defined (it is optional), convert the pointer to that integer type and then print.
Otherwise, if sizeof(uintmax_t) >= sizeof (void *) , convert to uintmax_t. uintmax_t is a required type, but may not be sufficiently large.
void printp(void *thing) {
uintptr_t j = (uintptr_t) thing;
char lst[(sizeof j * CHAR_BIT + 3)/ 4 + 1]; // Size needed to print in base 16
char *p = &lst[sizeof lst] - 1;
*p = '\0';
do {
p--;
*p = "0123456789ABCDEF"[j%16];
j /= 16;
} while (p > lst);
fputs(p, stdout);
}
The %O problem is likely a sign extension issue. (#mafso) Insure valuables used are unsigned, like unsigned and unsigned long. Without seeing the code difficult to know for sure.
About the first issue you're having, just to make sure, you want to print the address of thing (note that thing itself is a pointer) or the address of the origin of thing (the pointer to the pointer thing)?
You're currently printing the pointer to the pointer.
Change
dectohex((long)&thing, 1);
to
dectohex((long)thing, 1);
if that is the case.
About the %O problem, can you give a code example?
You need "unsigned long long" for your cast.
Pointers are unsigned, but long is signed.
The number of bits in any data type is implementation-dependent; however these days it is common for long and unsigned long to be 32 bits.
edit: to be more clear, you can't count on anything about the number of bits in C, C++ or Objective-C, it's always implementation-dependent. For example it was at one time common to have nine bit bytes and thirty-six bit words. That's why the Internet Protocols always specify "octets" - groups of eight bites - rather then "bytes".
That's one advantage of Java, in that the number of bits in each data type is strictly definited.
About your second question regarding zero-padding and negative integers, which seems entirely separate from the first question about hex output. You can handle negative numbers like this (although in 32-bit it does not work with the value -2147483648 which is 0x80000000).
#include <stdio.h>
#define MAXDIGITS 21
int printint(int value, int zeropad, int width)
{
int i, z, len = 0;
char strg [MAXDIGITS+1];
strg [MAXDIGITS] = 0;
if (value < 0) {
value = - value;
putchar ('-');
len = 1;
}
for (i=MAXDIGITS-1; i>=0; i--) {
strg [i] = '0' + value % 10;
if ((value /= 10) == 0)
break;
}
if (zeropad)
for (z=MAXDIGITS-i; z<width; z++) {
putchar ('0');
len++;
}
for (; i<MAXDIGITS; i++) {
putchar (strg [i]);
len++;
}
return len;
}
int main (int argc, char *argv[])
{
int num = 0, len;
if (argc > 1) {
sscanf (argv[1], "%d", &num);
// try the equivalent of printf("%4d, num);
len = printint (num, 0, 4);
printf (" length %d\n", len);
// try the equivalent of printf("%04d, num);
len = printint (num, 1, 4);
printf (" length %d\n", len);
}
return 0;
}

Strange behaviour when casting array char to array short

I have 2 array: the first one is 8 unsigned char, and the second one is 4 unsigned short, for some algorithm compatibility issue i need to use the short array with the values of the char array, to do so i'm doing a loop
j = 0;
for(i=0; i<8; i+=2)
{
short_array[j] = *(unsigned short*) (char_array + i);
j++;
}
Everything work fine here, but in some previous attempt to build this up, i've tried the following (this is obviously not the correct answer)
j = 0;
for(i=0; i<8; i+=2)
{
short_array[j] = (unsigned short*) *(&(char_array + i));
j++;
}
QUESTION:
Assuming the following char_array = {0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88}
When I do the first one short_array = {0x1122, 0x3344, 0x5566, 0x7788}
But when I do the second one, short_array = {0x3344, 0x5566, 0x7788, ???} (where ??? is undefined since it is a value in the memory and may change).
Can you explain why this i happening?
PS: My compiler suite is C251 from Keil
I've compared the 2 solutions (even if the second is not a working one), and this is definitly a compiler issue, first of all the compiler shouldn't let me compile &(char_array + i) , then I've find out (when inspecting the assembly code) that the char_array is incremented before accessing it in the loop for the second case; and the increment is made after reading the variable in the first case (the correct one). There seem to be no more explanation than a compiler implementation problem...
I would suggest to manually read out each element in your char array and build each pair of chars into a short. I know that there are probably faster methods, but you are implicitly stepping over the bounds of the type you have specific in the char array otherwise. Also, I would claim that my version is slightly easier to read in terms of your intent, albeit more kludgy.
That is, something like this:
IGNORE THIS FIRST CODE BLOCK... THIS IS WHAT HAPPENS WHEN I DON'T SLEEP!
j=0;
uint16_t temp; // recommend to use these types for portability
for(i=0; i<8; i+=2) {
temp = 0x0000;
temp += (uint16_t)(char_array[i] << 8);
temp += (uint16_t)(char_array[i+1]);
short_array[j] = temp;
j++;
}
Also, here's a faster method I came up with after thinking about the problem a bit more, and giving myself a well-deserved self-imposed code review.
j=0;
for(i=0; i<8; i+=2) {
short_array[j] = (char_array[i] << 8) | char_array[i+1]; // use bitwise operations
j++;
}

Resources