Goby3 3.2.3
2025.05.13
Loading...
Searching...
No Matches
base.h
Go to the documentation of this file.
1#ifndef JWT_CPP_BASE_H
2#define JWT_CPP_BASE_H
3
4#include <array>
5#include <stdexcept>
6#include <string>
7
8#ifdef __has_cpp_attribute
9#if __has_cpp_attribute(fallthrough)
10#define JWT_FALLTHROUGH [[fallthrough]]
11#endif
12#endif
13
14#ifndef JWT_FALLTHROUGH
15#define JWT_FALLTHROUGH
16#endif
17
18namespace jwt
19{
23namespace alphabet
24{
28struct base64
29{
30 static const std::array<char, 64>& data()
31 {
32 static constexpr std::array<char, 64> data{
33 {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
34 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
35 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
36 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'}};
37 return data;
38 }
39 static const std::string& fill()
40 {
41 static std::string fill{"="};
42 return fill;
43 }
44};
49{
50 static const std::array<char, 64>& data()
51 {
52 static constexpr std::array<char, 64> data{
53 {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
54 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
55 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
56 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_'}};
57 return data;
58 }
59 static const std::string& fill()
60 {
61 static std::string fill{"%3d"};
62 return fill;
63 }
64};
65} // namespace alphabet
66
70class base
71{
72 public:
73 template <typename T> static std::string encode(const std::string& bin)
74 {
75 return encode(bin, T::data(), T::fill());
76 }
77 template <typename T> static std::string decode(const std::string& base)
78 {
79 return decode(base, T::data(), T::fill());
80 }
81 template <typename T> static std::string pad(const std::string& base)
82 {
83 return pad(base, T::fill());
84 }
85 template <typename T> static std::string trim(const std::string& base)
86 {
87 return trim(base, T::fill());
88 }
89
90 private:
91 static std::string encode(const std::string& bin, const std::array<char, 64>& alphabet,
92 const std::string& fill)
93 {
94 size_t size = bin.size();
95 std::string res;
96
97 // clear incomplete bytes
98 size_t fast_size = size - size % 3;
99 for (size_t i = 0; i < fast_size;)
100 {
101 uint32_t octet_a = static_cast<unsigned char>(bin[i++]);
102 uint32_t octet_b = static_cast<unsigned char>(bin[i++]);
103 uint32_t octet_c = static_cast<unsigned char>(bin[i++]);
104
105 uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c;
106
107 res += alphabet[(triple >> 3 * 6) & 0x3F];
108 res += alphabet[(triple >> 2 * 6) & 0x3F];
109 res += alphabet[(triple >> 1 * 6) & 0x3F];
110 res += alphabet[(triple >> 0 * 6) & 0x3F];
111 }
112
113 if (fast_size == size)
114 return res;
115
116 size_t mod = size % 3;
117
118 uint32_t octet_a = fast_size < size ? static_cast<unsigned char>(bin[fast_size++]) : 0;
119 uint32_t octet_b = fast_size < size ? static_cast<unsigned char>(bin[fast_size++]) : 0;
120 uint32_t octet_c = fast_size < size ? static_cast<unsigned char>(bin[fast_size++]) : 0;
121
122 uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c;
123
124 switch (mod)
125 {
126 case 1:
127 res += alphabet[(triple >> 3 * 6) & 0x3F];
128 res += alphabet[(triple >> 2 * 6) & 0x3F];
129 res += fill;
130 res += fill;
131 break;
132 case 2:
133 res += alphabet[(triple >> 3 * 6) & 0x3F];
134 res += alphabet[(triple >> 2 * 6) & 0x3F];
135 res += alphabet[(triple >> 1 * 6) & 0x3F];
136 res += fill;
137 break;
138 default: break;
139 }
140
141 return res;
142 }
143
144 static std::string decode(const std::string& base, const std::array<char, 64>& alphabet,
145 const std::string& fill)
146 {
147 size_t size = base.size();
148
149 size_t fill_cnt = 0;
150 while (size > fill.size())
151 {
152 if (base.substr(size - fill.size(), fill.size()) == fill)
153 {
154 fill_cnt++;
155 size -= fill.size();
156 if (fill_cnt > 2)
157 throw std::runtime_error("Invalid input: too much fill");
158 }
159 else
160 break;
161 }
162
163 if ((size + fill_cnt) % 4 != 0)
164 throw std::runtime_error("Invalid input: incorrect total size");
165
166 size_t out_size = size / 4 * 3;
167 std::string res;
168 res.reserve(out_size);
169
170 auto get_sextet = [&](size_t offset)
171 {
172 for (size_t i = 0; i < alphabet.size(); i++)
173 {
174 if (alphabet[i] == base[offset])
175 return static_cast<uint32_t>(i);
176 }
177 throw std::runtime_error("Invalid input: not within alphabet");
178 };
179
180 size_t fast_size = size - size % 4;
181 for (size_t i = 0; i < fast_size;)
182 {
183 uint32_t sextet_a = get_sextet(i++);
184 uint32_t sextet_b = get_sextet(i++);
185 uint32_t sextet_c = get_sextet(i++);
186 uint32_t sextet_d = get_sextet(i++);
187
188 uint32_t triple = (sextet_a << 3 * 6) + (sextet_b << 2 * 6) + (sextet_c << 1 * 6) +
189 (sextet_d << 0 * 6);
190
191 res += static_cast<char>((triple >> 2 * 8) & 0xFFU);
192 res += static_cast<char>((triple >> 1 * 8) & 0xFFU);
193 res += static_cast<char>((triple >> 0 * 8) & 0xFFU);
194 }
195
196 if (fill_cnt == 0)
197 return res;
198
199 uint32_t triple = (get_sextet(fast_size) << 3 * 6) + (get_sextet(fast_size + 1) << 2 * 6);
200
201 switch (fill_cnt)
202 {
203 case 1:
204 triple |= (get_sextet(fast_size + 2) << 1 * 6);
205 res += static_cast<char>((triple >> 2 * 8) & 0xFFU);
206 res += static_cast<char>((triple >> 1 * 8) & 0xFFU);
207 break;
208 case 2: res += static_cast<char>((triple >> 2 * 8) & 0xFFU); break;
209 default: break;
210 }
211
212 return res;
213 }
214
215 static std::string pad(const std::string& base, const std::string& fill)
216 {
217 std::string padding;
218 switch (base.size() % 4)
219 {
220 case 1: padding += fill; JWT_FALLTHROUGH;
221 case 2: padding += fill; JWT_FALLTHROUGH;
222 case 3: padding += fill; JWT_FALLTHROUGH;
223 default: break;
224 }
225
226 return base + padding;
227 }
228
229 static std::string trim(const std::string& base, const std::string& fill)
230 {
231 auto pos = base.find(fill);
232 return base.substr(0, pos);
233 }
234};
235} // namespace jwt
236
237#endif
#define JWT_FALLTHROUGH
Definition base.h:15
Alphabet generic methods for working with encoding/decoding the base64 family.
Definition base.h:71
static std::string encode(const std::string &bin)
Definition base.h:73
static std::string trim(const std::string &base)
Definition base.h:85
static std::string pad(const std::string &base)
Definition base.h:81
static std::string decode(const std::string &base)
Definition base.h:77
JSON Web Token.
Definition base.h:19
valid list of characted when working with Base64
Definition base.h:29
static const std::array< char, 64 > & data()
Definition base.h:30
static const std::string & fill()
Definition base.h:39
valid list of characted when working with Base64URL
Definition base.h:49
static const std::string & fill()
Definition base.h:59
static const std::array< char, 64 > & data()
Definition base.h:50