Jeff Smith : crypt32: Make CryptBinaryToStringA fill short base64 buffer correctly.

Alexandre Julliard julliard at winehq.org
Wed Oct 9 14:36:29 CDT 2019


Module: wine
Branch: master
Commit: a9e6f9aa71074f96fda9a2475ef1b9009ceeb652
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=a9e6f9aa71074f96fda9a2475ef1b9009ceeb652

Author: Jeff Smith <whydoubt at gmail.com>
Date:   Wed Oct  9 12:53:55 2019 -0500

crypt32: Make CryptBinaryToStringA fill short base64 buffer correctly.

Signed-off-by: Jeff Smith <whydoubt at gmail.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/crypt32/base64.c       | 105 +++++++++++++++++++++++---------------------
 dlls/crypt32/tests/base64.c |   2 -
 2 files changed, 56 insertions(+), 51 deletions(-)

diff --git a/dlls/crypt32/base64.c b/dlls/crypt32/base64.c
index acd05ec1a5..ac60c6efbd 100644
--- a/dlls/crypt32/base64.c
+++ b/dlls/crypt32/base64.c
@@ -93,50 +93,53 @@ static BOOL EncodeBinaryToBinaryA(const BYTE *pbBinary,
     return ret;
 }
 
-static LONG encodeBase64A(const BYTE *in_buf, int in_len, LPCSTR sep,
+static DWORD stradd(LPSTR ptr, LPCSTR end, LPCSTR s, DWORD slen)
+{
+    if (ptr + slen > end)
+        slen = end - ptr;
+    memcpy(ptr, s, slen);
+    return slen;
+}
+
+static DWORD encodeBase64A(const BYTE *in_buf, int in_len, LPCSTR sep,
  char* out_buf, DWORD *out_len)
 {
     int div, i;
     const BYTE *d = in_buf;
     int bytes = (in_len*8 + 5)/6, pad_bytes = (bytes % 4) ? 4 - (bytes % 4) : 0;
-    DWORD needed;
     LPSTR ptr;
+    LPCSTR end;
+    char chunk[4];
 
-    TRACE("bytes is %d, pad bytes is %d\n", bytes, pad_bytes);
-    needed = bytes + pad_bytes;
-    needed += (needed / 64 + (needed % 64 ? 1 : 0)) * strlen(sep);
-    needed++;
-
-    if (needed > *out_len)
+    if (!out_buf)
     {
-        *out_len = needed;
-        return ERROR_INSUFFICIENT_BUFFER;
+        TRACE("bytes is %d, pad bytes is %d\n", bytes, pad_bytes);
+        *out_len = bytes + pad_bytes;
+        *out_len += (*out_len / 64 + (*out_len % 64 ? 1 : 0)) * strlen(sep) + 1;
+        return 0;
     }
-    else
-        *out_len = needed;
 
     /* Three bytes of input give 4 chars of output */
     div = in_len / 3;
 
     ptr = out_buf;
+    end = ptr + *out_len;
     i = 0;
-    while (div > 0)
+    while (div > 0 && ptr < end)
     {
         if (i && i % 64 == 0)
-        {
-            strcpy(ptr, sep);
-            ptr += strlen(sep);
-        }
+            ptr += stradd(ptr, end, sep, strlen(sep));
         /* first char is the first 6 bits of the first byte*/
-        *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
+        chunk[0] = b64[ ( d[0] >> 2) & 0x3f ];
         /* second char is the last 2 bits of the first byte and the first 4
          * bits of the second byte */
-        *ptr++ = b64[ ((d[0] << 4) & 0x30) | (d[1] >> 4 & 0x0f)];
+        chunk[1] = b64[ ((d[0] << 4) & 0x30) | (d[1] >> 4 & 0x0f)];
         /* third char is the last 4 bits of the second byte and the first 2
          * bits of the third byte */
-        *ptr++ = b64[ ((d[1] << 2) & 0x3c) | (d[2] >> 6 & 0x03)];
+        chunk[2] = b64[ ((d[1] << 2) & 0x3c) | (d[2] >> 6 & 0x03)];
         /* fourth char is the remaining 6 bits of the third byte */
-        *ptr++ = b64[   d[2]       & 0x3f];
+        chunk[3] = b64[   d[2]       & 0x3f];
+        ptr += stradd(ptr, end, chunk, 4);
         i += 4;
         d += 3;
         div--;
@@ -146,31 +149,33 @@ static LONG encodeBase64A(const BYTE *in_buf, int in_len, LPCSTR sep,
     {
         case 1:
             /* first char is the first 6 bits of the first byte*/
-            *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
+            chunk[0] = b64[ ( d[0] >> 2) & 0x3f ];
             /* second char is the last 2 bits of the first byte and the first 4
              * bits of the second byte */
-            *ptr++ = b64[ ((d[0] << 4) & 0x30) | (d[1] >> 4 & 0x0f)];
+            chunk[1] = b64[ ((d[0] << 4) & 0x30) | (d[1] >> 4 & 0x0f)];
             /* third char is the last 4 bits of the second byte padded with
              * two zeroes */
-            *ptr++ = b64[ ((d[1] << 2) & 0x3c) ];
+            chunk[2] = b64[ ((d[1] << 2) & 0x3c) ];
             /* fourth char is a = to indicate one byte of padding */
-            *ptr++ = '=';
+            chunk[3] = '=';
+            ptr += stradd(ptr, end, chunk, 4);
             break;
         case 2:
             /* first char is the first 6 bits of the first byte*/
-            *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
+            chunk[0] = b64[ ( d[0] >> 2) & 0x3f ];
             /* second char is the last 2 bits of the first byte padded with
              * four zeroes*/
-            *ptr++ = b64[ ((d[0] << 4) & 0x30)];
+            chunk[1] = b64[ ((d[0] << 4) & 0x30)];
             /* third char is = to indicate padding */
-            *ptr++ = '=';
+            chunk[2] = '=';
             /* fourth char is = to indicate padding */
-            *ptr++ = '=';
+            chunk[3] = '=';
+            ptr += stradd(ptr, end, chunk, 4);
             break;
     }
-    strcpy(ptr, sep);
+    ptr += stradd(ptr, end, sep, strlen(sep));
 
-    return ERROR_SUCCESS;
+    return ptr - out_buf;
 }
 
 static BOOL BinaryToBase64A(const BYTE *pbBinary,
@@ -215,26 +220,28 @@ static BOOL BinaryToBase64A(const BYTE *pbBinary,
 
     if (pszString)
     {
-        if (charsNeeded <= *pcchString)
+        LPSTR ptr = pszString;
+        DWORD size = *pcchString;
+        LPSTR end = ptr + size;
+
+        if (header)
         {
-            LPSTR ptr = pszString;
-            DWORD size = charsNeeded;
+            ptr += stradd(ptr, end, header, strlen(header));
+            ptr += stradd(ptr, end, sep, strlen(sep));
+            size = end - ptr;
+        }
+        ptr += encodeBase64A(pbBinary, cbBinary, sep, ptr, &size);
+        if (trailer)
+        {
+            ptr += stradd(ptr, end, trailer, strlen(trailer));
+            ptr += stradd(ptr, end, sep, strlen(sep));
+        }
 
-            if (header)
-            {
-                strcpy(ptr, header);
-                ptr += strlen(ptr);
-                strcpy(ptr, sep);
-                ptr += strlen(sep);
-            }
-            encodeBase64A(pbBinary, cbBinary, sep, ptr, &size);
-            ptr += size - 1;
-            if (trailer)
-            {
-                strcpy(ptr, trailer);
-                ptr += strlen(ptr);
-               strcpy(ptr, sep);
-            }
+        if (ptr < end)
+            *ptr = '\0';
+
+        if (charsNeeded <= *pcchString)
+        {
             *pcchString = charsNeeded - 1;
         }
         else
diff --git a/dlls/crypt32/tests/base64.c b/dlls/crypt32/tests/base64.c
index f2d16735ab..31605fe6b9 100644
--- a/dlls/crypt32/tests/base64.c
+++ b/dlls/crypt32/tests/base64.c
@@ -137,12 +137,10 @@ static void encodeAndCompareBase64_A(const BYTE *toEncode, DWORD toEncodeLen,
     ok((!ret && GetLastError() == ERROR_MORE_DATA) || broken(ret) /* XP */, "CryptBinaryToStringA failed %d, error %d.\n",
         ret, GetLastError());
     ok(strLen2 == strLen || broken(strLen2 == strLen - 1), "Expected length %d, got %d\n", strLen, strLen2);
-todo_wine {
     if (header)
         ok(str[0] == header[0], "Unexpected buffer contents %#x.\n", str[0]);
     else
         ok(str[0] == expected[0], "Unexpected buffer contents %#x.\n", str[0]);
-}
     strLen2 = strLen;
     ret = CryptBinaryToStringA(toEncode, toEncodeLen, format, str, &strLen2);
     ok(ret, "CryptBinaryToStringA failed: %d\n", GetLastError());




More information about the wine-cvs mailing list