Botan 3.0.0
Crypto and TLS for C&
codec_base.h
Go to the documentation of this file.
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
17namespace 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*/
33template <class Base>
34size_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 {
41 input_consumed = 0;
42
43 const size_t encoding_bytes_in = base.encoding_bytes_in();
44 const size_t encoding_bytes_out = base.encoding_bytes_out();
45
46 size_t input_remaining = input_length;
47 size_t output_produced = 0;
48
49 while(input_remaining >= encoding_bytes_in)
50 {
51 base.encode(output + output_produced, input + input_consumed);
52
53 input_consumed += encoding_bytes_in;
54 output_produced += encoding_bytes_out;
55 input_remaining -= encoding_bytes_in;
56 }
57
58 if(final_inputs && input_remaining)
59 {
60 std::vector<uint8_t> remainder(encoding_bytes_in, 0);
61 for(size_t i = 0; i != input_remaining; ++i)
62 { remainder[i] = input[input_consumed + i]; }
63
64 base.encode(output + output_produced, remainder.data());
65
66 const size_t bits_consumed = base.bits_consumed();
67 const size_t remaining_bits_before_padding = base.remaining_bits_before_padding();
68
69 size_t empty_bits = 8 * (encoding_bytes_in - input_remaining);
70 size_t index = output_produced + encoding_bytes_out - 1;
71 while(empty_bits >= remaining_bits_before_padding)
72 {
73 output[index--] = '=';
74 empty_bits -= bits_consumed;
75 }
76
77 input_consumed += input_remaining;
78 output_produced += encoding_bytes_out;
79 }
80
81 return output_produced;
82 }
83
84
85template <typename Base>
86std::string base_encode_to_string(Base&& base, const uint8_t input[], size_t input_length)
87 {
88 const size_t output_length = base.encode_max_output(input_length);
89 std::string output(output_length, 0);
90
91 size_t consumed = 0;
92 size_t produced = 0;
93
94 if(output_length > 0)
95 {
96 produced = base_encode(base, &output.front(),
97 input, input_length,
98 consumed, true);
99 }
100
101 BOTAN_ASSERT_EQUAL(consumed, input_length, "Consumed the entire input");
102 BOTAN_ASSERT_EQUAL(produced, output.size(), "Produced expected size");
103
104 return output;
105 }
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*/
123template <typename Base>
124size_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 {
132 const size_t decoding_bytes_in = base.decoding_bytes_in();
133 const size_t decoding_bytes_out = base.decoding_bytes_out();
134
135 uint8_t* out_ptr = output;
136 std::vector<uint8_t> decode_buf(decoding_bytes_in, 0);
137 size_t decode_buf_pos = 0;
138 size_t final_truncate = 0;
139
140 clear_mem(output, base.decode_max_output(input_length));
141
142 for(size_t i = 0; i != input_length; ++i)
143 {
144 const uint8_t bin = base.lookup_binary_value(input[i]);
145
146 if(base.check_bad_char(bin, input[i], ignore_ws)) // May throw Invalid_Argument
147 {
148 decode_buf[decode_buf_pos] = bin;
149 ++decode_buf_pos;
150 }
151
152 /*
153 * If we're at the end of the input, pad with 0s and truncate
154 */
155 if(final_inputs && (i == input_length - 1))
156 {
157 if(decode_buf_pos)
158 {
159 for(size_t j = decode_buf_pos; j < decoding_bytes_in; ++j)
160 { decode_buf[j] = 0; }
161
162 final_truncate = decoding_bytes_in - decode_buf_pos;
163 decode_buf_pos = decoding_bytes_in;
164 }
165 }
166
167 if(decode_buf_pos == decoding_bytes_in)
168 {
169 base.decode(out_ptr, decode_buf.data());
170
171 out_ptr += decoding_bytes_out;
172 decode_buf_pos = 0;
173 input_consumed = i+1;
174 }
175 }
176
177 while(input_consumed < input_length &&
178 base.lookup_binary_value(input[input_consumed]) == 0x80)
179 {
180 ++input_consumed;
181 }
182
183 size_t written = (out_ptr - output) - base.bytes_to_remove(final_truncate);
184
185 return written;
186 }
187
188template<typename Base>
189size_t base_decode_full(Base&& base, uint8_t output[], const char input[], size_t input_length, bool ignore_ws)
190 {
191 size_t consumed = 0;
192 const size_t written = base_decode(base, output, input, input_length, consumed, true, ignore_ws);
193
194 if(consumed != input_length)
195 {
196 throw Invalid_Argument(base.name() + " decoding failed, input did not have full bytes");
197 }
198
199 return written;
200 }
201
202template<typename Vector, typename Base>
203Vector base_decode_to_vec(Base&& base,
204 const char input[],
205 size_t input_length,
206 bool ignore_ws)
207 {
208 const size_t output_length = base.decode_max_output(input_length);
209 Vector bin(output_length);
210
211 const size_t written =
212 base_decode_full(base, bin.data(), input, input_length, ignore_ws);
213
214 bin.resize(written);
215 return bin;
216 }
217
218}
219
220#endif
#define BOTAN_ASSERT_EQUAL(expr1, expr2, assertion_made)
Definition: assert.h:80
Definition: alg_id.cpp:12
Vector base_decode_to_vec(Base &&base, const char input[], size_t input_length, bool ignore_ws)
Definition: codec_base.h:203
size_t base_encode(Base &&base, char output[], const uint8_t input[], size_t input_length, size_t &input_consumed, bool final_inputs)
Definition: codec_base.h:34
size_t base_decode(Base &&base, uint8_t output[], const char input[], size_t input_length, size_t &input_consumed, bool final_inputs, bool ignore_ws=true)
Definition: codec_base.h:124
std::string base_encode_to_string(Base &&base, const uint8_t input[], size_t input_length)
Definition: codec_base.h:86
constexpr void clear_mem(T *ptr, size_t n)
Definition: mem_ops.h:115
size_t base_decode_full(Base &&base, uint8_t output[], const char input[], size_t input_length, bool ignore_ws)
Definition: codec_base.h:189