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