Botan  1.10.9
hex.cpp
Go to the documentation of this file.
1 /*
2 * Hex Encoding and Decoding
3 * (C) 2010 Jack Lloyd
4 *
5 * Distributed under the terms of the Botan license
6 */
7 
8 #include <botan/hex.h>
9 #include <botan/mem_ops.h>
10 #include <stdexcept>
11 
12 namespace Botan {
13 
14 void hex_encode(char output[],
15  const byte input[],
16  size_t input_length,
17  bool uppercase)
18  {
19  static const byte BIN_TO_HEX_UPPER[16] = {
20  '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
21  'A', 'B', 'C', 'D', 'E', 'F' };
22 
23  static const byte BIN_TO_HEX_LOWER[16] = {
24  '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
25  'a', 'b', 'c', 'd', 'e', 'f' };
26 
27  const byte* tbl = uppercase ? BIN_TO_HEX_UPPER : BIN_TO_HEX_LOWER;
28 
29  for(size_t i = 0; i != input_length; ++i)
30  {
31  byte x = input[i];
32  output[2*i ] = tbl[(x >> 4) & 0x0F];
33  output[2*i+1] = tbl[(x ) & 0x0F];
34  }
35  }
36 
37 std::string hex_encode(const MemoryRegion<byte>& input,
38  bool uppercase)
39  {
40  return hex_encode(&input[0], input.size(), uppercase);
41  }
42 
43 std::string hex_encode(const byte input[],
44  size_t input_length,
45  bool uppercase)
46  {
47  std::string output(2 * input_length, 0);
48 
49  if(input_length)
50  hex_encode(&output[0], input, input_length, uppercase);
51 
52  return output;
53  }
54 
55 size_t hex_decode(byte output[],
56  const char input[],
57  size_t input_length,
58  size_t& input_consumed,
59  bool ignore_ws)
60  {
61  /*
62  * Mapping of hex characters to either their binary equivalent
63  * or to an error code.
64  * If valid hex (0-9 A-F a-f), the value.
65  * If whitespace, then 0x80
66  * Otherwise 0xFF
67  * Warning: this table assumes ASCII character encodings
68  */
69 
70  static const byte HEX_TO_BIN[256] = {
71  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80,
72  0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
73  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
74  0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
75  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x01,
76  0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0xFF, 0xFF,
77  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
78  0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
79  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
80  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0A, 0x0B, 0x0C,
81  0x0D, 0x0E, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
82  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
83  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
84  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
85  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
86  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
87  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
88  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
89  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
90  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
91  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
92  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
93  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
94  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
95  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
96  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
97 
98  byte* out_ptr = output;
99  bool top_nibble = true;
100 
101  clear_mem(output, input_length / 2);
102 
103  for(size_t i = 0; i != input_length; ++i)
104  {
105  const byte bin = HEX_TO_BIN[static_cast<byte>(input[i])];
106 
107  if(bin >= 0x10)
108  {
109  if(bin == 0x80 && ignore_ws)
110  continue;
111 
112  std::string bad_char(1, input[i]);
113  if(bad_char == "\t")
114  bad_char = "\\t";
115  else if(bad_char == "\n")
116  bad_char = "\\n";
117 
118  throw std::invalid_argument(
119  std::string("hex_decode: invalid hex character '") +
120  bad_char + "'");
121  }
122 
123  *out_ptr |= bin << (top_nibble*4);
124 
125  top_nibble = !top_nibble;
126  if(top_nibble)
127  ++out_ptr;
128  }
129 
130  input_consumed = input_length;
131  size_t written = (out_ptr - output);
132 
133  /*
134  * We only got half of a byte at the end; zap the half-written
135  * output and mark it as unread
136  */
137  if(!top_nibble)
138  {
139  *out_ptr = 0;
140  input_consumed -= 1;
141  }
142 
143  return written;
144  }
145 
146 size_t hex_decode(byte output[],
147  const char input[],
148  size_t input_length,
149  bool ignore_ws)
150  {
151  size_t consumed = 0;
152  size_t written = hex_decode(output, input, input_length,
153  consumed, ignore_ws);
154 
155  if(consumed != input_length)
156  throw std::invalid_argument("hex_decode: input did not have full bytes");
157 
158  return written;
159  }
160 
161 size_t hex_decode(byte output[],
162  const std::string& input,
163  bool ignore_ws)
164  {
165  return hex_decode(output, &input[0], input.length(), ignore_ws);
166  }
167 
168 SecureVector<byte> hex_decode(const char input[],
169  size_t input_length,
170  bool ignore_ws)
171  {
172  SecureVector<byte> bin(1 + input_length / 2);
173 
174  size_t written = hex_decode(&bin[0],
175  input,
176  input_length,
177  ignore_ws);
178 
179  bin.resize(written);
180  return bin;
181  }
182 
183 SecureVector<byte> hex_decode(const std::string& input,
184  bool ignore_ws)
185  {
186  return hex_decode(&input[0], input.size(), ignore_ws);
187  }
188 
189 }
void resize(size_t n)
Definition: secmem.h:211
size_t hex_decode(byte output[], const char input[], size_t input_length, size_t &input_consumed, bool ignore_ws)
Definition: hex.cpp:55
void clear_mem(T *ptr, size_t n)
Definition: mem_ops.h:32
unsigned char byte
Definition: types.h:22
size_t size() const
Definition: secmem.h:29
void hex_encode(char output[], const byte input[], size_t input_length, bool uppercase)
Definition: hex.cpp:14