简体   繁体   中英

How to convert a hexadecimal char into a 4-bit binary representation?

I wish to compare a SHA-256 hash which is stored in u8[32](after being calculated in kernel-space) with a 64 char string that the user passes as string.

For eg. : User passes a SHA-256 hash "49454bcda10e0dd4543cfa39da9615a19950570129420f956352a58780550839" as char* which will take 64 bytes. But this has to be compared with a hash inside the kernel space which is represented as u8 hash[32].

The hash inside the kernel gets properly printed in ASCII by the following code:

int i;
u8 hash[32];

for(i=0; i<32; i++)
    printk(KERN_CONT "%hhx ", hash[i]);

Output : "49 45 4b cd a1 0e 0d d4 54 3c fa 39 da 96 15 a1 99 50 57 01 29 42 0f 95 63 52 a5 87 80 55 08 39 "

As the complete hash is stored in 32 bytes and printed as 64 chars in groups of 2 chars per u8 space, I assume that currently one u8 block stores information worth 2 chars ie 00101111 prints to be 2f.

Is there a way to store the 64 bytes string in 32 bytes so that it can be compared?

Here is how to use scanf to do the conversion:

char *shaStr = "49454bcda10e0dd4543cfa39da9615a19950570129420f956352a58780550839";
uint8_t sha[32];
for (int i = 0 ; i != 32 ; i++) {
    sscanf(shaStr+2*i, "%2" SCNx8, &sha[i]);
    printf("%02x ", sha[i]);
}

The approach here is to call sscanf repeatedly with the "%2" SCNx8 format specifier, which means "two hex characters converted to uint8_t ". The position is determined by the index of the loop iteration, ie shaStr+2*i

Demo.

Characters are often stored in ASCII , so start by having a look at an ASCII chart . This will show you the relationship between a character like 'a' and the number 97 .

You will note all of the numbers are right next to each other. This is why you often see people do c-'0' or c-48 since it will convert the ASCII-encoded digits into numbers you can use.

However you will note that the letters and the numbers are far away from each other, which is slightly less convenient. If you arrange them by bits, you may notice a pattern: Bit 6 (&64) is set for letters, but unset for digits. Observing that, converting hex-ASCII into numbers is straightforward:

int h2i(char c){return (9*!!(c&64))+(c&15);}

Once you have converted a single character, converting a string is also straightforward:

void hs(char*d,char*s){while(*s){*d=(h2i(*s)*16)+h2i(s[1]);s+=2;++d;}}

Adding support for non-hex characters embedded (like whitespace) is a useful exercise you can do to convince yourself you understand what is going on.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM