Botan  2.11.0
Crypto and TLS for C++11
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 
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  {
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 
85 template <typename Base>
86 std::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 */
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  {
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 
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  {
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 
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  {
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
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
void clear_mem(T *ptr, size_t n)
Definition: mem_ops.h:111
std::string base_encode_to_string(Base &&base, const uint8_t input[], size_t input_length)
Definition: codec_base.h:86
#define BOTAN_ASSERT_EQUAL(expr1, expr2, assertion_made)
Definition: assert.h:81
Definition: alg_id.cpp:13
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_decode_full(Base &&base, uint8_t output[], const char input[], size_t input_length, bool ignore_ws)
Definition: codec_base.h:189
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