# 4.4 Turning ASCII Hex Keys (or Other ASCII Hex Data) into Binary

#### 4.4.1 Problem

You have a key represented in ASCII that you'd like to convert into binary form. The string containing the key is NULL-terminated.

#### 4.4.2 Solution

The code listed in the following Section 4.4.3 parses an ASCII string that represents hexadecimal data, and it returns a malloc( )'d buffer of the appropriate length. Note that the buffer will be half the size of the input string, not counting the leading "0x" if it exists. The exception is when there is whitespace. This function passes back the number of bytes written in its second parameter. If that parameter is negative, an error occurred.

#### 4.4.3 Discussion

The spc_hex2bin( ) function shown in this section converts an ASCII string into a binary string. Spaces and tabs are ignored. A leading "0x" or "0X" is ignored. There are two cases in which this function can fail. First, if it sees a non-hexadecimal digit, it assumes that the string is not in the right format, and it returns NULL, setting the error parameter to ERR_NOT_HEX. Second, if there is an odd number of hex digits in the string, it returns NULL, setting the error parameter to ERR_BAD_SIZE.

```#include <string.h>
#include <stdlib.h>
#include <ctype.h>

#define ERR_NOT_HEX  -1
#define ERR_NO_MEM   -3

unsigned char *spc_hex2bin(const unsigned char *input, size_t *l) {
unsigned char       shift = 4, value = 0;
unsigned char       *r, *ret;
const unsigned char *p;

if (!(r = ret = (unsigned char *)malloc(strlen(input) / 2))) {
*l = ERR_NO_MEM;
return 0;
}
for (p = input;  isspace(*p);  p++);
if (p[0] =  = '0' && (p[1] =  = 'x' || p[1] =  = 'X')) p += 2;

while (p[0]) {
switch (p[0]) {
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
value |= (*p++ - '0') << shift;
break;
case 'a': case 'b': case 'c':
case 'd': case 'e': case 'f':
value |= (*p++ - 'a' + 0xa) << shift;
break;
case 'A': case 'B': case 'C':
case 'D': case 'E': case 'F':
value |= (*p++ - 'A' + 0xa) << shift;
break;
case 0:
if (!shift) {
*l = ERR_NOT_HEX;
free(ret);
return 0;
}
break;
default:
if (isspace(p[0])) p++;
else {
*l = ERR_NOT_HEX;
free(ret);
return 0;
}
}
if ((shift = (shift + 4) % 8) != 0) {
*r++ = value;
value = 0;
}
}
if (!shift) {
free(ret);
return 0;
}
*l = (r - ret);
return (unsigned char *)realloc(ret, *l);
}```

 Foreword
 Preface
 Chapter 1. Safe Initialization
 Chapter 2. Access Control
 Chapter 3. Input Validation
 Chapter 5. Symmetric Encryption
 Chapter 6. Hashes and Message Authentication
 Chapter 7. Public Key Cryptography
 Chapter 8. Authentication and Key Exchange
 Chapter 9. Networking
 Chapter 10. Public Key Infrastructure
 Chapter 11. Random Numbers
 Chapter 12. Anti-Tampering
 Chapter 13. Other Topics
 Colophon