From 361da15eed25e2c6800057aa29ac328af1d399a8 Mon Sep 17 00:00:00 2001 From: David Fort Date: Wed, 16 Aug 2023 11:06:17 +0200 Subject: [PATCH] [crypto] extend base64 to output crLf when encoding Some windows APIs do put \r\n every 64 characters of the output of a base64 encoded blob. The extended version of crypto_base64_encode allows to do the same. --- include/freerdp/crypto/crypto.h | 2 ++ libfreerdp/crypto/base64.c | 35 +++++++++++++++++++++++++++-- libfreerdp/crypto/test/TestBase64.c | 18 ++++++++++++++- 3 files changed, 52 insertions(+), 3 deletions(-) diff --git a/include/freerdp/crypto/crypto.h b/include/freerdp/crypto/crypto.h index b10ed79d0..6137769b9 100644 --- a/include/freerdp/crypto/crypto.h +++ b/include/freerdp/crypto/crypto.h @@ -39,6 +39,8 @@ extern "C" typedef struct rdp_CertInfo rdpCertInfo; FREERDP_API char* crypto_base64_encode(const BYTE* data, size_t length); + FREERDP_API char* crypto_base64_encode_ex(const BYTE* data, size_t length, BOOL withCrLf); + FREERDP_API void crypto_base64_decode(const char* enc_data, size_t length, BYTE** dec_data, size_t* res_length); diff --git a/libfreerdp/crypto/base64.c b/libfreerdp/crypto/base64.c index ef699133b..6bbd9bb24 100644 --- a/libfreerdp/crypto/base64.c +++ b/libfreerdp/crypto/base64.c @@ -26,7 +26,8 @@ static const char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; static const char base64url[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; -static char* base64_encode(const char* alphabet, const BYTE* data, size_t length, BOOL pad) +static char* base64_encode_ex(const char* alphabet, const BYTE* data, size_t length, BOOL pad, + BOOL crLf, size_t lineSize) { int c; const BYTE* q; @@ -34,9 +35,17 @@ static char* base64_encode(const char* alphabet, const BYTE* data, size_t length char* ret; int i = 0; int blocks; + size_t outLen = (length + 3) * 4 / 3; + size_t extra = 0; + if (crLf) + { + size_t nCrLf = (outLen + lineSize - 1) / lineSize; + extra = nCrLf * 2; + } + size_t outCounter = 0; q = data; - p = ret = (char*)malloc((length + 3) * 4 / 3 + 1); + p = ret = (char*)malloc(outLen + extra + 1); if (!p) return NULL; @@ -62,6 +71,13 @@ static char* base64_encode(const char* alphabet, const BYTE* data, size_t length *p++ = alphabet[(c & 0x0003F000) >> 12]; *p++ = alphabet[(c & 0x00000FC0) >> 6]; *p++ = alphabet[c & 0x0000003F]; + + outCounter += 4; + if (crLf && (outCounter % lineSize == 0)) + { + *p++ = '\r'; + *p++ = '\n'; + } } /* then remainder */ @@ -89,11 +105,21 @@ static char* base64_encode(const char* alphabet, const BYTE* data, size_t length break; } + if (crLf && length % 3) + { + *p++ = '\r'; + *p++ = '\n'; + } *p = 0; return ret; } +static char* base64_encode(const char* alphabet, const BYTE* data, size_t length, BOOL pad) +{ + return base64_encode_ex(alphabet, data, length, pad, FALSE, 64); +} + static int base64_decode_char(const char* alphabet, char c) { char* p = NULL; @@ -197,6 +223,11 @@ out_free: return NULL; } +char* crypto_base64_encode_ex(const BYTE* data, size_t length, BOOL withCrLf) +{ + return base64_encode_ex(base64, data, length, TRUE, withCrLf, 64); +} + char* crypto_base64_encode(const BYTE* data, size_t length) { return base64_encode(base64, data, length, TRUE); diff --git a/libfreerdp/crypto/test/TestBase64.c b/libfreerdp/crypto/test/TestBase64.c index dde275e35..1c01df799 100644 --- a/libfreerdp/crypto/test/TestBase64.c +++ b/libfreerdp/crypto/test/TestBase64.c @@ -156,7 +156,23 @@ int TestBase64(int argc, char* argv[]) fprintf(stderr, "ko, = in a wrong place\n"); return -1; } - fprintf(stderr, "ok\n"); + testNb++; + + /* test the encode_ex version that will add \r\n */ + fprintf(stderr, "%d:encode base64 with crLf...", testNb); + const char* longStr = "01234567890123456789012345678901234567890123456789"; + const char* longStrExpected = + "MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3\r\nODk=\r\n"; + + char* encoded = crypto_base64_encode_ex((const BYTE*)longStr, strlen(longStr), TRUE); + if (!encoded || strcmp(encoded, longStrExpected) != 0) + { + fprintf(stderr, "problem with encode with CRLF\n"); + return -1; + } + free(encoded); + fprintf(stderr, "ok\n"); + return 0; }