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 }