OpenVPN 3 Core Library
Loading...
Searching...
No Matches
base64.hpp
Go to the documentation of this file.
1// OpenVPN -- An application to securely tunnel IP networks
2// over a single port, with support for SSL/TLS-based
3// session authentication and key exchange,
4// packet encryption, packet authentication, and
5// packet compression.
6//
7// Copyright (C) 2012- OpenVPN Inc.
8//
9// SPDX-License-Identifier: MPL-2.0 OR AGPL-3.0-only WITH openvpn3-openssl-exception
10//
11
12// General-purpose base64 encode and decode.
13
14#ifndef OPENVPN_COMMON_BASE64_H
15#define OPENVPN_COMMON_BASE64_H
16
17#include <string>
18#include <cstring> // for std::memset, std::strlen
19#include <algorithm> // for std::min
20#include <cstddef> // for ptrdiff_t
21
24
25namespace openvpn {
26
27class Base64
28{
29
31 {
32 public:
33 using value_type = unsigned char;
34
35 public:
36 ConstUCharWrap(const value_type *data, size_t size)
37 : data_(data),
38 size_(size)
39 {
40 }
41
42 size_t size() const
43 {
44 return size_;
45 }
46 value_type operator[](const size_t i) const
47 {
48 return data_[i];
49 }
50
51
52 private:
54 size_t size_;
55 };
56
57 public:
58 OPENVPN_SIMPLE_EXCEPTION(base64_decode_out_of_bound_error);
59
60 private:
61 // Minimal class to minic the container our decode method expects
63 {
64 public:
65 using value_type = unsigned char;
66
67 public:
69 : data(data), size(size), index(0)
70 {
71 }
72
74 {
75 if (index >= size)
76 throw base64_decode_out_of_bound_error();
77
78 data[index++] = c;
79 }
80
82 size_t size;
83 size_t index;
84 };
85
86 public:
87 OPENVPN_SIMPLE_EXCEPTION(base64_bad_map);
88 OPENVPN_SIMPLE_EXCEPTION(base64_decode_error);
89
90 // altmap is "+/=" by default
91 // another possible encoding for URLs: "-_."
92 Base64(const char *altmap = nullptr)
93 {
94 // build encoding map
95 {
96 unsigned int i;
97 unsigned char j = 65;
98 for (i = 0; i < 62; ++i)
99 {
100 enc[i] = j++;
101 if (j == 91)
102 j = 97;
103 else if (j == 123)
104 j = 48;
105 }
106 if (!altmap)
107 altmap = "+/=";
108 if (std::strlen(altmap) != 3)
109 throw base64_bad_map();
110 enc[62] = (unsigned char)altmap[0];
111 enc[63] = (unsigned char)altmap[1];
112 equal = (unsigned char)altmap[2];
113 }
114
115 // build decoding map
116 {
117 std::memset(dec, 0xFF, 128);
118 for (unsigned int i = 0; i < 64; ++i)
119 {
120 const unsigned char c = enc[i];
121 if (c >= 128)
122 throw base64_bad_map();
123 dec[c] = (unsigned char)i;
124 }
125 }
126 }
127
128 static size_t decode_size_max(const size_t encode_size)
129 {
130 return encode_size;
131 }
132
133 static size_t encode_size_max(const size_t decode_size)
134 {
135 return decode_size * 4 / 3 + 4;
136 }
137
138 template <typename V>
139 std::string encode(const V &data) const
140 {
141 char *s, *p;
142 size_t i;
143 unsigned int c;
144 const size_t size = data.size();
145
146 p = s = new char[encode_size_max(size)];
147 for (i = 0; i < size;)
148 {
149 c = static_cast<unsigned char>(data[i++]) << 8;
150 if (i < size)
151 c += static_cast<unsigned char>(data[i]);
152 i++;
153 c <<= 8;
154 if (i < size)
155 c += static_cast<unsigned char>(data[i]);
156 i++;
157 p[0] = enc[(c & 0x00fc0000) >> 18];
158 p[1] = enc[(c & 0x0003f000) >> 12];
159 p[2] = enc[(c & 0x00000fc0) >> 6];
160 p[3] = enc[c & 0x0000003f];
161 if (i > size)
162 p[3] = equal;
163 if (i > size + 1)
164 p[2] = equal;
165 p += 4;
166 }
167 *p = '\0';
168 const std::string ret(s);
169 delete[] s;
170 return ret;
171 }
172
173 std::string encode(const void *data, size_t size) const
174 {
175 return encode(ConstUCharWrap((const unsigned char *)data, size));
176 }
177
186 size_t decode(void *data, size_t len, const std::string &str) const
187 {
188 UCharWrap ret((unsigned char *)data, len);
189 decode(ret, str);
190 return ret.index;
191 }
192
193 std::string decode(const std::string &str) const
194 {
195 std::string ret;
196 ret.reserve(str.length());
197 decode(ret, str);
198 return ret;
199 }
200
201 template <typename V>
202 void decode(V &dest, const std::string &str) const
203 {
204 const char *endp = str.c_str() + str.length();
205 for (const char *p = str.c_str(); p < endp; p += 4)
206 {
207 using vvalue_t = typename V::value_type;
208 unsigned int marker;
209 const unsigned int val = token_decode(p, std::min(endp - p, ptrdiff_t(4)), marker);
210 dest.push_back(static_cast<vvalue_t>((val >> 16) & 0xff));
211 if (marker < 2)
212 dest.push_back(static_cast<vvalue_t>((val >> 8) & 0xff));
213 if (marker < 1)
214 dest.push_back(static_cast<vvalue_t>(val & 0xff));
215 }
216 }
217
218 template <typename V>
219 bool is_base64(const V &data, const size_t expected_decoded_length) const
220 {
221 const size_t size = data.size();
222 if (size != encoded_len(expected_decoded_length))
223 return false;
224 const size_t eq_begin = size - num_eq(expected_decoded_length);
225 for (size_t i = 0; i < size; ++i)
226 {
227 const char c = data[i];
228 if (i < eq_begin)
229 {
230 if (!is_base64_char(c))
231 return false;
232 }
233 else
234 {
235 if (c != equal)
236 return false;
237 }
238 }
239 return true;
240 }
241
242 private:
243 bool is_base64_char(const char c) const
244 {
245 const size_t idx = c;
246 return idx < 128 && dec[idx] != 0xFF;
247 }
248
249 unsigned int decode_base64_char(const char c) const
250 {
251 const size_t idx = c;
252 if (idx >= 128)
253 throw base64_decode_error();
254 const unsigned int v = dec[idx];
255 if (v == 0xFF)
256 throw base64_decode_error();
257 return v;
258 }
259
260 unsigned int token_decode(const char *token, const ptrdiff_t len, unsigned int &marker) const
261 {
262 size_t i;
263 unsigned int val = 0;
264 marker = 0; // number of equal chars seen
265 if (len < 4)
266 throw base64_decode_error();
267 for (i = 0; i < 4; i++)
268 {
269 val <<= 6;
270 if (token[i] == equal)
271 marker++;
272 else if (marker > 0)
273 throw base64_decode_error();
274 else
275 val += decode_base64_char(token[i]);
276 }
277 if (marker > 2)
278 throw base64_decode_error();
279 return val;
280 }
281
282 static size_t encoded_len(const size_t decoded_len)
283 {
284 return (decoded_len * 4 / 3 + 3) & ~3;
285 }
286
287 static size_t num_eq(const size_t decoded_len)
288 {
289 return (-1 - decoded_len) % 3;
290 }
291
292 unsigned char enc[64];
293 unsigned char dec[128];
294 unsigned char equal;
295};
296
297// provide a static Base64 object
298
299inline const Base64 *base64; // GLOBAL
300inline const Base64 *base64_urlsafe; // GLOBAL
301
303{
304 if (!base64)
305 base64 = new Base64();
306 if (!base64_urlsafe)
307 base64_urlsafe = new Base64("-_.");
308}
309
311{
312 if (base64)
313 {
314 delete base64;
315 base64 = nullptr;
316 }
317 if (base64_urlsafe)
318 {
319 delete base64_urlsafe;
320 base64_urlsafe = nullptr;
321 }
322}
323
324} // namespace openvpn
325
326#endif
value_type operator[](const size_t i) const
Definition base64.hpp:46
ConstUCharWrap(const value_type *data, size_t size)
Definition base64.hpp:36
const value_type * data_
Definition base64.hpp:53
void push_back(value_type c)
Definition base64.hpp:73
UCharWrap(value_type *data, size_t size)
Definition base64.hpp:68
unsigned char value_type
Definition base64.hpp:65
static size_t encode_size_max(const size_t decode_size)
Definition base64.hpp:133
unsigned char equal
Definition base64.hpp:294
bool is_base64_char(const char c) const
Definition base64.hpp:243
OPENVPN_SIMPLE_EXCEPTION(base64_bad_map)
bool is_base64(const V &data, const size_t expected_decoded_length) const
Definition base64.hpp:219
Base64(const char *altmap=nullptr)
Definition base64.hpp:92
unsigned int decode_base64_char(const char c) const
Definition base64.hpp:249
void decode(V &dest, const std::string &str) const
Definition base64.hpp:202
unsigned int token_decode(const char *token, const ptrdiff_t len, unsigned int &marker) const
Definition base64.hpp:260
static size_t num_eq(const size_t decoded_len)
Definition base64.hpp:287
std::string decode(const std::string &str) const
Definition base64.hpp:193
static size_t decode_size_max(const size_t encode_size)
Definition base64.hpp:128
static size_t encoded_len(const size_t decoded_len)
Definition base64.hpp:282
std::string encode(const void *data, size_t size) const
Definition base64.hpp:173
OPENVPN_SIMPLE_EXCEPTION(base64_decode_error)
OPENVPN_SIMPLE_EXCEPTION(base64_decode_out_of_bound_error)
std::string encode(const V &data) const
Definition base64.hpp:139
size_t decode(void *data, size_t len, const std::string &str) const
Definition base64.hpp:186
unsigned char enc[64]
Definition base64.hpp:292
unsigned char dec[128]
Definition base64.hpp:293
Support deferred server-side state creation when client connects.
Definition ovpncli.cpp:95
const Base64 * base64_urlsafe
Definition base64.hpp:300
const Base64 * base64
Definition base64.hpp:299
void base64_uninit_static()
Definition base64.hpp:310
void base64_init_static()
Definition base64.hpp:302
std::string ret