crypt32: Make CryptBinaryToStringA fill short base64 buffer correctly.

Signed-off-by: Jeff Smith <whydoubt@gmail.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Jeff Smith 2019-10-09 12:53:55 -05:00 committed by Alexandre Julliard
parent e0708d0601
commit a9e6f9aa71
2 changed files with 56 additions and 51 deletions

View File

@ -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)
{
LPSTR ptr = pszString;
DWORD size = *pcchString;
LPSTR end = ptr + size;
if (header)
{
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 (ptr < end)
*ptr = '\0';
if (charsNeeded <= *pcchString)
{
LPSTR ptr = pszString;
DWORD size = charsNeeded;
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);
}
*pcchString = charsNeeded - 1;
}
else

View File

@ -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());