21 |
andreas |
1 |
/*
|
|
|
2 |
* Copyright (C) 2021 by Andreas Theofilu <andreas@theosys.at>
|
|
|
3 |
*
|
|
|
4 |
* This program is free software; you can redistribute it and/or modify
|
|
|
5 |
* it under the terms of the GNU General Public License as published by
|
|
|
6 |
* the Free Software Foundation; either version 3 of the License, or
|
|
|
7 |
* (at your option) any later version.
|
|
|
8 |
*
|
|
|
9 |
* This program is distributed in the hope that it will be useful,
|
|
|
10 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
11 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
12 |
* GNU General Public License for more details.
|
|
|
13 |
*
|
|
|
14 |
* You should have received a copy of the GNU General Public License
|
|
|
15 |
* along with this program; if not, write to the Free Software Foundation,
|
|
|
16 |
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
17 |
*/
|
|
|
18 |
|
|
|
19 |
#include "base64.h"
|
|
|
20 |
#include "terror.h"
|
|
|
21 |
|
|
|
22 |
static const BYTE from_base64[] = {
|
|
|
23 |
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
|
|
24 |
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
|
|
25 |
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, 255, 62, 255, 63,
|
|
|
26 |
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255, 255, 255, 255,
|
|
|
27 |
255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
|
|
|
28 |
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 63,
|
|
|
29 |
255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
|
|
|
30 |
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 255, 255, 255, 255, 255
|
|
|
31 |
};
|
|
|
32 |
|
|
|
33 |
static const char to_base64[] =
|
|
|
34 |
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
|
|
35 |
"abcdefghijklmnopqrstuvwxyz"
|
|
|
36 |
"0123456789+/";
|
|
|
37 |
|
|
|
38 |
|
|
|
39 |
std::string Base64::encode(const std::vector<BYTE>& buf)
|
|
|
40 |
{
|
|
|
41 |
DECL_TRACER("Base64::encode(const std::vector<BYTE>& buf)");
|
|
|
42 |
|
|
|
43 |
if (buf.empty())
|
|
|
44 |
return ""; // Avoid dereferencing buf if it's empty
|
|
|
45 |
|
|
|
46 |
return encode(&buf[0], (unsigned int)buf.size());
|
|
|
47 |
}
|
|
|
48 |
|
|
|
49 |
std::string Base64::encode(const BYTE* buf, unsigned int bufLen)
|
|
|
50 |
{
|
|
|
51 |
DECL_TRACER("Base64::encode(const BYTE* buf, unsigned int bufLen)");
|
|
|
52 |
|
|
|
53 |
// Calculate how many bytes that needs to be added to get a multiple of 3
|
|
|
54 |
size_t missing = 0;
|
|
|
55 |
size_t ret_size = bufLen;
|
|
|
56 |
|
|
|
57 |
while ((ret_size % 3) != 0)
|
|
|
58 |
{
|
|
|
59 |
++ret_size;
|
|
|
60 |
++missing;
|
|
|
61 |
}
|
|
|
62 |
|
|
|
63 |
// Expand the return string size to a multiple of 4
|
|
|
64 |
ret_size = 4*ret_size/3;
|
|
|
65 |
|
|
|
66 |
std::string ret;
|
|
|
67 |
ret.reserve(ret_size);
|
|
|
68 |
|
|
|
69 |
for (unsigned int i = 0; i < ret_size / 4; ++i)
|
|
|
70 |
{
|
|
|
71 |
// Read a group of three bytes (avoid buffer overrun by replacing with 0)
|
|
|
72 |
size_t index = i*3;
|
|
|
73 |
BYTE b3[3];
|
|
|
74 |
b3[0] = (index+0 < bufLen) ? buf[index+0] : 0;
|
|
|
75 |
b3[1] = (index+1 < bufLen) ? buf[index+1] : 0;
|
|
|
76 |
b3[2] = (index+2 < bufLen) ? buf[index+2] : 0;
|
|
|
77 |
|
|
|
78 |
// Transform into four base 64 characters
|
|
|
79 |
BYTE b4[4];
|
|
|
80 |
b4[0] = ((b3[0] & 0xfc) >> 2);
|
|
|
81 |
b4[1] = ((b3[0] & 0x03) << 4) + ((b3[1] & 0xf0) >> 4);
|
|
|
82 |
b4[2] = ((b3[1] & 0x0f) << 2) + ((b3[2] & 0xc0) >> 6);
|
|
|
83 |
b4[3] = ((b3[2] & 0x3f) << 0);
|
|
|
84 |
|
|
|
85 |
// Add the base 64 characters to the return value
|
|
|
86 |
ret.push_back(to_base64[b4[0]]);
|
|
|
87 |
ret.push_back(to_base64[b4[1]]);
|
|
|
88 |
ret.push_back(to_base64[b4[2]]);
|
|
|
89 |
ret.push_back(to_base64[b4[3]]);
|
|
|
90 |
}
|
|
|
91 |
|
|
|
92 |
// Replace data that is invalid (always as many as there are missing bytes)
|
|
|
93 |
for (size_t i=0; i<missing; ++i)
|
|
|
94 |
ret[ret_size - i - 1] = '=';
|
|
|
95 |
|
|
|
96 |
return ret;
|
|
|
97 |
}
|
|
|
98 |
|
|
|
99 |
std::vector<BYTE> Base64::decode(std::string encoded_string)
|
|
|
100 |
{
|
|
|
101 |
DECL_TRACER("Base64::decode(std::string encoded_string)");
|
|
|
102 |
|
|
|
103 |
// Make sure string length is a multiple of 4
|
|
|
104 |
while ((encoded_string.size() % 4) != 0)
|
|
|
105 |
encoded_string.push_back('=');
|
|
|
106 |
|
|
|
107 |
size_t encoded_size = encoded_string.size();
|
|
|
108 |
std::vector<BYTE> ret;
|
|
|
109 |
ret.reserve(3*encoded_size/4);
|
|
|
110 |
|
|
|
111 |
for (size_t i=0; i<encoded_size; i += 4)
|
|
|
112 |
{
|
|
|
113 |
// Get values for each group of four base 64 characters
|
|
|
114 |
BYTE b4[4];
|
|
|
115 |
b4[0] = (encoded_string[i+0] <= 'z') ? from_base64[(int)encoded_string[i+0]] : 0xff;
|
|
|
116 |
b4[1] = (encoded_string[i+1] <= 'z') ? from_base64[(int)encoded_string[i+1]] : 0xff;
|
|
|
117 |
b4[2] = (encoded_string[i+2] <= 'z') ? from_base64[(int)encoded_string[i+2]] : 0xff;
|
|
|
118 |
b4[3] = (encoded_string[i+3] <= 'z') ? from_base64[(int)encoded_string[i+3]] : 0xff;
|
|
|
119 |
|
|
|
120 |
// Transform into a group of three bytes
|
|
|
121 |
BYTE b3[3];
|
|
|
122 |
b3[0] = ((b4[0] & 0x3f) << 2) + ((b4[1] & 0x30) >> 4);
|
|
|
123 |
b3[1] = ((b4[1] & 0x0f) << 4) + ((b4[2] & 0x3c) >> 2);
|
|
|
124 |
b3[2] = ((b4[2] & 0x03) << 6) + ((b4[3] & 0x3f) >> 0);
|
|
|
125 |
|
|
|
126 |
// Add the byte to the return value if it isn't part of an '=' character (indicated by 0xff)
|
|
|
127 |
if (b4[1] != 0xff) ret.push_back(b3[0]);
|
|
|
128 |
if (b4[2] != 0xff) ret.push_back(b3[1]);
|
|
|
129 |
if (b4[3] != 0xff) ret.push_back(b3[2]);
|
|
|
130 |
}
|
|
|
131 |
|
|
|
132 |
return ret;
|
|
|
133 |
}
|
|
|
134 |
|