/src/botan/build/include/botan/internal/codec_base.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Base Encoding and Decoding |
3 | | * (C) 2018 Erwan Chaussy |
4 | | * (C) 2018 Jack Lloyd |
5 | | * |
6 | | * Botan is released under the Simplified BSD License (see license.txt) |
7 | | */ |
8 | | |
9 | | #ifndef BOTAN_BASE_CODEC_H_ |
10 | | #define BOTAN_BASE_CODEC_H_ |
11 | | |
12 | | #include <botan/secmem.h> |
13 | | #include <botan/exceptn.h> |
14 | | #include <vector> |
15 | | #include <string> |
16 | | |
17 | | namespace Botan { |
18 | | |
19 | | /** |
20 | | * Perform encoding using the base provided |
21 | | * @param base object giving access to the encodings specifications |
22 | | * @param output an array of at least base.encode_max_output bytes |
23 | | * @param input is some binary data |
24 | | * @param input_length length of input in bytes |
25 | | * @param input_consumed is an output parameter which says how many |
26 | | * bytes of input were actually consumed. If less than |
27 | | * input_length, then the range input[consumed:length] |
28 | | * should be passed in later along with more input. |
29 | | * @param final_inputs true iff this is the last input, in which case |
30 | | padding chars will be applied if needed |
31 | | * @return number of bytes written to output |
32 | | */ |
33 | | template <class Base> |
34 | | size_t base_encode(Base&& base, |
35 | | char output[], |
36 | | const uint8_t input[], |
37 | | size_t input_length, |
38 | | size_t& input_consumed, |
39 | | bool final_inputs) |
40 | 0 | { |
41 | 0 | input_consumed = 0; |
42 | 0 |
|
43 | 0 | const size_t encoding_bytes_in = base.encoding_bytes_in(); |
44 | 0 | const size_t encoding_bytes_out = base.encoding_bytes_out(); |
45 | 0 |
|
46 | 0 | size_t input_remaining = input_length; |
47 | 0 | size_t output_produced = 0; |
48 | 0 |
|
49 | 0 | while(input_remaining >= encoding_bytes_in) |
50 | 0 | { |
51 | 0 | base.encode(output + output_produced, input + input_consumed); |
52 | 0 |
|
53 | 0 | input_consumed += encoding_bytes_in; |
54 | 0 | output_produced += encoding_bytes_out; |
55 | 0 | input_remaining -= encoding_bytes_in; |
56 | 0 | } |
57 | 0 |
|
58 | 0 | if(final_inputs && input_remaining) |
59 | 0 | { |
60 | 0 | std::vector<uint8_t> remainder(encoding_bytes_in, 0); |
61 | 0 | for(size_t i = 0; i != input_remaining; ++i) |
62 | 0 | { remainder[i] = input[input_consumed + i]; } |
63 | 0 |
|
64 | 0 | base.encode(output + output_produced, remainder.data()); |
65 | 0 |
|
66 | 0 | const size_t bits_consumed = base.bits_consumed(); |
67 | 0 | const size_t remaining_bits_before_padding = base.remaining_bits_before_padding(); |
68 | 0 |
|
69 | 0 | size_t empty_bits = 8 * (encoding_bytes_in - input_remaining); |
70 | 0 | size_t index = output_produced + encoding_bytes_out - 1; |
71 | 0 | while(empty_bits >= remaining_bits_before_padding) |
72 | 0 | { |
73 | 0 | output[index--] = '='; |
74 | 0 | empty_bits -= bits_consumed; |
75 | 0 | } |
76 | 0 |
|
77 | 0 | input_consumed += input_remaining; |
78 | 0 | output_produced += encoding_bytes_out; |
79 | 0 | } |
80 | 0 |
|
81 | 0 | return output_produced; |
82 | 0 | } Unexecuted instantiation: base64.cpp:unsigned long Botan::base_encode<Botan::(anonymous namespace)::Base64>(Botan::(anonymous namespace)::Base64&&, char*, unsigned char const*, unsigned long, unsigned long&, bool) Unexecuted instantiation: base64.cpp:unsigned long Botan::base_encode<Botan::(anonymous namespace)::Base64&>(Botan::(anonymous namespace)::Base64&, char*, unsigned char const*, unsigned long, unsigned long&, bool) |
83 | | |
84 | | |
85 | | template <typename Base> |
86 | | std::string base_encode_to_string(Base&& base, const uint8_t input[], size_t input_length) |
87 | 0 | { |
88 | 0 | const size_t output_length = base.encode_max_output(input_length); |
89 | 0 | std::string output(output_length, 0); |
90 | 0 |
|
91 | 0 | size_t consumed = 0; |
92 | 0 | size_t produced = 0; |
93 | 0 |
|
94 | 0 | if(output_length > 0) |
95 | 0 | { |
96 | 0 | produced = base_encode(base, &output.front(), |
97 | 0 | input, input_length, |
98 | 0 | consumed, true); |
99 | 0 | } |
100 | 0 |
|
101 | 0 | BOTAN_ASSERT_EQUAL(consumed, input_length, "Consumed the entire input"); |
102 | 0 | BOTAN_ASSERT_EQUAL(produced, output.size(), "Produced expected size"); |
103 | 0 |
|
104 | 0 | return output; |
105 | 0 | } |
106 | | |
107 | | /** |
108 | | * Perform decoding using the base provided |
109 | | * @param base object giving access to the encodings specifications |
110 | | * @param output an array of at least Base::decode_max_output bytes |
111 | | * @param input some base input |
112 | | * @param input_length length of input in bytes |
113 | | * @param input_consumed is an output parameter which says how many |
114 | | * bytes of input were actually consumed. If less than |
115 | | * input_length, then the range input[consumed:length] |
116 | | * should be passed in later along with more input. |
117 | | * @param final_inputs true iff this is the last input, in which case |
118 | | padding is allowed |
119 | | * @param ignore_ws ignore whitespace on input; if false, throw an |
120 | | exception if whitespace is encountered |
121 | | * @return number of bytes written to output |
122 | | */ |
123 | | template <typename Base> |
124 | | size_t base_decode(Base&& base, |
125 | | uint8_t output[], |
126 | | const char input[], |
127 | | size_t input_length, |
128 | | size_t& input_consumed, |
129 | | bool final_inputs, |
130 | | bool ignore_ws = true) |
131 | 5.52k | { |
132 | 5.52k | const size_t decoding_bytes_in = base.decoding_bytes_in(); |
133 | 5.52k | const size_t decoding_bytes_out = base.decoding_bytes_out(); |
134 | 5.52k | |
135 | 5.52k | uint8_t* out_ptr = output; |
136 | 5.52k | std::vector<uint8_t> decode_buf(decoding_bytes_in, 0); |
137 | 5.52k | size_t decode_buf_pos = 0; |
138 | 5.52k | size_t final_truncate = 0; |
139 | 5.52k | |
140 | 5.52k | clear_mem(output, base.decode_max_output(input_length)); |
141 | 5.52k | |
142 | 6.00M | for(size_t i = 0; i != input_length; ++i) |
143 | 5.99M | { |
144 | 5.99M | const uint8_t bin = base.lookup_binary_value(input[i]); |
145 | 5.99M | |
146 | 5.99M | if(base.check_bad_char(bin, input[i], ignore_ws)) // May throw Invalid_Argument |
147 | 5.87M | { |
148 | 5.87M | decode_buf[decode_buf_pos] = bin; |
149 | 5.87M | ++decode_buf_pos; |
150 | 5.87M | } |
151 | 5.99M | |
152 | 5.99M | /* |
153 | 5.99M | * If we're at the end of the input, pad with 0s and truncate |
154 | 5.99M | */ |
155 | 5.99M | if(final_inputs && (i == input_length - 1)) |
156 | 5.37k | { |
157 | 5.37k | if(decode_buf_pos) |
158 | 154 | { |
159 | 470 | for(size_t j = decode_buf_pos; j < decoding_bytes_in; ++j) |
160 | 316 | { decode_buf[j] = 0; } |
161 | 154 | |
162 | 154 | final_truncate = decoding_bytes_in - decode_buf_pos; |
163 | 154 | decode_buf_pos = decoding_bytes_in; |
164 | 154 | } |
165 | 5.37k | } |
166 | 5.99M | |
167 | 5.99M | if(decode_buf_pos == decoding_bytes_in) |
168 | 1.46M | { |
169 | 1.46M | base.decode(out_ptr, decode_buf.data()); |
170 | 1.46M | |
171 | 1.46M | out_ptr += decoding_bytes_out; |
172 | 1.46M | decode_buf_pos = 0; |
173 | 1.46M | input_consumed = i+1; |
174 | 1.46M | } |
175 | 5.99M | } |
176 | 5.52k | |
177 | 12.9k | while(input_consumed < input_length && |
178 | 12.9k | base.lookup_binary_value(input[input_consumed]) == 0x80) |
179 | 7.38k | { |
180 | 7.38k | ++input_consumed; |
181 | 7.38k | } |
182 | 5.52k | |
183 | 5.52k | size_t written = (out_ptr - output) - base.bytes_to_remove(final_truncate); |
184 | 5.52k | |
185 | 5.52k | return written; |
186 | 5.52k | } Unexecuted instantiation: base64.cpp:unsigned long Botan::base_decode<Botan::(anonymous namespace)::Base64>(Botan::(anonymous namespace)::Base64&&, unsigned char*, char const*, unsigned long, unsigned long&, bool, bool) base64.cpp:unsigned long Botan::base_decode<Botan::(anonymous namespace)::Base64&>(Botan::(anonymous namespace)::Base64&, unsigned char*, char const*, unsigned long, unsigned long&, bool, bool) Line | Count | Source | 131 | 5.52k | { | 132 | 5.52k | const size_t decoding_bytes_in = base.decoding_bytes_in(); | 133 | 5.52k | const size_t decoding_bytes_out = base.decoding_bytes_out(); | 134 | 5.52k | | 135 | 5.52k | uint8_t* out_ptr = output; | 136 | 5.52k | std::vector<uint8_t> decode_buf(decoding_bytes_in, 0); | 137 | 5.52k | size_t decode_buf_pos = 0; | 138 | 5.52k | size_t final_truncate = 0; | 139 | 5.52k | | 140 | 5.52k | clear_mem(output, base.decode_max_output(input_length)); | 141 | 5.52k | | 142 | 6.00M | for(size_t i = 0; i != input_length; ++i) | 143 | 5.99M | { | 144 | 5.99M | const uint8_t bin = base.lookup_binary_value(input[i]); | 145 | 5.99M | | 146 | 5.99M | if(base.check_bad_char(bin, input[i], ignore_ws)) // May throw Invalid_Argument | 147 | 5.87M | { | 148 | 5.87M | decode_buf[decode_buf_pos] = bin; | 149 | 5.87M | ++decode_buf_pos; | 150 | 5.87M | } | 151 | 5.99M | | 152 | 5.99M | /* | 153 | 5.99M | * If we're at the end of the input, pad with 0s and truncate | 154 | 5.99M | */ | 155 | 5.99M | if(final_inputs && (i == input_length - 1)) | 156 | 5.37k | { | 157 | 5.37k | if(decode_buf_pos) | 158 | 154 | { | 159 | 470 | for(size_t j = decode_buf_pos; j < decoding_bytes_in; ++j) | 160 | 316 | { decode_buf[j] = 0; } | 161 | 154 | | 162 | 154 | final_truncate = decoding_bytes_in - decode_buf_pos; | 163 | 154 | decode_buf_pos = decoding_bytes_in; | 164 | 154 | } | 165 | 5.37k | } | 166 | 5.99M | | 167 | 5.99M | if(decode_buf_pos == decoding_bytes_in) | 168 | 1.46M | { | 169 | 1.46M | base.decode(out_ptr, decode_buf.data()); | 170 | 1.46M | | 171 | 1.46M | out_ptr += decoding_bytes_out; | 172 | 1.46M | decode_buf_pos = 0; | 173 | 1.46M | input_consumed = i+1; | 174 | 1.46M | } | 175 | 5.99M | } | 176 | 5.52k | | 177 | 12.9k | while(input_consumed < input_length && | 178 | 12.9k | base.lookup_binary_value(input[input_consumed]) == 0x80) | 179 | 7.38k | { | 180 | 7.38k | ++input_consumed; | 181 | 7.38k | } | 182 | 5.52k | | 183 | 5.52k | size_t written = (out_ptr - output) - base.bytes_to_remove(final_truncate); | 184 | 5.52k | | 185 | 5.52k | return written; | 186 | 5.52k | } |
|
187 | | |
188 | | template<typename Base> |
189 | | size_t base_decode_full(Base&& base, uint8_t output[], const char input[], size_t input_length, bool ignore_ws) |
190 | 5.52k | { |
191 | 5.52k | size_t consumed = 0; |
192 | 5.52k | const size_t written = base_decode(base, output, input, input_length, consumed, true, ignore_ws); |
193 | 5.52k | |
194 | 5.52k | if(consumed != input_length) |
195 | 82 | { |
196 | 82 | throw Invalid_Argument(base.name() + " decoding failed, input did not have full bytes"); |
197 | 82 | } |
198 | 5.44k | |
199 | 5.44k | return written; |
200 | 5.44k | } Unexecuted instantiation: base64.cpp:unsigned long Botan::base_decode_full<Botan::(anonymous namespace)::Base64>(Botan::(anonymous namespace)::Base64&&, unsigned char*, char const*, unsigned long, bool) base64.cpp:unsigned long Botan::base_decode_full<Botan::(anonymous namespace)::Base64&>(Botan::(anonymous namespace)::Base64&, unsigned char*, char const*, unsigned long, bool) Line | Count | Source | 190 | 5.52k | { | 191 | 5.52k | size_t consumed = 0; | 192 | 5.52k | const size_t written = base_decode(base, output, input, input_length, consumed, true, ignore_ws); | 193 | 5.52k | | 194 | 5.52k | if(consumed != input_length) | 195 | 82 | { | 196 | 82 | throw Invalid_Argument(base.name() + " decoding failed, input did not have full bytes"); | 197 | 82 | } | 198 | 5.44k | | 199 | 5.44k | return written; | 200 | 5.44k | } |
|
201 | | |
202 | | template<typename Vector, typename Base> |
203 | | Vector base_decode_to_vec(Base&& base, |
204 | | const char input[], |
205 | | size_t input_length, |
206 | | bool ignore_ws) |
207 | 5.52k | { |
208 | 5.52k | const size_t output_length = base.decode_max_output(input_length); |
209 | 5.52k | Vector bin(output_length); |
210 | 5.52k | |
211 | 5.52k | const size_t written = |
212 | 5.52k | base_decode_full(base, bin.data(), input, input_length, ignore_ws); |
213 | 5.52k | |
214 | 5.52k | bin.resize(written); |
215 | 5.52k | return bin; |
216 | 5.52k | } |
217 | | |
218 | | } |
219 | | |
220 | | #endif |