/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,2020 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 | | #include <botan/internal/ct_utils.h> |
12 | | |
13 | | namespace Botan { |
14 | | |
15 | | namespace { |
16 | | |
17 | | char hex_encode_nibble(uint8_t n, bool uppercase) |
18 | 971k | { |
19 | 971k | BOTAN_DEBUG_ASSERT(n <= 15); |
20 | | |
21 | 971k | const auto in_09 = CT::Mask<uint8_t>::is_lt(n, 10); |
22 | | |
23 | 971k | const char c_09 = n + '0'; |
24 | 971k | const char c_af = n + (uppercase ? 'A' : 'a') - 10; |
25 | | |
26 | 971k | return in_09.select(c_09, c_af); |
27 | 971k | } |
28 | | |
29 | | } |
30 | | |
31 | | void hex_encode(char output[], |
32 | | const uint8_t input[], |
33 | | size_t input_length, |
34 | | bool uppercase) |
35 | 18.7k | { |
36 | 504k | for(size_t i = 0; i != input_length; ++i) |
37 | 485k | { |
38 | 485k | const uint8_t n0 = (input[i] >> 4) & 0xF; |
39 | 485k | const uint8_t n1 = (input[i] ) & 0xF; |
40 | | |
41 | 485k | output[2*i ] = hex_encode_nibble(n0, uppercase); |
42 | 485k | output[2*i+1] = hex_encode_nibble(n1, uppercase); |
43 | 485k | } |
44 | 18.7k | } |
45 | | |
46 | | std::string hex_encode(const uint8_t input[], |
47 | | size_t input_length, |
48 | | bool uppercase) |
49 | 18.7k | { |
50 | 18.7k | std::string output(2 * input_length, 0); |
51 | | |
52 | 18.7k | if(input_length) |
53 | 18.7k | hex_encode(&output.front(), input, input_length, uppercase); |
54 | | |
55 | 18.7k | return output; |
56 | 18.7k | } |
57 | | |
58 | | namespace { |
59 | | |
60 | | uint8_t hex_char_to_bin(char input) |
61 | 1.85M | { |
62 | 1.85M | const uint8_t c = static_cast<uint8_t>(input); |
63 | | |
64 | 1.85M | const auto is_alpha_upper = CT::Mask<uint8_t>::is_within_range(c, uint8_t('A'), uint8_t('F')); |
65 | 1.85M | const auto is_alpha_lower = CT::Mask<uint8_t>::is_within_range(c, uint8_t('a'), uint8_t('f')); |
66 | 1.85M | const auto is_decimal = CT::Mask<uint8_t>::is_within_range(c, uint8_t('0'), uint8_t('9')); |
67 | | |
68 | 1.85M | const auto is_whitespace = CT::Mask<uint8_t>::is_any_of(c, { |
69 | 1.85M | uint8_t(' '), uint8_t('\t'), uint8_t('\n'), uint8_t('\r') |
70 | 1.85M | }); |
71 | | |
72 | 1.85M | const uint8_t c_upper = c - uint8_t('A') + 10; |
73 | 1.85M | const uint8_t c_lower = c - uint8_t('a') + 10; |
74 | 1.85M | const uint8_t c_decim = c - uint8_t('0'); |
75 | | |
76 | 1.85M | uint8_t ret = 0xFF; // default value |
77 | | |
78 | 1.85M | ret = is_alpha_upper.select(c_upper, ret); |
79 | 1.85M | ret = is_alpha_lower.select(c_lower, ret); |
80 | 1.85M | ret = is_decimal.select(c_decim, ret); |
81 | 1.85M | ret = is_whitespace.select(0x80, ret); |
82 | | |
83 | 1.85M | return ret; |
84 | 1.85M | } |
85 | | |
86 | | } |
87 | | |
88 | | |
89 | | size_t hex_decode(uint8_t output[], |
90 | | const char input[], |
91 | | size_t input_length, |
92 | | size_t& input_consumed, |
93 | | bool ignore_ws) |
94 | 50.7k | { |
95 | 50.7k | uint8_t* out_ptr = output; |
96 | 50.7k | bool top_nibble = true; |
97 | | |
98 | 50.7k | clear_mem(output, input_length / 2); |
99 | | |
100 | 1.90M | for(size_t i = 0; i != input_length; ++i) |
101 | 1.85M | { |
102 | 1.85M | const uint8_t bin = hex_char_to_bin(input[i]); |
103 | | |
104 | 1.85M | if(bin >= 0x10) |
105 | 0 | { |
106 | 0 | if(bin == 0x80 && ignore_ws) |
107 | 0 | continue; |
108 | | |
109 | 0 | std::string bad_char(1, input[i]); |
110 | 0 | if(bad_char == "\t") |
111 | 0 | bad_char = "\\t"; |
112 | 0 | else if(bad_char == "\n") |
113 | 0 | bad_char = "\\n"; |
114 | |
|
115 | 0 | throw Invalid_Argument( |
116 | 0 | std::string("hex_decode: invalid hex character '") + |
117 | 0 | bad_char + "'"); |
118 | 0 | } |
119 | | |
120 | 1.85M | if(top_nibble) |
121 | 925k | *out_ptr |= bin << 4; |
122 | 925k | else |
123 | 925k | *out_ptr |= bin; |
124 | | |
125 | 1.85M | top_nibble = !top_nibble; |
126 | 1.85M | if(top_nibble) |
127 | 925k | ++out_ptr; |
128 | 1.85M | } |
129 | | |
130 | 50.7k | input_consumed = input_length; |
131 | 50.7k | size_t written = (out_ptr - output); |
132 | | |
133 | | /* |
134 | | * We only got half of a uint8_t at the end; zap the half-written |
135 | | * output and mark it as unread |
136 | | */ |
137 | 50.7k | if(!top_nibble) |
138 | 0 | { |
139 | 0 | *out_ptr = 0; |
140 | 0 | input_consumed -= 1; |
141 | 0 | } |
142 | | |
143 | 50.7k | return written; |
144 | 50.7k | } |
145 | | |
146 | | size_t hex_decode(uint8_t output[], |
147 | | const char input[], |
148 | | size_t input_length, |
149 | | bool ignore_ws) |
150 | 50.7k | { |
151 | 50.7k | size_t consumed = 0; |
152 | 50.7k | size_t written = hex_decode(output, input, input_length, |
153 | 50.7k | consumed, ignore_ws); |
154 | | |
155 | 50.7k | if(consumed != input_length) |
156 | 0 | throw Invalid_Argument("hex_decode: input did not have full bytes"); |
157 | | |
158 | 50.7k | return written; |
159 | 50.7k | } |
160 | | |
161 | | size_t hex_decode(uint8_t output[], |
162 | | const std::string& input, |
163 | | bool ignore_ws) |
164 | 43.0k | { |
165 | 43.0k | return hex_decode(output, input.data(), input.length(), ignore_ws); |
166 | 43.0k | } |
167 | | |
168 | | secure_vector<uint8_t> hex_decode_locked(const char input[], |
169 | | size_t input_length, |
170 | | bool ignore_ws) |
171 | 7.75k | { |
172 | 7.75k | secure_vector<uint8_t> bin(1 + input_length / 2); |
173 | | |
174 | 7.75k | size_t written = hex_decode(bin.data(), |
175 | 7.75k | input, |
176 | 7.75k | input_length, |
177 | 7.75k | ignore_ws); |
178 | | |
179 | 7.75k | bin.resize(written); |
180 | 7.75k | return bin; |
181 | 7.75k | } |
182 | | |
183 | | secure_vector<uint8_t> hex_decode_locked(const std::string& input, |
184 | | bool ignore_ws) |
185 | 0 | { |
186 | 0 | return hex_decode_locked(input.data(), input.size(), ignore_ws); |
187 | 0 | } |
188 | | |
189 | | std::vector<uint8_t> hex_decode(const char input[], |
190 | | size_t input_length, |
191 | | bool ignore_ws) |
192 | 0 | { |
193 | 0 | std::vector<uint8_t> bin(1 + input_length / 2); |
194 | |
|
195 | 0 | size_t written = hex_decode(bin.data(), |
196 | 0 | input, |
197 | 0 | input_length, |
198 | 0 | ignore_ws); |
199 | |
|
200 | 0 | bin.resize(written); |
201 | 0 | return bin; |
202 | 0 | } |
203 | | |
204 | | std::vector<uint8_t> hex_decode(const std::string& input, |
205 | | bool ignore_ws) |
206 | 0 | { |
207 | 0 | return hex_decode(input.data(), input.size(), ignore_ws); |
208 | 0 | } |
209 | | |
210 | | } |