I have a unsigned char array of which I'd like to calculate the CRC32 checksum.
The CRC32 function also expects a unsigned char pointer, however, it interprets the array as an ASCII array.
This is the CRC function:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
unsigned int crc32(unsigned char *message)
{
int i, j;
unsigned int byte, crc, mask;
i = 0;
crc = 0xFFFFFFFF;
while (message[i] != 0) {
byte = message[i]; // Get next byte.
crc = crc ^ byte;
for (j = 7; j >= 0; j--) { // Do eight times.
mask = -(crc & 1);
crc = (crc >> 1) ^ (0xEDB88320 & mask);
}
i = i + 1;
}
return ~crc;
}
int main(int argc, char **argv)
{
unsigned char *arr;
if ((arr = malloc(64)) == NULL) {
perror("Could not allocate memory");
exit(EXIT_FAILURE);
}
char str[] = "47d46d17e759a1dec810758c08004510002127d90000401152e4c0a8b21fc0a8b2255b9b5b9c000db20caabbccddee00000000000000000000000000";
memcpy(arr, str, strlen(str));
// ...
unsigned int crc = crc32(arr);
printf("CRC: 0x%x\n", crc); // 0xB6BA014A instead of 0xBF6B57A2
return 0;
}
Now, I'd like to calculate the CRC32 but the unsigned char array has to be interpreted as an hex array.
F.ex., this is the result of the calculated CRC:
Input:
"47d46d17e759a1dec810758c08004510002127d90000401152e4c0a8b21fc0a8b2255b9b5b9c000db20caabbccddee00000000000000000000000000"
How to interpret an unsigned char array as hex array?
Convert each pair of hexadecimal characters in the string to a byte value. Code below converts via a compound literal to form a 3 byte string, followed by a call to strtoul()
.
// v----------------------------------v _compound literal_
arr2[i / 2] = strtoul((char[3]) {str[i], str[i + 1], '\0'}, 0, 16);
More advanced code would test for the unexpected presence of non-hexadecimal characters or an odd/zero length.
CRC calculation changes needed
Change CRC calculation to a length based one rather than a string one.
// unsigned int crc32(const char *)
unsigned int crc32(const void *m, size_t len)
Although not coded below, consider uint32_t
instead of unsigned int
in crc32()
for correct operation when unsigned
is not 32-bit.
Altogether
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
unsigned int crc32(const void *m, size_t len) {
const unsigned char *message = m;
size_t i;
int j;
unsigned int byte, crc, mask;
i = 0;
crc = 0xFFFFFFFF;
//while (message[i] != 0) {
while (i < len) {
byte = message[i]; // Get next byte.
crc = crc ^ byte;
for (j = 7; j >= 0; j--) { // Do eight times.
mask = -(crc & 1);
crc = (crc >> 1) ^ (0xEDB88320 & mask);
}
i = i + 1;
}
return ~crc;
}
Sample usage
int main() {
char str[] =
"47d46d17e759a1dec810758c08004510002127d90000401152e4c0a8b21fc0a8b2255b9b5b9c000db20caabbccddee00000000000000000000000000";
size_t len = strlen(str);
unsigned int crc = crc32(str, len);
printf("CRC: 0x%X\n", crc); // 0xB6BA014A instead of 0xBF6B57A2
size_t len2 = (len + 1) / 2;
unsigned char arr2[len2];
for (size_t i = 0; i < len; i += 2) {
arr2[i / 2] = strtoul((char[3]) {str[i], str[i + 1], '\0'}, 0, 16);
}
crc = crc32(arr2, len2);
printf("CRC: 0x%X\n", crc); // 0xB6BA014A instead of 0xBF6B57A2
return 0;
}
Output
CRC: 0xB6BA014A
CRC: 0xBF6B57A2
OP original code had undefined behavior in that it looked for a null character with while (message[i] != 0) {
, yet memcpy(arr, str, strlen(str));
failed to provide one.
User contributions licensed under CC BY-SA 3.0