Line data Source code
1 : // base64 encodig and decoding.
2 : //
3 : // Based on the implementations by
4 : // Jouni Malinen <j@w1.fi> and contributors from wpa_supplicant and hostapd in
5 : // http://web.mit.edu/freebsd/head/contrib/wpa/ and
6 : // http://web.mit.edu/freebsd/head/contrib/wpa/src/utils/base64.c and
7 : // http://web.mit.edu/freebsd/head/contrib/wpa/src/utils/base64.h
8 : //
9 : // Published under a 3-clause BSD license
10 : //
11 :
12 : #include <string>
13 : #include <cstring>
14 : #include <stdexcept>
15 :
16 : #include "crpropa/base64.h"
17 :
18 : namespace crpropa
19 : {
20 :
21 : //Alphabet used
22 : static const unsigned char encode_alphabet[65] =
23 : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
24 : static int decode_alphabet[256] = {-1};
25 :
26 : /// Encodes data
27 99 : std::string Base64::encode(const unsigned char *src, size_t len)
28 : {
29 99 : size_t olen = 4*((len + 2) / 3); /* 3-byte blocks to 4-byte */
30 :
31 99 : if (olen < len)
32 0 : throw std::runtime_error("Integer overflow in Base64::encoding, data to large!");
33 :
34 : std::string outStr;
35 : outStr.resize(olen);
36 :
37 : unsigned char *out = (unsigned char*) outStr.c_str();
38 : unsigned char *pos = out;
39 : const unsigned char *end, *in;
40 :
41 99 : end = src + len;
42 : in = src;
43 6666 : while (end - in >= 3) {
44 6567 : *pos++ = encode_alphabet[in[0] >> 2];
45 6567 : *pos++ = encode_alphabet[((in[0] & 0x03) << 4) | (in[1] >> 4)];
46 6567 : *pos++ = encode_alphabet[((in[1] & 0x0f) << 2) | (in[2] >> 6)];
47 6567 : *pos++ = encode_alphabet[in[2] & 0x3f];
48 6567 : in += 3;
49 : }
50 :
51 99 : if (end - in) {
52 66 : *pos++ = encode_alphabet[in[0] >> 2];
53 66 : if (end - in == 1) {
54 33 : *pos++ = encode_alphabet[(in[0] & 0x03) << 4];
55 33 : *pos++ = '=';
56 : }
57 : else {
58 33 : *pos++ = encode_alphabet[((in[0] & 0x03) << 4) |
59 33 : (in[1] >> 4)];
60 33 : *pos++ = encode_alphabet[(in[1] & 0x0f) << 2];
61 : }
62 66 : *pos++ = '=';
63 : }
64 :
65 99 : return outStr;
66 : }
67 :
68 :
69 100 : std::string Base64::decode(const std::string &data)
70 : {
71 : const unsigned char *src = (unsigned char*) data.c_str();
72 : size_t len = data.size();
73 :
74 100 : if (decode_alphabet[0] == -1)
75 : { // build decode alphabet
76 : std::memset(decode_alphabet, 0x80, 256);
77 65 : for (size_t i = 0; i < sizeof(encode_alphabet) - 1; i++)
78 64 : decode_alphabet[encode_alphabet[i]] = (unsigned char) i;
79 1 : decode_alphabet['='] = 0;
80 : }
81 :
82 : size_t olen = 0;
83 26656 : for (size_t i = 0; i < len; i++) {
84 26556 : if (decode_alphabet[src[i]] != 0x80)
85 26556 : olen++;
86 : }
87 :
88 100 : if (olen == 0 || olen % 4)
89 0 : throw std::runtime_error("Base64 decode, invalid input size");
90 :
91 100 : olen = olen / 4 * 3;
92 : std::string str;
93 : str.resize(olen);
94 :
95 : unsigned char *out = (unsigned char*) str.c_str();
96 : unsigned char *pos = out;
97 :
98 : size_t count = 0;
99 : int pad = 0;
100 : unsigned char block[4];
101 26589 : for (size_t i = 0; i < len; i++) {
102 26556 : unsigned char tmp = decode_alphabet[src[i]];
103 26556 : if (tmp == 0x80)
104 0 : continue;
105 :
106 26556 : if (src[i] == '=')
107 101 : pad++;
108 26556 : block[count] = tmp;
109 26556 : count++;
110 26556 : if (count == 4) {
111 6639 : *pos++ = (block[0] << 2) | (block[1] >> 4);
112 6639 : *pos++ = (block[1] << 4) | (block[2] >> 2);
113 6639 : *pos++ = (block[2] << 6) | block[3];
114 : count = 0;
115 6639 : if (pad) {
116 67 : if (pad == 1)
117 : pos--;
118 34 : else if (pad == 2)
119 : pos -= 2;
120 : else {
121 0 : throw std::runtime_error("Base64 decode, invalid padding");
122 : }
123 : break;
124 : }
125 : }
126 : }
127 100 : return str;
128 : }
129 : };
|