Botan  1.10.9
base64.cpp
Go to the documentation of this file.
1 /*
2 * Base64 Encoding and Decoding
3 * (C) 2010 Jack Lloyd
4 *
5 * Distributed under the terms of the Botan license
6 */
7 
8 #include <botan/base64.h>
9 #include <botan/mem_ops.h>
10 #include <botan/internal/rounding.h>
11 #include <botan/internal/assert.h>
12 #include <stdexcept>
13 
14 namespace Botan {
15 
16 namespace {
17 
18 static const byte BIN_TO_BASE64[64] = {
19  'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
20  'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
21  'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
22  'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
23  '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
24 };
25 
26 void do_base64_encode(char out[4], const byte in[3])
27  {
28  out[0] = BIN_TO_BASE64[((in[0] & 0xFC) >> 2)];
29  out[1] = BIN_TO_BASE64[((in[0] & 0x03) << 4) | (in[1] >> 4)];
30  out[2] = BIN_TO_BASE64[((in[1] & 0x0F) << 2) | (in[2] >> 6)];
31  out[3] = BIN_TO_BASE64[((in[2] & 0x3F) )];
32  }
33 
34 }
35 
36 size_t base64_encode(char out[],
37  const byte in[],
38  size_t input_length,
39  size_t& input_consumed,
40  bool final_inputs)
41  {
42  input_consumed = 0;
43 
44  size_t input_remaining = input_length;
45  size_t output_produced = 0;
46 
47  while(input_remaining >= 3)
48  {
49  do_base64_encode(out + output_produced, in + input_consumed);
50 
51  input_consumed += 3;
52  output_produced += 4;
53  input_remaining -= 3;
54  }
55 
56  if(final_inputs && input_remaining)
57  {
58  byte remainder[3] = { 0 };
59  for(size_t i = 0; i != input_remaining; ++i)
60  remainder[i] = in[input_consumed + i];
61 
62  do_base64_encode(out + output_produced, remainder);
63 
64  size_t empty_bits = 8 * (3 - input_remaining);
65  size_t index = output_produced + 4 - 1;
66  while(empty_bits >= 8)
67  {
68  out[index--] = '=';
69  empty_bits -= 6;
70  }
71 
72  input_consumed += input_remaining;
73  output_produced += 4;
74  }
75 
76  return output_produced;
77  }
78 
79 std::string base64_encode(const byte input[],
80  size_t input_length)
81  {
82  std::string output((round_up<size_t>(input_length, 3) / 3) * 4, 0);
83 
84  size_t consumed = 0;
85  size_t produced = base64_encode(&output[0],
86  input, input_length,
87  consumed, true);
88 
89  BOTAN_ASSERT_EQUAL(consumed, input_length, "Did not consume all input");
90  BOTAN_ASSERT_EQUAL(produced, output.size(), "Did not produce right amount");
91 
92  return output;
93  }
94 
95 std::string base64_encode(const MemoryRegion<byte>& input)
96  {
97  return base64_encode(&input[0], input.size());
98  }
99 
100 size_t base64_decode(byte 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 byte 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  byte* out_ptr = output;
140  byte 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 byte bin = BASE64_TO_BIN[static_cast<byte>(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 std::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 i = decode_buf_pos; i != 4; ++i)
178  decode_buf[i] = 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<byte>(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(byte 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 std::invalid_argument("base64_decode: input did not have full bytes");
218 
219  return written;
220  }
221 
222 size_t base64_decode(byte output[],
223  const std::string& input,
224  bool ignore_ws)
225  {
226  return base64_decode(output, &input[0], input.length(), ignore_ws);
227  }
228 
230  size_t input_length,
231  bool ignore_ws)
232  {
233  SecureVector<byte> bin((round_up<size_t>(input_length, 4) * 3) / 4);
234 
235  size_t written = base64_decode(&bin[0],
236  input,
237  input_length,
238  ignore_ws);
239 
240  bin.resize(written);
241  return bin;
242  }
243 
244 SecureVector<byte> base64_decode(const std::string& input,
245  bool ignore_ws)
246  {
247  return base64_decode(&input[0], input.size(), ignore_ws);
248  }
249 
250 
251 }
void resize(size_t n)
Definition: secmem.h:211
size_t base64_decode(byte output[], const char input[], size_t input_length, size_t &input_consumed, bool final_inputs, bool ignore_ws)
Definition: base64.cpp:100
void clear_mem(T *ptr, size_t n)
Definition: mem_ops.h:32
unsigned char byte
Definition: types.h:22
size_t size() const
Definition: secmem.h:29
#define BOTAN_ASSERT_EQUAL(value1, value2, msg)
Definition: assert.h:29
size_t base64_encode(char out[], const byte in[], size_t input_length, size_t &input_consumed, bool final_inputs)
Definition: base64.cpp:36