FreeRDP
Loading...
Searching...
No Matches
base64.c
1
20#include <freerdp/config.h>
21
22#include <winpr/crt.h>
23
24#include <freerdp/crypto/crypto.h>
25
26static const char enc_base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
27static const char enc_base64url[] =
28 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
29
30static const signed char dec_base64url[] = {
31 -1, /* 0 000 00 00000000 NUL &#00; Null character */
32 -1, /* 1 001 01 00000001 SOH &#01; Start of Heading */
33 -1, /* 2 002 02 00000010 STX &#02; Start of Text */
34 -1, /* 3 003 03 00000011 ETX &#03; End of Text */
35 -1, /* 4 004 04 00000100 EOT &#04; End of Transmission */
36 -1, /* 5 005 05 00000101 ENQ &#05; Enquiry */
37 -1, /* 6 006 06 00000110 ACK &#06; Acknowledge */
38 -1, /* 7 007 07 00000111 BEL &#07; Bell, Alert */
39 -1, /* 8 010 08 00001000 BS &#08; Backspace */
40 -1, /* 9 011 09 00001001 HT &#09; Horizontal Tab */
41 -1, /* 10 012 0A 00001010 LF &#10; Line Feed */
42 -1, /* 11 013 0B 00001011 VT &#11; Vertical Tabulation */
43 -1, /* 12 014 0C 00001100 FF &#12; Form Feed */
44 -1, /* 13 015 0D 00001101 CR &#13; Carriage Return */
45 -1, /* 14 016 0E 00001110 SO &#14; Shift Out */
46 -1, /* 15 017 0F 00001111 SI &#15; Shift In */
47 -1, /* 16 020 10 00010000 DLE &#16; Data Link Escape */
48 -1, /* 17 021 11 00010001 DC1 &#17; Device Control One (XON) */
49 -1, /* 18 022 12 00010010 DC2 &#18; Device Control Two */
50 -1, /* 19 023 13 00010011 DC3 &#19; Device Control Three (XOFF) */
51 -1, /* 20 024 14 00010100 DC4 &#20; Device Control Four */
52 -1, /* 21 025 15 00010101 NAK &#21; Negative Acknowledge */
53 -1, /* 22 026 16 00010110 SYN &#22; Synchronous Idle */
54 -1, /* 23 027 17 00010111 ETB &#23; End of Transmission Block */
55 -1, /* 24 030 18 00011000 CAN &#24; Cancel */
56 -1, /* 25 031 19 00011001 EM &#25; End of medium */
57 -1, /* 26 032 1A 00011010 SUB &#26; Substitute */
58 -1, /* 27 033 1B 00011011 ESC &#27; Escape */
59 -1, /* 28 034 1C 00011100 FS &#28; File Separator */
60 -1, /* 29 035 1D 00011101 GS &#29; Group Separator */
61 -1, /* 30 036 1E 00011110 RS &#30; Record Separator */
62 -1, /* 31 037 1F 00011111 US &#31; Unit Separator */
63 -1, /* 32 040 20 00100000 SP &#32; Space */
64 -1, /* 33 041 21 00100001 ! &#33; &excl; Exclamation mark */
65 -1, /* 34 042 22 00100010 " &#34; &quot; Double quotes (or speech marks) */
66 -1, /* 35 043 23 00100011 # &#35; &num; Number sign */
67 -1, /* 36 044 24 00100100 $ &#36; &dollar; Dollar */
68 -1, /* 37 045 25 00100101 % &#37; &percnt; Per cent sign */
69 -1, /* 38 046 26 00100110 & &#38; &amp; Ampersand */
70 -1, /* 39 047 27 00100111 ' &#39; &apos; Single quote */
71 -1, /* 40 050 28 00101000 ( &#40; &lparen; Open parenthesis (or open
72 * bracket)
73 */
74 -1, /* 41 051 29 00101001 ) &#41; &rparen; Close parenthesis (or close
75 * bracket)
76 */
77 -1, /* 42 052 2A 00101010 * &#42; &ast; Asterisk */
78 -1, /* 43 053 2B 00101011 + &#43; &plus; Plus */
79 -1, /* 44 054 2C 00101100 , &#44; &comma; Comma */
80 62, /* 45 055 2D 00101101 - &#45; Hyphen-minus */
81 -1, /* 46 056 2E 00101110 . &#46; &period; Period, dot or full stop */
82 -1, /* 47 057 2F 00101111 / &#47; &sol; Slash or divide */
83 52, /* 48 060 30 00110000 0 &#48; Zero */
84 53, /* 49 061 31 00110001 1 &#49; One */
85 54, /* 50 062 32 00110010 2 &#50; Two */
86 55, /* 51 063 33 00110011 3 &#51; Three */
87 56, /* 52 064 34 00110100 4 &#52; Four */
88 57, /* 53 065 35 00110101 5 &#53; Five */
89 58, /* 54 066 36 00110110 6 &#54; Six */
90 59, /* 55 067 37 00110111 7 &#55; Seven */
91 60, /* 56 070 38 00111000 8 &#56; Eight */
92 61, /* 57 071 39 00111001 9 &#57; Nine */
93 -1, /* 58 072 3A 00111010 : &#58; &colon; Colon */
94 -1, /* 59 073 3B 00111011 ; &#59; &semi; Semicolon */
95 -1, /* 60 074 3C 00111100 < &#60; &lt; Less than (or open angled bracket)
96 */
97 -1, /* 61 075 3D 00111101 = &#61; &equals; Equals */
98 -1, /* 62 076 3E 00111110 > &#62; &gt; Greater than (or close angled
99 * bracket)
100 */
101 -1, /* 63 077 3F 00111111 ? &#63; &quest; Question mark */
102 -1, /* 64 100 40 01000000 @ &#64; &commat; At sign */
103 0, /* 65 101 41 01000001 A &#65; Uppercase A */
104 1, /* 66 102 42 01000010 B &#66; Uppercase B */
105 2, /* 67 103 43 01000011 C &#67; Uppercase C */
106 3, /* 68 104 44 01000100 D &#68; Uppercase D */
107 4, /* 69 105 45 01000101 E &#69; Uppercase E */
108 5, /* 70 106 46 01000110 F &#70; Uppercase F */
109 6, /* 71 107 47 01000111 G &#71; Uppercase G */
110 7, /* 72 110 48 01001000 H &#72; Uppercase H */
111 8, /* 73 111 49 01001001 I &#73; Uppercase I */
112 9, /* 74 112 4A 01001010 J &#74; Uppercase J */
113 10, /* 75 113 4B 01001011 K &#75; Uppercase K */
114 11, /* 76 114 4C 01001100 L &#76; Uppercase L */
115 12, /* 77 115 4D 01001101 M &#77; Uppercase M */
116 13, /* 78 116 4E 01001110 N &#78; Uppercase N */
117 14, /* 79 117 4F 01001111 O &#79; Uppercase O */
118 15, /* 80 120 50 01010000 P &#80; Uppercase P */
119 16, /* 81 121 51 01010001 Q &#81; Uppercase Q */
120 17, /* 82 122 52 01010010 R &#82; Uppercase R */
121 18, /* 83 123 53 01010011 S &#83; Uppercase S */
122 19, /* 84 124 54 01010100 T &#84; Uppercase T */
123 20, /* 85 125 55 01010101 U &#85; Uppercase U */
124 21, /* 86 126 56 01010110 V &#86; Uppercase V */
125 22, /* 87 127 57 01010111 W &#87; Uppercase W */
126 23, /* 88 130 58 01011000 X &#88; Uppercase X */
127 24, /* 89 131 59 01011001 Y &#89; Uppercase Y */
128 25, /* 90 132 5A 01011010 Z &#90; Uppercase Z */
129 -1, /* 91 133 5B 01011011 [ &#91; &lsqb; Opening bracket */
130 -1, /* 92 134 5C 01011100 \ &#92; &bsol; Backslash */
131 -1, /* 93 135 5D 01011101 ] &#93; &rsqb; Closing bracket */
132 -1, /* 94 136 5E 01011110 ^ &#94; &Hat; Caret - circumflex */
133 63, /* 95 137 5F 01011111 _ &#95; &lowbar; Underscore */
134 -1, /* 96 140 60 01100000 ` &#96; &grave; Grave accent */
135 26, /* 97 141 61 01100001 a &#97; Lowercase a */
136 27, /* 98 142 62 01100010 b &#98; Lowercase b */
137 28, /* 99 143 63 01100011 c &#99; Lowercase c */
138 29, /* 100 144 64 01100100 d &#100; Lowercase d */
139 30, /* 101 145 65 01100101 e &#101; Lowercase e */
140 31, /* 102 146 66 01100110 f &#102; Lowercase f */
141 32, /* 103 147 67 01100111 g &#103; Lowercase g */
142 33, /* 104 150 68 01101000 h &#104; Lowercase h */
143 34, /* 105 151 69 01101001 i &#105; Lowercase i */
144 35, /* 106 152 6A 01101010 j &#106; Lowercase j */
145 36, /* 107 153 6B 01101011 k &#107; Lowercase k */
146 37, /* 108 154 6C 01101100 l &#108; Lowercase l */
147 38, /* 109 155 6D 01101101 m &#109; Lowercase m */
148 39, /* 110 156 6E 01101110 n &#110; Lowercase n */
149 40, /* 111 157 6F 01101111 o &#111; Lowercase o */
150 41, /* 112 160 70 01110000 p &#112; Lowercase p */
151 42, /* 113 161 71 01110001 q &#113; Lowercase q */
152 43, /* 114 162 72 01110010 r &#114; Lowercase r */
153 44, /* 115 163 73 01110011 s &#115; Lowercase s */
154 45, /* 116 164 74 01110100 t &#116; Lowercase t */
155 46, /* 117 165 75 01110101 u &#117; Lowercase u */
156 47, /* 118 166 76 01110110 v &#118; Lowercase v */
157 48, /* 119 167 77 01110111 w &#119; Lowercase w */
158 49, /* 120 170 78 01111000 x &#120; Lowercase x */
159 50, /* 121 171 79 01111001 y &#121; Lowercase y */
160 51, /* 122 172 7A 01111010 z &#122; Lowercase z */
161 -1, /* 123 173 7B 01111011 { &#123; &lcub; Opening brace */
162 -1, /* 124 174 7C 01111100 | &#124; &verbar; Vertical bar */
163 -1, /* 125 175 7D 01111101 } &#125; &rcub; Closing brace */
164 -1, /* 126 176 7E 01111110 ~ &#126; &tilde; Equivalency sign - tilde */
165 -1, /* 127 177 7F 01111111 DEL &#127; Delete */
166};
167static const signed char dec_base64[] = {
168 -1, /* 0 000 00 00000000 NUL &#00; Null character */
169 -1, /* 1 001 01 00000001 SOH &#01; Start of Heading */
170 -1, /* 2 002 02 00000010 STX &#02; Start of Text */
171 -1, /* 3 003 03 00000011 ETX &#03; End of Text */
172 -1, /* 4 004 04 00000100 EOT &#04; End of Transmission */
173 -1, /* 5 005 05 00000101 ENQ &#05; Enquiry */
174 -1, /* 6 006 06 00000110 ACK &#06; Acknowledge */
175 -1, /* 7 007 07 00000111 BEL &#07; Bell, Alert */
176 -1, /* 8 010 08 00001000 BS &#08; Backspace */
177 -1, /* 9 011 09 00001001 HT &#09; Horizontal Tab */
178 -1, /* 10 012 0A 00001010 LF &#10; Line Feed */
179 -1, /* 11 013 0B 00001011 VT &#11; Vertical Tabulation */
180 -1, /* 12 014 0C 00001100 FF &#12; Form Feed */
181 -1, /* 13 015 0D 00001101 CR &#13; Carriage Return */
182 -1, /* 14 016 0E 00001110 SO &#14; Shift Out */
183 -1, /* 15 017 0F 00001111 SI &#15; Shift In */
184 -1, /* 16 020 10 00010000 DLE &#16; Data Link Escape */
185 -1, /* 17 021 11 00010001 DC1 &#17; Device Control One (XON) */
186 -1, /* 18 022 12 00010010 DC2 &#18; Device Control Two */
187 -1, /* 19 023 13 00010011 DC3 &#19; Device Control Three (XOFF) */
188 -1, /* 20 024 14 00010100 DC4 &#20; Device Control Four */
189 -1, /* 21 025 15 00010101 NAK &#21; Negative Acknowledge */
190 -1, /* 22 026 16 00010110 SYN &#22; Synchronous Idle */
191 -1, /* 23 027 17 00010111 ETB &#23; End of Transmission Block */
192 -1, /* 24 030 18 00011000 CAN &#24; Cancel */
193 -1, /* 25 031 19 00011001 EM &#25; End of medium */
194 -1, /* 26 032 1A 00011010 SUB &#26; Substitute */
195 -1, /* 27 033 1B 00011011 ESC &#27; Escape */
196 -1, /* 28 034 1C 00011100 FS &#28; File Separator */
197 -1, /* 29 035 1D 00011101 GS &#29; Group Separator */
198 -1, /* 30 036 1E 00011110 RS &#30; Record Separator */
199 -1, /* 31 037 1F 00011111 US &#31; Unit Separator */
200 -1, /* 32 040 20 00100000 SP &#32; Space */
201 -1, /* 33 041 21 00100001 ! &#33; &excl; Exclamation mark */
202 -1, /* 34 042 22 00100010 " &#34; &quot; Double quotes (or speech marks) */
203 -1, /* 35 043 23 00100011 # &#35; &num; Number sign */
204 -1, /* 36 044 24 00100100 $ &#36; &dollar; Dollar */
205 -1, /* 37 045 25 00100101 % &#37; &percnt; Per cent sign */
206 -1, /* 38 046 26 00100110 & &#38; &amp; Ampersand */
207 -1, /* 39 047 27 00100111 ' &#39; &apos; Single quote */
208 -1, /* 40 050 28 00101000 ( &#40; &lparen; Open parenthesis (or open
209 * bracket)
210 */
211 -1, /* 41 051 29 00101001 ) &#41; &rparen; Close parenthesis (or close
212 * bracket)
213 */
214 -1, /* 42 052 2A 00101010 * &#42; &ast; Asterisk */
215 62, /* 43 053 2B 00101011 + &#43; &plus; Plus */
216 -1, /* 44 054 2C 00101100 , &#44; &comma; Comma */
217 -1, /* 45 055 2D 00101101 - &#45; Hyphen-minus */
218 -1, /* 46 056 2E 00101110 . &#46; &period; Period, dot or full stop */
219 63, /* 47 057 2F 00101111 / &#47; &sol; Slash or divide */
220 52, /* 48 060 30 00110000 0 &#48; Zero */
221 53, /* 49 061 31 00110001 1 &#49; One */
222 54, /* 50 062 32 00110010 2 &#50; Two */
223 55, /* 51 063 33 00110011 3 &#51; Three */
224 56, /* 52 064 34 00110100 4 &#52; Four */
225 57, /* 53 065 35 00110101 5 &#53; Five */
226 58, /* 54 066 36 00110110 6 &#54; Six */
227 59, /* 55 067 37 00110111 7 &#55; Seven */
228 60, /* 56 070 38 00111000 8 &#56; Eight */
229 61, /* 57 071 39 00111001 9 &#57; Nine */
230 -1, /* 58 072 3A 00111010 : &#58; &colon; Colon */
231 -1, /* 59 073 3B 00111011 ; &#59; &semi; Semicolon */
232 -1, /* 60 074 3C 00111100 < &#60; &lt; Less than (or open angled bracket)
233 */
234 -1, /* 61 075 3D 00111101 = &#61; &equals; Equals */
235 -1, /* 62 076 3E 00111110 > &#62; &gt; Greater than (or close angled
236 * bracket)
237 */
238 -1, /* 63 077 3F 00111111 ? &#63; &quest; Question mark */
239 -1, /* 64 100 40 01000000 @ &#64; &commat; At sign */
240 0, /* 65 101 41 01000001 A &#65; Uppercase A */
241 1, /* 66 102 42 01000010 B &#66; Uppercase B */
242 2, /* 67 103 43 01000011 C &#67; Uppercase C */
243 3, /* 68 104 44 01000100 D &#68; Uppercase D */
244 4, /* 69 105 45 01000101 E &#69; Uppercase E */
245 5, /* 70 106 46 01000110 F &#70; Uppercase F */
246 6, /* 71 107 47 01000111 G &#71; Uppercase G */
247 7, /* 72 110 48 01001000 H &#72; Uppercase H */
248 8, /* 73 111 49 01001001 I &#73; Uppercase I */
249 9, /* 74 112 4A 01001010 J &#74; Uppercase J */
250 10, /* 75 113 4B 01001011 K &#75; Uppercase K */
251 11, /* 76 114 4C 01001100 L &#76; Uppercase L */
252 12, /* 77 115 4D 01001101 M &#77; Uppercase M */
253 13, /* 78 116 4E 01001110 N &#78; Uppercase N */
254 14, /* 79 117 4F 01001111 O &#79; Uppercase O */
255 15, /* 80 120 50 01010000 P &#80; Uppercase P */
256 16, /* 81 121 51 01010001 Q &#81; Uppercase Q */
257 17, /* 82 122 52 01010010 R &#82; Uppercase R */
258 18, /* 83 123 53 01010011 S &#83; Uppercase S */
259 19, /* 84 124 54 01010100 T &#84; Uppercase T */
260 20, /* 85 125 55 01010101 U &#85; Uppercase U */
261 21, /* 86 126 56 01010110 V &#86; Uppercase V */
262 22, /* 87 127 57 01010111 W &#87; Uppercase W */
263 23, /* 88 130 58 01011000 X &#88; Uppercase X */
264 24, /* 89 131 59 01011001 Y &#89; Uppercase Y */
265 25, /* 90 132 5A 01011010 Z &#90; Uppercase Z */
266 -1, /* 91 133 5B 01011011 [ &#91; &lsqb; Opening bracket */
267 -1, /* 92 134 5C 01011100 \ &#92; &bsol; Backslash */
268 -1, /* 93 135 5D 01011101 ] &#93; &rsqb; Closing bracket */
269 -1, /* 94 136 5E 01011110 ^ &#94; &Hat; Caret - circumflex */
270 -1, /* 95 137 5F 01011111 _ &#95; &lowbar; Underscore */
271 -1, /* 96 140 60 01100000 ` &#96; &grave; Grave accent */
272 26, /* 97 141 61 01100001 a &#97; Lowercase a */
273 27, /* 98 142 62 01100010 b &#98; Lowercase b */
274 28, /* 99 143 63 01100011 c &#99; Lowercase c */
275 29, /* 100 144 64 01100100 d &#100; Lowercase d */
276 30, /* 101 145 65 01100101 e &#101; Lowercase e */
277 31, /* 102 146 66 01100110 f &#102; Lowercase f */
278 32, /* 103 147 67 01100111 g &#103; Lowercase g */
279 33, /* 104 150 68 01101000 h &#104; Lowercase h */
280 34, /* 105 151 69 01101001 i &#105; Lowercase i */
281 35, /* 106 152 6A 01101010 j &#106; Lowercase j */
282 36, /* 107 153 6B 01101011 k &#107; Lowercase k */
283 37, /* 108 154 6C 01101100 l &#108; Lowercase l */
284 38, /* 109 155 6D 01101101 m &#109; Lowercase m */
285 39, /* 110 156 6E 01101110 n &#110; Lowercase n */
286 40, /* 111 157 6F 01101111 o &#111; Lowercase o */
287 41, /* 112 160 70 01110000 p &#112; Lowercase p */
288 42, /* 113 161 71 01110001 q &#113; Lowercase q */
289 43, /* 114 162 72 01110010 r &#114; Lowercase r */
290 44, /* 115 163 73 01110011 s &#115; Lowercase s */
291 45, /* 116 164 74 01110100 t &#116; Lowercase t */
292 46, /* 117 165 75 01110101 u &#117; Lowercase u */
293 47, /* 118 166 76 01110110 v &#118; Lowercase v */
294 48, /* 119 167 77 01110111 w &#119; Lowercase w */
295 49, /* 120 170 78 01111000 x &#120; Lowercase x */
296 50, /* 121 171 79 01111001 y &#121; Lowercase y */
297 51, /* 122 172 7A 01111010 z &#122; Lowercase z */
298 -1, /* 123 173 7B 01111011 { &#123; &lcub; Opening brace */
299 -1, /* 124 174 7C 01111100 | &#124; &verbar; Vertical bar */
300 -1, /* 125 175 7D 01111101 } &#125; &rcub; Closing brace */
301 -1, /* 126 176 7E 01111110 ~ &#126; &tilde; Equivalency sign - tilde */
302 -1, /* 127 177 7F 01111111 DEL &#127; Delete */
303};
304
305WINPR_ATTR_MALLOC(free, 1)
306static inline char* base64_encode_ex(const char* WINPR_RESTRICT alphabet,
307 WINPR_ATTR_UNUSED size_t alphabetCount,
308 const BYTE* WINPR_RESTRICT data, size_t length, BOOL pad,
309 BOOL crLf, size_t lineSize, size_t* plen)
310{
311 size_t outLen = (length + 3) * 4 / 3;
312 size_t extra = 0;
313 if (crLf)
314 {
315 size_t nCrLf = (outLen + lineSize - 1) / lineSize;
316 extra = nCrLf * 2ull;
317 }
318 size_t outCounter = 0;
319
320 const BYTE* q = data;
321 const size_t allocsize = outLen + extra + 1ull;
322 char* p = calloc(allocsize, sizeof(char));
323 if (!p)
324 return nullptr;
325
326 char* ret = p;
327
328 /* b1, b2, b3 are input bytes
329 *
330 * 0 1 2
331 * 012345678901234567890123
332 * | b1 | b2 | b3 |
333 *
334 * [ c1 ] [ c3 ]
335 * [ c2 ] [ c4 ]
336 *
337 * c1, c2, c3, c4 are output chars in base64
338 */
339
340 /* first treat complete blocks */
341 const size_t blocks = length - (length % 3);
342 for (size_t i = 0; i < blocks; i += 3, q += 3)
343 {
344 const unsigned c = ((unsigned)q[0] << 16) + ((unsigned)q[1] << 8) + q[2];
345 const unsigned idx0 = (c & 0x00FC0000) >> 18;
346 const unsigned idx1 = (c & 0x0003F000) >> 12;
347 const unsigned idx2 = (c & 0x00000FC0) >> 6;
348 const unsigned idx3 = c & 0x0000003F;
349
350 WINPR_ASSERT(idx0 < alphabetCount);
351 WINPR_ASSERT(idx1 < alphabetCount);
352 WINPR_ASSERT(idx2 < alphabetCount);
353 WINPR_ASSERT(idx3 < alphabetCount);
354
355 *p++ = alphabet[idx0];
356 *p++ = alphabet[idx1];
357 *p++ = alphabet[idx2];
358 *p++ = alphabet[idx3];
359
360 outCounter += 4;
361 if (crLf && (outCounter % lineSize == 0))
362 {
363 *p++ = '\r';
364 *p++ = '\n';
365 }
366 }
367
368 /* then remainder */
369 switch (length % 3)
370 {
371 case 0:
372 break;
373 case 1:
374 {
375 const unsigned c = ((unsigned)q[0] << 16);
376 const unsigned idx0 = (c & 0x00FC0000) >> 18;
377 const unsigned idx1 = (c & 0x0003F000) >> 12;
378
379 WINPR_ASSERT(idx0 < alphabetCount);
380 WINPR_ASSERT(idx1 < alphabetCount);
381
382 *p++ = alphabet[idx0];
383 *p++ = alphabet[idx1];
384 if (pad)
385 {
386 *p++ = '=';
387 *p++ = '=';
388 }
389 }
390 break;
391 case 2:
392 {
393 const unsigned c = ((unsigned)q[0] << 16) + ((unsigned)q[1] << 8);
394 const unsigned idx0 = (c & 0x00FC0000) >> 18;
395 const unsigned idx1 = (c & 0x0003F000) >> 12;
396 const unsigned idx2 = (c & 0x00000FC0) >> 6;
397
398 WINPR_ASSERT(idx0 < alphabetCount);
399 WINPR_ASSERT(idx1 < alphabetCount);
400 WINPR_ASSERT(idx2 < alphabetCount);
401
402 *p++ = alphabet[idx0];
403 *p++ = alphabet[idx1];
404 *p++ = alphabet[idx2];
405 if (pad)
406 *p++ = '=';
407 }
408 break;
409 default:
410 break;
411 }
412
413 if (crLf && length % 3)
414 {
415 *p++ = '\r';
416 *p++ = '\n';
417 }
418 *p = 0;
419
420 if (plen)
421 *plen = strnlen(ret, allocsize);
422 return ret;
423}
424
425WINPR_ATTR_MALLOC(free, 1)
426static inline char* base64_encode(const char* WINPR_RESTRICT alphabet, size_t alphabetCount,
427 const BYTE* WINPR_RESTRICT data, size_t length, BOOL pad,
428 size_t* plen)
429{
430 return base64_encode_ex(alphabet, alphabetCount, data, length, pad, FALSE, 64, plen);
431}
432
433WINPR_ATTR_NODISCARD
434static inline int base64_decode_char(const signed char* WINPR_RESTRICT alphabet,
435 size_t alphabetCount, char c)
436{
437 /* ensure char is signed for this check */
438 const int ic = (int)c;
439 if ((ic <= 0) || ((size_t)ic >= alphabetCount))
440 return -1;
441
442 return alphabet[(size_t)c];
443}
444
445WINPR_ATTR_MALLOC(free, 1)
446static inline void* base64_decode(const signed char* WINPR_RESTRICT alphabet, size_t alphabetCount,
447 const char* WINPR_RESTRICT s, size_t length,
448 size_t* WINPR_RESTRICT data_len, BOOL pad)
449{
450 int n[4] = WINPR_C_ARRAY_INIT;
451 BYTE* data = nullptr;
452 const size_t remainder = length % 4;
453
454 if ((pad && remainder > 0) || (remainder == 1))
455 return nullptr;
456
457 if (!pad && remainder)
458 length += 4 - remainder;
459
460 BYTE* q = data = (BYTE*)malloc(length / 4 * 3 + 1);
461 if (!q)
462 return nullptr;
463
464 /* first treat complete blocks */
465 const size_t nBlocks = (length / 4);
466 size_t outputLen = 0;
467
468 if (nBlocks < 1)
469 {
470 free(data);
471 return nullptr;
472 }
473
474 for (size_t i = 0; i < nBlocks - 1; i++, q += 3)
475 {
476 n[0] = base64_decode_char(alphabet, alphabetCount, *s++);
477 n[1] = base64_decode_char(alphabet, alphabetCount, *s++);
478 n[2] = base64_decode_char(alphabet, alphabetCount, *s++);
479 n[3] = base64_decode_char(alphabet, alphabetCount, *s++);
480
481 if ((n[0] == -1) || (n[1] == -1) || (n[2] == -1) || (n[3] == -1))
482 goto out_free;
483
484 q[0] = (BYTE)((n[0] << 2) + (n[1] >> 4));
485 q[1] = (BYTE)(((n[1] & 15) << 4) + (n[2] >> 2));
486 q[2] = (BYTE)(((n[2] & 3) << 6) + n[3]);
487 outputLen += 3;
488 }
489
490 /* treat last block */
491 n[0] = base64_decode_char(alphabet, alphabetCount, *s++);
492 n[1] = base64_decode_char(alphabet, alphabetCount, *s++);
493 if ((n[0] == -1) || (n[1] == -1))
494 goto out_free;
495
496 n[2] = remainder == 2 ? -1 : base64_decode_char(alphabet, alphabetCount, *s++);
497 n[3] = remainder >= 2 ? -1 : base64_decode_char(alphabet, alphabetCount, *s++);
498
499 q[0] = (BYTE)((n[0] << 2) + (n[1] >> 4));
500 if (n[2] == -1)
501 {
502 /* XX== */
503 outputLen += 1;
504 if (n[3] != -1)
505 goto out_free;
506
507 q[1] = (BYTE)((n[1] & 15) << 4);
508 }
509 else if (n[3] == -1)
510 {
511 /* yyy= */
512 outputLen += 2;
513 q[1] = (BYTE)(((n[1] & 15) << 4) + (n[2] >> 2));
514 q[2] = (BYTE)((n[2] & 3) << 6);
515 }
516 else
517 {
518 /* XXXX */
519 outputLen += 3;
520 q[0] = (BYTE)((n[0] << 2) + (n[1] >> 4));
521 q[1] = (BYTE)(((n[1] & 15) << 4) + (n[2] >> 2));
522 q[2] = (BYTE)(((n[2] & 3) << 6) + n[3]);
523 }
524
525 if (data_len)
526 *data_len = outputLen;
527 data[outputLen] = '\0';
528
529 return data;
530out_free:
531 free(data);
532 return nullptr;
533}
534
535char* crypto_base64_encode_ex(const BYTE* WINPR_RESTRICT data, size_t length, BOOL withCrLf)
536{
537 return crypto_base64_encode_ex_len(data, length, withCrLf, nullptr);
538}
539
540FREERDP_API char* crypto_base64_encode_ex_len(const void* WINPR_RESTRICT data, size_t length,
541 BOOL withCrLf, size_t* plen)
542{
543 return base64_encode_ex(enc_base64, ARRAYSIZE(enc_base64), data, length, TRUE, withCrLf, 64,
544 plen);
545}
546
547char* crypto_base64_encode(const BYTE* WINPR_RESTRICT data, size_t length)
548{
549 return crypto_base64_encode_len(data, length, nullptr);
550}
551
552char* crypto_base64_encode_len(const void* WINPR_RESTRICT data, size_t length, size_t* plen)
553{
554 return base64_encode(enc_base64, ARRAYSIZE(enc_base64), data, length, TRUE, plen);
555}
556
557void crypto_base64_decode(const char* WINPR_RESTRICT enc_data, size_t length,
558 BYTE** WINPR_RESTRICT dec_data, size_t* WINPR_RESTRICT res_length)
559{
560 *dec_data =
561 base64_decode(dec_base64, ARRAYSIZE(dec_base64), enc_data, length, res_length, TRUE);
562}
563
564char* crypto_base64url_encode(const BYTE* WINPR_RESTRICT data, size_t length)
565{
566 return crypto_base64url_encode_len(data, length, nullptr);
567}
568
569char* crypto_base64url_encode_len(const void* WINPR_RESTRICT data, size_t length, size_t* plen)
570{
571 return base64_encode(enc_base64url, ARRAYSIZE(enc_base64url), data, length, FALSE, plen);
572}
573
574void crypto_base64url_decode(const char* WINPR_RESTRICT enc_data, size_t length,
575 BYTE** WINPR_RESTRICT dec_data, size_t* WINPR_RESTRICT res_length)
576{
577 *dec_data =
578 base64_decode(dec_base64url, ARRAYSIZE(dec_base64url), enc_data, length, res_length, FALSE);
579}