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