JWT-CPP v0.7.2
A header only library for creating and validating JSON Web Tokens (JWT) in C++
Loading...
Searching...
No Matches
base.h
1#ifndef JWT_CPP_BASE_H
2#define JWT_CPP_BASE_H
3
4#include <algorithm>
5#include <array>
6#include <cstdint>
7#include <stdexcept>
8#include <string>
9#include <vector>
10
11#ifdef __has_cpp_attribute
12#if __has_cpp_attribute(fallthrough)
13#define JWT_FALLTHROUGH [[fallthrough]]
14#endif
15#endif
16
17#ifndef JWT_FALLTHROUGH
18#define JWT_FALLTHROUGH
19#endif
20
21namespace jwt {
25 namespace alphabet {
32 struct base64 {
33 static const std::array<char, 64>& data() {
34 static constexpr std::array<char, 64> data{
35 {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
36 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
37 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
38 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'}};
39 return data;
40 }
41 static const std::array<int8_t, 256>& rdata() {
42 static constexpr std::array<int8_t, 256> rdata{{
43 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
44 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
45 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6,
46 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
47 -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
48 49, 50, 51, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
49 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
50 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
51 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
52 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
53 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
54 }};
55 return rdata;
56 }
57 static const std::string& fill() {
58 static const std::string fill{"="};
59 return fill;
60 }
61 };
62
71 struct base64url {
72 static const std::array<char, 64>& data() {
73 static constexpr std::array<char, 64> data{
74 {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
75 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
76 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
77 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_'}};
78 return data;
79 }
80 static const std::array<int8_t, 256>& rdata() {
81 static constexpr std::array<int8_t, 256> rdata{{
82 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
83 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1,
84 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6,
85 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, 63,
86 -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
87 49, 50, 51, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
88 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
89 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
90 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
91 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
92 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
93 }};
94 return rdata;
95 }
96 static const std::string& fill() {
97 static const std::string fill{"%3d"};
98 return fill;
99 }
100 };
101 namespace helper {
109 static const std::array<char, 64>& data() {
110 static constexpr std::array<char, 64> data{
111 {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
112 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
113 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
114 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_'}};
115 return data;
116 }
117 static const std::array<int8_t, 256>& rdata() {
118 static constexpr std::array<int8_t, 256> rdata{{
119 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
120 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1,
121 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6,
122 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, 63,
123 -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
124 49, 50, 51, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
125 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
126 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
127 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
128 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
129 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
130 }};
131 return rdata;
132 }
133 static const std::vector<std::string>& fill() {
134 static const std::vector<std::string> fill{"%3D", "%3d"};
135 return fill;
136 }
137 };
138 } // namespace helper
139
140 inline uint32_t index(const std::array<int8_t, 256>& rdata, char symbol) {
141 auto index = rdata[static_cast<unsigned char>(symbol)];
142 if (index <= -1) { throw std::runtime_error("Invalid input: not within alphabet"); }
143 return static_cast<uint32_t>(index);
144 }
145 } // namespace alphabet
146
150 namespace base {
151 namespace details {
152 struct padding {
153 size_t count = 0;
154 size_t length = 0;
155
156 padding() = default;
157 padding(size_t count, size_t length) : count(count), length(length) {}
158
159 padding operator+(const padding& p) { return padding(count + p.count, length + p.length); }
160
161 friend bool operator==(const padding& lhs, const padding& rhs) {
162 return lhs.count == rhs.count && lhs.length == rhs.length;
163 }
164 };
165
166 inline padding count_padding(const std::string& base, const std::vector<std::string>& fills) {
167 for (const auto& fill : fills) {
168 // Try the next one if it does not match the end
169 if (base.size() < fill.size() || base.compare(base.size() - fill.size(), fill.size(), fill) != 0)
170 continue;
171
172 auto end = base.size() - fill.size();
173 while (end > fill.size() && base.compare(end - fill.size(), fill.size(), fill) == 0)
174 end -= fill.size();
175 return {(base.size() - end) / fill.size(), base.size() - end};
176 }
177
178 return {};
179 }
180
181 inline std::string encode(const std::string& bin, const std::array<char, 64>& alphabet,
182 const std::string& fill) {
183 size_t size = bin.size();
184 std::string res;
185
186 // clear incomplete bytes
187 size_t fast_size = size - size % 3;
188 for (size_t i = 0; i < fast_size;) {
189 uint32_t octet_a = static_cast<unsigned char>(bin[i++]);
190 uint32_t octet_b = static_cast<unsigned char>(bin[i++]);
191 uint32_t octet_c = static_cast<unsigned char>(bin[i++]);
192
193 uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c;
194
195 res += alphabet[(triple >> 3 * 6) & 0x3F];
196 res += alphabet[(triple >> 2 * 6) & 0x3F];
197 res += alphabet[(triple >> 1 * 6) & 0x3F];
198 res += alphabet[(triple >> 0 * 6) & 0x3F];
199 }
200
201 if (fast_size == size) return res;
202
203 size_t mod = size % 3;
204
205 uint32_t octet_a = fast_size < size ? static_cast<unsigned char>(bin[fast_size++]) : 0;
206 uint32_t octet_b = fast_size < size ? static_cast<unsigned char>(bin[fast_size++]) : 0;
207 uint32_t octet_c = fast_size < size ? static_cast<unsigned char>(bin[fast_size++]) : 0;
208
209 uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c;
210
211 switch (mod) {
212 case 1:
213 res += alphabet[(triple >> 3 * 6) & 0x3F];
214 res += alphabet[(triple >> 2 * 6) & 0x3F];
215 res += fill;
216 res += fill;
217 break;
218 case 2:
219 res += alphabet[(triple >> 3 * 6) & 0x3F];
220 res += alphabet[(triple >> 2 * 6) & 0x3F];
221 res += alphabet[(triple >> 1 * 6) & 0x3F];
222 res += fill;
223 break;
224 default: break;
225 }
226
227 return res;
228 }
229
230 inline std::string decode(const std::string& base, const std::array<int8_t, 256>& rdata,
231 const std::vector<std::string>& fill) {
232 const auto pad = count_padding(base, fill);
233 if (pad.count > 2) throw std::runtime_error("Invalid input: too much fill");
234
235 const size_t size = base.size() - pad.length;
236 if ((size + pad.count) % 4 != 0) throw std::runtime_error("Invalid input: incorrect total size");
237
238 size_t out_size = size / 4 * 3;
239 std::string res;
240 res.reserve(out_size);
241
242 auto get_sextet = [&](size_t offset) { return alphabet::index(rdata, base[offset]); };
243
244 size_t fast_size = size - size % 4;
245 for (size_t i = 0; i < fast_size;) {
246 uint32_t sextet_a = get_sextet(i++);
247 uint32_t sextet_b = get_sextet(i++);
248 uint32_t sextet_c = get_sextet(i++);
249 uint32_t sextet_d = get_sextet(i++);
250
251 uint32_t triple =
252 (sextet_a << 3 * 6) + (sextet_b << 2 * 6) + (sextet_c << 1 * 6) + (sextet_d << 0 * 6);
253
254 res += static_cast<char>((triple >> 2 * 8) & 0xFFU);
255 res += static_cast<char>((triple >> 1 * 8) & 0xFFU);
256 res += static_cast<char>((triple >> 0 * 8) & 0xFFU);
257 }
258
259 if (pad.count == 0) return res;
260
261 uint32_t triple = (get_sextet(fast_size) << 3 * 6) + (get_sextet(fast_size + 1) << 2 * 6);
262
263 switch (pad.count) {
264 case 1:
265 triple |= (get_sextet(fast_size + 2) << 1 * 6);
266 res += static_cast<char>((triple >> 2 * 8) & 0xFFU);
267 res += static_cast<char>((triple >> 1 * 8) & 0xFFU);
268 break;
269 case 2: res += static_cast<char>((triple >> 2 * 8) & 0xFFU); break;
270 default: break;
271 }
272
273 return res;
274 }
275
276 inline std::string decode(const std::string& base, const std::array<int8_t, 256>& rdata,
277 const std::string& fill) {
278 return decode(base, rdata, std::vector<std::string>{fill});
279 }
280
281 inline std::string pad(const std::string& base, const std::string& fill) {
282 std::string padding;
283 switch (base.size() % 4) {
284 case 1: padding += fill; JWT_FALLTHROUGH;
285 case 2: padding += fill; JWT_FALLTHROUGH;
286 case 3: padding += fill; JWT_FALLTHROUGH;
287 default: break;
288 }
289
290 return base + padding;
291 }
292
293 inline std::string trim(const std::string& base, const std::string& fill) {
294 auto pos = base.find(fill);
295 return base.substr(0, pos);
296 }
297 } // namespace details
298
309 template<typename T>
310 std::string encode(const std::string& bin) {
311 return details::encode(bin, T::data(), T::fill());
312 }
313
323 template<typename T>
324 std::string decode(const std::string& base) {
325 return details::decode(base, T::rdata(), T::fill());
326 }
327
337 template<typename T>
338 std::string pad(const std::string& base) {
339 return details::pad(base, T::fill());
340 }
341
351 template<typename T>
352 std::string trim(const std::string& base) {
353 return details::trim(base, T::fill());
354 }
355 } // namespace base
356} // namespace jwt
357
358#endif
character maps when encoding and decoding
Definition base.h:25
A collection of fellable functions for working with base64 and base64url.
Definition base.h:150
std::string trim(const std::string &base)
Generic base64 trimming.
Definition base.h:352
std::string decode(const std::string &base)
Generic base64 decoding.
Definition base.h:324
std::string pad(const std::string &base)
Generic base64 padding.
Definition base.h:338
std::string encode(const std::string &bin)
Generic base64 encoding.
Definition base.h:310
JSON Web Token.
Definition base.h:21
valid list of character when working with Base64
Definition base.h:32
valid list of character when working with Base64URL
Definition base.h:71
A General purpose base64url alphabet respecting the URI Case Normalization
Definition base.h:108