Botan  1.11.15
src/lib/codec/hex/hex.cpp
Go to the documentation of this file.
00001 /*
00002 * Hex Encoding and Decoding
00003 * (C) 2010 Jack Lloyd
00004 *
00005 * Botan is released under the Simplified BSD License (see license.txt)
00006 */
00007 
00008 #include <botan/hex.h>
00009 #include <botan/mem_ops.h>
00010 #include <stdexcept>
00011 
00012 namespace Botan {
00013 
00014 void hex_encode(char output[],
00015                 const byte input[],
00016                 size_t input_length,
00017                 bool uppercase)
00018    {
00019    static const byte BIN_TO_HEX_UPPER[16] = {
00020       '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
00021       'A', 'B', 'C', 'D', 'E', 'F' };
00022 
00023    static const byte BIN_TO_HEX_LOWER[16] = {
00024       '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
00025       'a', 'b', 'c', 'd', 'e', 'f' };
00026 
00027    const byte* tbl = uppercase ? BIN_TO_HEX_UPPER : BIN_TO_HEX_LOWER;
00028 
00029    for(size_t i = 0; i != input_length; ++i)
00030       {
00031       byte x = input[i];
00032       output[2*i  ] = tbl[(x >> 4) & 0x0F];
00033       output[2*i+1] = tbl[(x     ) & 0x0F];
00034       }
00035    }
00036 
00037 std::string hex_encode(const byte input[],
00038                        size_t input_length,
00039                        bool uppercase)
00040    {
00041    std::string output(2 * input_length, 0);
00042 
00043    if(input_length)
00044       hex_encode(&output[0], input, input_length, uppercase);
00045 
00046    return output;
00047    }
00048 
00049 size_t hex_decode(byte output[],
00050                   const char input[],
00051                   size_t input_length,
00052                   size_t& input_consumed,
00053                   bool ignore_ws)
00054    {
00055    /*
00056    * Mapping of hex characters to either their binary equivalent
00057    * or to an error code.
00058    *  If valid hex (0-9 A-F a-f), the value.
00059    *  If whitespace, then 0x80
00060    *  Otherwise 0xFF
00061    * Warning: this table assumes ASCII character encodings
00062    */
00063 
00064    static const byte HEX_TO_BIN[256] = {
00065       0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80,
00066       0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
00067       0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
00068       0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
00069       0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x01,
00070       0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0xFF, 0xFF,
00071       0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
00072       0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
00073       0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
00074       0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0A, 0x0B, 0x0C,
00075       0x0D, 0x0E, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
00076       0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
00077       0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
00078       0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
00079       0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
00080       0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
00081       0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
00082       0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
00083       0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
00084       0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
00085       0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
00086       0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
00087       0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
00088       0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
00089       0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
00090       0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
00091 
00092    byte* out_ptr = output;
00093    bool top_nibble = true;
00094 
00095    clear_mem(output, input_length / 2);
00096 
00097    for(size_t i = 0; i != input_length; ++i)
00098       {
00099       const byte bin = HEX_TO_BIN[static_cast<byte>(input[i])];
00100 
00101       if(bin >= 0x10)
00102          {
00103          if(bin == 0x80 && ignore_ws)
00104             continue;
00105 
00106          std::string bad_char(1, input[i]);
00107          if(bad_char == "\t")
00108            bad_char = "\\t";
00109          else if(bad_char == "\n")
00110            bad_char = "\\n";
00111 
00112          throw std::invalid_argument(
00113            std::string("hex_decode: invalid hex character '") +
00114            bad_char + "'");
00115          }
00116 
00117       *out_ptr |= bin << (top_nibble*4);
00118 
00119       top_nibble = !top_nibble;
00120       if(top_nibble)
00121          ++out_ptr;
00122       }
00123 
00124    input_consumed = input_length;
00125    size_t written = (out_ptr - output);
00126 
00127    /*
00128    * We only got half of a byte at the end; zap the half-written
00129    * output and mark it as unread
00130    */
00131    if(!top_nibble)
00132       {
00133       *out_ptr = 0;
00134       input_consumed -= 1;
00135       }
00136 
00137    return written;
00138    }
00139 
00140 size_t hex_decode(byte output[],
00141                   const char input[],
00142                   size_t input_length,
00143                   bool ignore_ws)
00144    {
00145    size_t consumed = 0;
00146    size_t written = hex_decode(output, input, input_length,
00147                                consumed, ignore_ws);
00148 
00149    if(consumed != input_length)
00150       throw std::invalid_argument("hex_decode: input did not have full bytes");
00151 
00152    return written;
00153    }
00154 
00155 size_t hex_decode(byte output[],
00156                   const std::string& input,
00157                   bool ignore_ws)
00158    {
00159    return hex_decode(output, &input[0], input.length(), ignore_ws);
00160    }
00161 
00162 secure_vector<byte> hex_decode_locked(const char input[],
00163                                       size_t input_length,
00164                                       bool ignore_ws)
00165    {
00166    secure_vector<byte> bin(1 + input_length / 2);
00167 
00168    size_t written = hex_decode(&bin[0],
00169                                input,
00170                                input_length,
00171                                ignore_ws);
00172 
00173    bin.resize(written);
00174    return bin;
00175    }
00176 
00177 secure_vector<byte> hex_decode_locked(const std::string& input,
00178                                       bool ignore_ws)
00179    {
00180    return hex_decode_locked(&input[0], input.size(), ignore_ws);
00181    }
00182 
00183 std::vector<byte> hex_decode(const char input[],
00184                              size_t input_length,
00185                              bool ignore_ws)
00186    {
00187    std::vector<byte> bin(1 + input_length / 2);
00188 
00189    size_t written = hex_decode(&bin[0],
00190                                input,
00191                                input_length,
00192                                ignore_ws);
00193 
00194    bin.resize(written);
00195    return bin;
00196    }
00197 
00198 std::vector<byte> hex_decode(const std::string& input,
00199                              bool ignore_ws)
00200    {
00201    return hex_decode(&input[0], input.size(), ignore_ws);
00202    }
00203 
00204 }