/* * Hex Encoding and Decoding * (C) 2010 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ #include #include #include namespace Botan { void hex_encode(char output[], const uint8_t input[], size_t input_length, bool uppercase) { static const uint8_t BIN_TO_HEX_UPPER[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; static const uint8_t BIN_TO_HEX_LOWER[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; const uint8_t* tbl = uppercase ? BIN_TO_HEX_UPPER : BIN_TO_HEX_LOWER; for(size_t i = 0; i != input_length; ++i) { uint8_t x = input[i]; output[2*i ] = tbl[(x >> 4) & 0x0F]; output[2*i+1] = tbl[(x ) & 0x0F]; } } std::string hex_encode(const uint8_t input[], size_t input_length, bool uppercase) { std::string output(2 * input_length, 0); if(input_length) hex_encode(&output.front(), input, input_length, uppercase); return output; } size_t hex_decode(uint8_t output[], const char input[], size_t input_length, size_t& input_consumed, bool ignore_ws) { /* * Mapping of hex characters to either their binary equivalent * or to an error code. * If valid hex (0-9 A-F a-f), the value. * If whitespace, then 0x80 * Otherwise 0xFF * Warning: this table assumes ASCII character encodings */ static const uint8_t HEX_TO_BIN[256] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; uint8_t* out_ptr = output; bool top_nibble = true; clear_mem(output, input_length / 2); for(size_t i = 0; i != input_length; ++i) { const uint8_t bin = HEX_TO_BIN[static_cast(input[i])]; if(bin >= 0x10) { if(bin == 0x80 && ignore_ws) continue; std::string bad_char(1, input[i]); if(bad_char == "\t") bad_char = "\\t"; else if(bad_char == "\n") bad_char = "\\n"; throw Invalid_Argument( std::string("hex_decode: invalid hex character '") + bad_char + "'"); } *out_ptr |= bin << (top_nibble*4); top_nibble = !top_nibble; if(top_nibble) ++out_ptr; } input_consumed = input_length; size_t written = (out_ptr - output); /* * We only got half of a uint8_t at the end; zap the half-written * output and mark it as unread */ if(!top_nibble) { *out_ptr = 0; input_consumed -= 1; } return written; } size_t hex_decode(uint8_t output[], const char input[], size_t input_length, bool ignore_ws) { size_t consumed = 0; size_t written = hex_decode(output, input, input_length, consumed, ignore_ws); if(consumed != input_length) throw Invalid_Argument("hex_decode: input did not have full bytes"); return written; } size_t hex_decode(uint8_t output[], const std::string& input, bool ignore_ws) { return hex_decode(output, input.data(), input.length(), ignore_ws); } secure_vector hex_decode_locked(const char input[], size_t input_length, bool ignore_ws) { secure_vector bin(1 + input_length / 2); size_t written = hex_decode(bin.data(), input, input_length, ignore_ws); bin.resize(written); return bin; } secure_vector hex_decode_locked(const std::string& input, bool ignore_ws) { return hex_decode_locked(input.data(), input.size(), ignore_ws); } std::vector hex_decode(const char input[], size_t input_length, bool ignore_ws) { std::vector bin(1 + input_length / 2); size_t written = hex_decode(bin.data(), input, input_length, ignore_ws); bin.resize(written); return bin; } std::vector hex_decode(const std::string& input, bool ignore_ws) { return hex_decode(input.data(), input.size(), ignore_ws); } }