20#include <freerdp/config.h>
24#include <freerdp/crypto/crypto.h>
26static const char enc_base64[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
27static const char enc_base64url[] =
28 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
30static const signed char dec_base64url[] = {
167static const signed char dec_base64[] = {
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)
312 if (length > SIZE_MAX / 4 - 3)
315 size_t outLen = (length + 3) * 4 / 3;
319 size_t nCrLf = (outLen + lineSize - 1) / lineSize;
320 extra = nCrLf * 2ull;
322 size_t outCounter = 0;
324 const BYTE* q = data;
325 const size_t allocsize = outLen + extra + 1ull;
326 char* p = calloc(allocsize,
sizeof(
char));
345 const size_t blocks = length - (length % 3);
346 for (
size_t i = 0; i < blocks; i += 3, q += 3)
348 const unsigned c = ((unsigned)q[0] << 16) + ((unsigned)q[1] << 8) + q[2];
349 const unsigned idx0 = (c & 0x00FC0000) >> 18;
350 const unsigned idx1 = (c & 0x0003F000) >> 12;
351 const unsigned idx2 = (c & 0x00000FC0) >> 6;
352 const unsigned idx3 = c & 0x0000003F;
354 WINPR_ASSERT(idx0 < alphabetCount);
355 WINPR_ASSERT(idx1 < alphabetCount);
356 WINPR_ASSERT(idx2 < alphabetCount);
357 WINPR_ASSERT(idx3 < alphabetCount);
359 *p++ = alphabet[idx0];
360 *p++ = alphabet[idx1];
361 *p++ = alphabet[idx2];
362 *p++ = alphabet[idx3];
365 if (crLf && (outCounter % lineSize == 0))
379 const unsigned c = ((unsigned)q[0] << 16);
380 const unsigned idx0 = (c & 0x00FC0000) >> 18;
381 const unsigned idx1 = (c & 0x0003F000) >> 12;
383 WINPR_ASSERT(idx0 < alphabetCount);
384 WINPR_ASSERT(idx1 < alphabetCount);
386 *p++ = alphabet[idx0];
387 *p++ = alphabet[idx1];
397 const unsigned c = ((unsigned)q[0] << 16) + ((unsigned)q[1] << 8);
398 const unsigned idx0 = (c & 0x00FC0000) >> 18;
399 const unsigned idx1 = (c & 0x0003F000) >> 12;
400 const unsigned idx2 = (c & 0x00000FC0) >> 6;
402 WINPR_ASSERT(idx0 < alphabetCount);
403 WINPR_ASSERT(idx1 < alphabetCount);
404 WINPR_ASSERT(idx2 < alphabetCount);
406 *p++ = alphabet[idx0];
407 *p++ = alphabet[idx1];
408 *p++ = alphabet[idx2];
417 if (crLf && length % 3)
425 *plen = strnlen(ret, allocsize);
429WINPR_ATTR_MALLOC(free, 1)
430static inline
char* base64_encode(const
char* WINPR_RESTRICT alphabet,
size_t alphabetCount,
431 const BYTE* WINPR_RESTRICT data,
size_t length, BOOL pad,
434 return base64_encode_ex(alphabet, alphabetCount, data, length, pad, FALSE, 64, plen);
438static inline int base64_decode_char(
const signed char* WINPR_RESTRICT alphabet,
439 size_t alphabetCount,
char c)
442 const int ic = (int)c;
443 if ((ic <= 0) || ((size_t)ic >= alphabetCount))
446 return alphabet[(size_t)c];
449WINPR_ATTR_MALLOC(free, 1)
450static inline
void* base64_decode(const
signed char* WINPR_RESTRICT alphabet,
size_t alphabetCount,
451 const
char* WINPR_RESTRICT s,
size_t length,
452 size_t* WINPR_RESTRICT data_len, BOOL pad)
454 int n[4] = WINPR_C_ARRAY_INIT;
455 BYTE* data =
nullptr;
456 const size_t remainder = length % 4;
458 if ((pad && remainder > 0) || (remainder == 1))
461 if (!pad && remainder)
462 length += 4 - remainder;
464 BYTE* q = data = (BYTE*)malloc(length / 4 * 3 + 1);
469 const size_t nBlocks = (length / 4);
470 size_t outputLen = 0;
478 for (
size_t i = 0; i < nBlocks - 1; i++, q += 3)
480 n[0] = base64_decode_char(alphabet, alphabetCount, *s++);
481 n[1] = base64_decode_char(alphabet, alphabetCount, *s++);
482 n[2] = base64_decode_char(alphabet, alphabetCount, *s++);
483 n[3] = base64_decode_char(alphabet, alphabetCount, *s++);
485 if ((n[0] == -1) || (n[1] == -1) || (n[2] == -1) || (n[3] == -1))
488 q[0] = (BYTE)((n[0] << 2) + (n[1] >> 4));
489 q[1] = (BYTE)(((n[1] & 15) << 4) + (n[2] >> 2));
490 q[2] = (BYTE)(((n[2] & 3) << 6) + n[3]);
495 n[0] = base64_decode_char(alphabet, alphabetCount, *s++);
496 n[1] = base64_decode_char(alphabet, alphabetCount, *s++);
497 if ((n[0] == -1) || (n[1] == -1))
500 n[2] = remainder == 2 ? -1 : base64_decode_char(alphabet, alphabetCount, *s++);
501 n[3] = remainder >= 2 ? -1 : base64_decode_char(alphabet, alphabetCount, *s++);
503 q[0] = (BYTE)((n[0] << 2) + (n[1] >> 4));
511 q[1] = (BYTE)((n[1] & 15) << 4);
517 q[1] = (BYTE)(((n[1] & 15) << 4) + (n[2] >> 2));
518 q[2] = (BYTE)((n[2] & 3) << 6);
524 q[0] = (BYTE)((n[0] << 2) + (n[1] >> 4));
525 q[1] = (BYTE)(((n[1] & 15) << 4) + (n[2] >> 2));
526 q[2] = (BYTE)(((n[2] & 3) << 6) + n[3]);
530 *data_len = outputLen;
531 data[outputLen] =
'\0';
539char* crypto_base64_encode_ex(
const BYTE* WINPR_RESTRICT data,
size_t length, BOOL withCrLf)
541 return crypto_base64_encode_ex_len(data, length, withCrLf,
nullptr);
544FREERDP_API
char* crypto_base64_encode_ex_len(
const void* WINPR_RESTRICT data,
size_t length,
545 BOOL withCrLf,
size_t* plen)
547 return base64_encode_ex(enc_base64, ARRAYSIZE(enc_base64), data, length, TRUE, withCrLf, 64,
551char* crypto_base64_encode(
const BYTE* WINPR_RESTRICT data,
size_t length)
553 return crypto_base64_encode_len(data, length,
nullptr);
556char* crypto_base64_encode_len(
const void* WINPR_RESTRICT data,
size_t length,
size_t* plen)
558 return base64_encode(enc_base64, ARRAYSIZE(enc_base64), data, length, TRUE, plen);
561void crypto_base64_decode(
const char* WINPR_RESTRICT enc_data,
size_t length,
562 BYTE** WINPR_RESTRICT dec_data,
size_t* WINPR_RESTRICT res_length)
565 base64_decode(dec_base64, ARRAYSIZE(dec_base64), enc_data, length, res_length, TRUE);
568char* crypto_base64url_encode(
const BYTE* WINPR_RESTRICT data,
size_t length)
570 return crypto_base64url_encode_len(data, length,
nullptr);
573char* crypto_base64url_encode_len(
const void* WINPR_RESTRICT data,
size_t length,
size_t* plen)
575 return base64_encode(enc_base64url, ARRAYSIZE(enc_base64url), data, length, FALSE, plen);
578void crypto_base64url_decode(
const char* WINPR_RESTRICT enc_data,
size_t length,
579 BYTE** WINPR_RESTRICT dec_data,
size_t* WINPR_RESTRICT res_length)
582 base64_decode(dec_base64url, ARRAYSIZE(dec_base64url), enc_data, length, res_length, FALSE);