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)
311 size_t outLen = (length + 3) * 4 / 3;
315 size_t nCrLf = (outLen + lineSize - 1) / lineSize;
316 extra = nCrLf * 2ull;
318 size_t outCounter = 0;
320 const BYTE* q = data;
321 const size_t allocsize = outLen + extra + 1ull;
322 char* p = calloc(allocsize,
sizeof(
char));
341 const size_t blocks = length - (length % 3);
342 for (
size_t i = 0; i < blocks; i += 3, q += 3)
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;
350 WINPR_ASSERT(idx0 < alphabetCount);
351 WINPR_ASSERT(idx1 < alphabetCount);
352 WINPR_ASSERT(idx2 < alphabetCount);
353 WINPR_ASSERT(idx3 < alphabetCount);
355 *p++ = alphabet[idx0];
356 *p++ = alphabet[idx1];
357 *p++ = alphabet[idx2];
358 *p++ = alphabet[idx3];
361 if (crLf && (outCounter % lineSize == 0))
375 const unsigned c = ((unsigned)q[0] << 16);
376 const unsigned idx0 = (c & 0x00FC0000) >> 18;
377 const unsigned idx1 = (c & 0x0003F000) >> 12;
379 WINPR_ASSERT(idx0 < alphabetCount);
380 WINPR_ASSERT(idx1 < alphabetCount);
382 *p++ = alphabet[idx0];
383 *p++ = alphabet[idx1];
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;
398 WINPR_ASSERT(idx0 < alphabetCount);
399 WINPR_ASSERT(idx1 < alphabetCount);
400 WINPR_ASSERT(idx2 < alphabetCount);
402 *p++ = alphabet[idx0];
403 *p++ = alphabet[idx1];
404 *p++ = alphabet[idx2];
413 if (crLf && length % 3)
421 *plen = strnlen(ret, allocsize);
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,
430 return base64_encode_ex(alphabet, alphabetCount, data, length, pad, FALSE, 64, plen);
434static inline int base64_decode_char(
const signed char* WINPR_RESTRICT alphabet,
435 size_t alphabetCount,
char c)
438 const int ic = (int)c;
439 if ((ic <= 0) || ((size_t)ic >= alphabetCount))
442 return alphabet[(size_t)c];
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)
450 int n[4] = WINPR_C_ARRAY_INIT;
451 BYTE* data =
nullptr;
452 const size_t remainder = length % 4;
454 if ((pad && remainder > 0) || (remainder == 1))
457 if (!pad && remainder)
458 length += 4 - remainder;
460 BYTE* q = data = (BYTE*)malloc(length / 4 * 3 + 1);
465 const size_t nBlocks = (length / 4);
466 size_t outputLen = 0;
474 for (
size_t i = 0; i < nBlocks - 1; i++, q += 3)
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++);
481 if ((n[0] == -1) || (n[1] == -1) || (n[2] == -1) || (n[3] == -1))
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]);
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))
496 n[2] = remainder == 2 ? -1 : base64_decode_char(alphabet, alphabetCount, *s++);
497 n[3] = remainder >= 2 ? -1 : base64_decode_char(alphabet, alphabetCount, *s++);
499 q[0] = (BYTE)((n[0] << 2) + (n[1] >> 4));
507 q[1] = (BYTE)((n[1] & 15) << 4);
513 q[1] = (BYTE)(((n[1] & 15) << 4) + (n[2] >> 2));
514 q[2] = (BYTE)((n[2] & 3) << 6);
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]);
526 *data_len = outputLen;
527 data[outputLen] =
'\0';
535char* crypto_base64_encode_ex(
const BYTE* WINPR_RESTRICT data,
size_t length, BOOL withCrLf)
537 return crypto_base64_encode_ex_len(data, length, withCrLf,
nullptr);
540FREERDP_API
char* crypto_base64_encode_ex_len(
const void* WINPR_RESTRICT data,
size_t length,
541 BOOL withCrLf,
size_t* plen)
543 return base64_encode_ex(enc_base64, ARRAYSIZE(enc_base64), data, length, TRUE, withCrLf, 64,
547char* crypto_base64_encode(
const BYTE* WINPR_RESTRICT data,
size_t length)
549 return crypto_base64_encode_len(data, length,
nullptr);
552char* crypto_base64_encode_len(
const void* WINPR_RESTRICT data,
size_t length,
size_t* plen)
554 return base64_encode(enc_base64, ARRAYSIZE(enc_base64), data, length, TRUE, plen);
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)
561 base64_decode(dec_base64, ARRAYSIZE(dec_base64), enc_data, length, res_length, TRUE);
564char* crypto_base64url_encode(
const BYTE* WINPR_RESTRICT data,
size_t length)
566 return crypto_base64url_encode_len(data, length,
nullptr);
569char* crypto_base64url_encode_len(
const void* WINPR_RESTRICT data,
size_t length,
size_t* plen)
571 return base64_encode(enc_base64url, ARRAYSIZE(enc_base64url), data, length, FALSE, plen);
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)
578 base64_decode(dec_base64url, ARRAYSIZE(dec_base64url), enc_data, length, res_length, FALSE);