Botan 1.10.17
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
14namespace Botan {
15
16namespace {
17
18static 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
26void 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
36size_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
79std::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
95std::string base64_encode(const MemoryRegion<byte>& input)
96 {
97 return base64_encode(&input[0], input.size());
98 }
99
100size_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
207size_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
222size_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
244SecureVector<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}
#define BOTAN_ASSERT_EQUAL(value1, value2, msg)
Definition assert.h:29
size_t size() const
Definition secmem.h:29
void resize(size_t n)
Definition secmem.h:217
T round_up(T n, T align_to)
Definition rounding.h:22
size_t base64_encode(char out[], const byte in[], size_t input_length, size_t &input_consumed, bool final_inputs)
Definition base64.cpp:36
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