xref: /DragonStub/apps/lib/hexdump.c (revision f412fd2a1a248b546b7085648dece8d908077fab)
1*f412fd2aSLoGin const char hex_asc[] = "0123456789abcdef";
2*f412fd2aSLoGin const char hex_asc_upper[] = "0123456789ABCDEF";
3*f412fd2aSLoGin 
4*f412fd2aSLoGin /**
5*f412fd2aSLoGin  * hex_to_bin - convert a hex digit to its real value
6*f412fd2aSLoGin  * @ch: ascii character represents hex digit
7*f412fd2aSLoGin  *
8*f412fd2aSLoGin  * hex_to_bin() converts one hex digit to its actual value or -1 in case of bad
9*f412fd2aSLoGin  * input.
10*f412fd2aSLoGin  *
11*f412fd2aSLoGin  * This function is used to load cryptographic keys, so it is coded in such a
12*f412fd2aSLoGin  * way that there are no conditions or memory accesses that depend on data.
13*f412fd2aSLoGin  *
14*f412fd2aSLoGin  * Explanation of the logic:
15*f412fd2aSLoGin  * (ch - '9' - 1) is negative if ch <= '9'
16*f412fd2aSLoGin  * ('0' - 1 - ch) is negative if ch >= '0'
17*f412fd2aSLoGin  * we "and" these two values, so the result is negative if ch is in the range
18*f412fd2aSLoGin  *	'0' ... '9'
19*f412fd2aSLoGin  * we are only interested in the sign, so we do a shift ">> 8"; note that right
20*f412fd2aSLoGin  *	shift of a negative value is implementation-defined, so we cast the
21*f412fd2aSLoGin  *	value to (unsigned) before the shift --- we have 0xffffff if ch is in
22*f412fd2aSLoGin  *	the range '0' ... '9', 0 otherwise
23*f412fd2aSLoGin  * we "and" this value with (ch - '0' + 1) --- we have a value 1 ... 10 if ch is
24*f412fd2aSLoGin  *	in the range '0' ... '9', 0 otherwise
25*f412fd2aSLoGin  * we add this value to -1 --- we have a value 0 ... 9 if ch is in the range '0'
26*f412fd2aSLoGin  *	... '9', -1 otherwise
27*f412fd2aSLoGin  * the next line is similar to the previous one, but we need to decode both
28*f412fd2aSLoGin  *	uppercase and lowercase letters, so we use (ch & 0xdf), which converts
29*f412fd2aSLoGin  *	lowercase to uppercase
30*f412fd2aSLoGin  */
hex_to_bin(unsigned char ch)31*f412fd2aSLoGin int hex_to_bin(unsigned char ch)
32*f412fd2aSLoGin {
33*f412fd2aSLoGin 	unsigned char cu = ch & 0xdf;
34*f412fd2aSLoGin 	return -1 +
35*f412fd2aSLoGin 	       ((ch - '0' + 1) &
36*f412fd2aSLoGin 		(unsigned)((ch - '9' - 1) & ('0' - 1 - ch)) >> 8) +
37*f412fd2aSLoGin 	       ((cu - 'A' + 11) &
38*f412fd2aSLoGin 		(unsigned)((cu - 'F' - 1) & ('A' - 1 - cu)) >> 8);
39*f412fd2aSLoGin }