Botan  2.7.0
Crypto and TLS for C++11
base64.cpp
Go to the documentation of this file.
1 /*
2 * Base64 Encoding and Decoding
3 * (C) 2010,2015 Jack Lloyd
4 *
5 * Botan is released under the Simplified BSD License (see license.txt)
6 */
7 
8 #include <botan/base64.h>
9 #include <botan/exceptn.h>
10 #include <botan/mem_ops.h>
11 #include <botan/internal/rounding.h>
12 
13 namespace Botan {
14 
15 namespace {
16 
17 static const uint8_t BIN_TO_BASE64[64] = {
18  'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
19  'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
20  'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
21  'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
22  '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
23 };
24 
25 void do_base64_encode(char out[4], const uint8_t in[3])
26  {
27  out[0] = BIN_TO_BASE64[(in[0] & 0xFC) >> 2];
28  out[1] = BIN_TO_BASE64[((in[0] & 0x03) << 4) | (in[1] >> 4)];
29  out[2] = BIN_TO_BASE64[((in[1] & 0x0F) << 2) | (in[2] >> 6)];
30  out[3] = BIN_TO_BASE64[in[2] & 0x3F];
31  }
32 
33 }
34 
35 size_t base64_encode(char out[],
36  const uint8_t in[],
37  size_t input_length,
38  size_t& input_consumed,
39  bool final_inputs)
40  {
41  input_consumed = 0;
42 
43  size_t input_remaining = input_length;
44  size_t output_produced = 0;
45 
46  while(input_remaining >= 3)
47  {
48  do_base64_encode(out + output_produced, in + input_consumed);
49 
50  input_consumed += 3;
51  output_produced += 4;
52  input_remaining -= 3;
53  }
54 
55  if(final_inputs && input_remaining)
56  {
57  uint8_t remainder[3] = { 0 };
58  for(size_t i = 0; i != input_remaining; ++i)
59  remainder[i] = in[input_consumed + i];
60 
61  do_base64_encode(out + output_produced, remainder);
62 
63  size_t empty_bits = 8 * (3 - input_remaining);
64  size_t index = output_produced + 4 - 1;
65  while(empty_bits >= 8)
66  {
67  out[index--] = '=';
68  empty_bits -= 6;
69  }
70 
71  input_consumed += input_remaining;
72  output_produced += 4;
73  }
74 
75  return output_produced;
76  }
77 
78 std::string base64_encode(const uint8_t input[],
79  size_t input_length)
80  {
81  const size_t output_length = base64_encode_max_output(input_length);
82  std::string output(output_length, 0);
83 
84  size_t consumed = 0;
85  size_t produced = 0;
86 
87  if (output_length > 0)
88  {
89  produced = base64_encode(&output.front(),
90  input, input_length,
91  consumed, true);
92  }
93 
94  BOTAN_ASSERT_EQUAL(consumed, input_length, "Consumed the entire input");
95  BOTAN_ASSERT_EQUAL(produced, output.size(), "Produced expected size");
96 
97  return output;
98  }
99 
100 size_t base64_decode(uint8_t output[],
101  const char input[],
102  size_t input_length,
103  size_t& input_consumed,
104  bool final_inputs,
105  bool ignore_ws)
106  {
107  /*
108  * Base64 Decoder Lookup Table
109  * Warning: assumes ASCII encodings
110  */
111  static const uint8_t BASE64_TO_BIN[256] = {
112  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80,
113  0x80, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
114  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
115  0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
116  0xFF, 0xFF, 0xFF, 0x3E, 0xFF, 0xFF, 0xFF, 0x3F, 0x34, 0x35,
117  0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0xFF, 0xFF,
118  0xFF, 0x81, 0xFF, 0xFF, 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04,
119  0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
120  0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
121  0x19, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1A, 0x1B, 0x1C,
122  0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26,
123  0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30,
124  0x31, 0x32, 0x33, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
125  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
126  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
127  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
128  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
129  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
130  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
131  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
132  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
133  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
134  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
135  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
136  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
137  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
138 
139  uint8_t* out_ptr = output;
140  uint8_t decode_buf[4];
141  size_t decode_buf_pos = 0;
142  size_t final_truncate = 0;
143 
144  clear_mem(output, input_length * 3 / 4);
145 
146  for(size_t i = 0; i != input_length; ++i)
147  {
148  const uint8_t bin = BASE64_TO_BIN[static_cast<uint8_t>(input[i])];
149 
150  if(bin <= 0x3F)
151  {
152  decode_buf[decode_buf_pos] = bin;
153  decode_buf_pos += 1;
154  }
155  else if(!(bin == 0x81 || (bin == 0x80 && ignore_ws)))
156  {
157  std::string bad_char(1, input[i]);
158  if(bad_char == "\t")
159  bad_char = "\\t";
160  else if(bad_char == "\n")
161  bad_char = "\\n";
162  else if(bad_char == "\r")
163  bad_char = "\\r";
164 
165  throw Invalid_Argument(
166  std::string("base64_decode: invalid base64 character '") +
167  bad_char + "'");
168  }
169 
170  /*
171  * If we're at the end of the input, pad with 0s and truncate
172  */
173  if(final_inputs && (i == input_length - 1))
174  {
175  if(decode_buf_pos)
176  {
177  for(size_t j = decode_buf_pos; j != 4; ++j)
178  decode_buf[j] = 0;
179  final_truncate = (4 - decode_buf_pos);
180  decode_buf_pos = 4;
181  }
182  }
183 
184  if(decode_buf_pos == 4)
185  {
186  out_ptr[0] = (decode_buf[0] << 2) | (decode_buf[1] >> 4);
187  out_ptr[1] = (decode_buf[1] << 4) | (decode_buf[2] >> 2);
188  out_ptr[2] = (decode_buf[2] << 6) | decode_buf[3];
189 
190  out_ptr += 3;
191  decode_buf_pos = 0;
192  input_consumed = i+1;
193  }
194  }
195 
196  while(input_consumed < input_length &&
197  BASE64_TO_BIN[static_cast<uint8_t>(input[input_consumed])] == 0x80)
198  {
199  ++input_consumed;
200  }
201 
202  size_t written = (out_ptr - output) - final_truncate;
203 
204  return written;
205  }
206 
207 size_t base64_decode(uint8_t output[],
208  const char input[],
209  size_t input_length,
210  bool ignore_ws)
211  {
212  size_t consumed = 0;
213  size_t written = base64_decode(output, input, input_length,
214  consumed, true, ignore_ws);
215 
216  if(consumed != input_length)
217  throw Invalid_Argument("base64_decode: input did not have full bytes");
218 
219  return written;
220  }
221 
222 size_t base64_decode(uint8_t output[],
223  const std::string& input,
224  bool ignore_ws)
225  {
226  return base64_decode(output, input.data(), input.length(), ignore_ws);
227  }
228 
230  size_t input_length,
231  bool ignore_ws)
232  {
233  const size_t output_length = base64_decode_max_output(input_length);
234  secure_vector<uint8_t> bin(output_length);
235 
236  size_t written = base64_decode(bin.data(),
237  input,
238  input_length,
239  ignore_ws);
240 
241  bin.resize(written);
242  return bin;
243  }
244 
245 secure_vector<uint8_t> base64_decode(const std::string& input,
246  bool ignore_ws)
247  {
248  return base64_decode(input.data(), input.size(), ignore_ws);
249  }
250 
251 size_t base64_encode_max_output(size_t input_length)
252  {
253  return (round_up(input_length, 3) / 3) * 4;
254  }
255 
256 size_t base64_decode_max_output(size_t input_length)
257  {
258  return (round_up(input_length, 4) * 3) / 4;
259  }
260 
261 }
size_t base64_decode_max_output(size_t input_length)
Definition: base64.cpp:256
void clear_mem(T *ptr, size_t n)
Definition: mem_ops.h:97
size_t base64_encode_max_output(size_t input_length)
Definition: base64.cpp:251
size_t base64_encode(char out[], const uint8_t in[], size_t input_length, size_t &input_consumed, bool final_inputs)
Definition: base64.cpp:35
#define BOTAN_ASSERT_EQUAL(expr1, expr2, assertion_made)
Definition: assert.h:69
size_t base64_decode(uint8_t output[], const char input[], size_t input_length, size_t &input_consumed, bool final_inputs, bool ignore_ws)
Definition: base64.cpp:100
Definition: alg_id.cpp:13
std::vector< T, secure_allocator< T > > secure_vector
Definition: secmem.h:88
size_t round_up(size_t n, size_t align_to)
Definition: rounding.h:21