[PATCH v3 2/2] crypt32: Add implementation for CRYPT_STRING_HEX format
Aaro Altonen
a.altonen at hotmail.com
Fri Mar 27 01:27:32 CDT 2020
Add CRYPT_STRING_HEX format implementation for CryptStringToBinaryW()
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=48487
Signed-off-by: Aaro Altonen <a.altonen at hotmail.com>
---
v2:
- remove wcstok() and string duplication entirely
- properly check wchars
(thanks Nikolay)
v3:
- If string length is zero, return ERROR_INVADLID_PARAMETER
---
dlls/crypt32/base64.c | 77 +++++++++++++++++++++++++++++++++++++
dlls/crypt32/tests/base64.c | 76 ++++++++++++++++++------------------
2 files changed, 115 insertions(+), 38 deletions(-)
diff --git a/dlls/crypt32/base64.c b/dlls/crypt32/base64.c
index 73619421ab..0a4ffa17a4 100644
--- a/dlls/crypt32/base64.c
+++ b/dlls/crypt32/base64.c
@@ -1036,6 +1036,81 @@ static LONG DecodeAnyW(LPCWSTR pszString, DWORD cchString,
return ret;
}
+static BYTE char_to_byte(WCHAR c)
+{
+ BYTE lb = c & 0xff;
+
+ /* upper byte is allowed to be 0xff */
+ if (c >> 8 != 0xff && c >> 8 != 0x00)
+ return 0xff;
+
+ if (lb >= '0' && lb <= '9')
+ return lb - '0';
+ if (lb >= 'a' && lb <= 'f')
+ return lb - 'a' + 10;
+ if (lb >= 'A' && lb <= 'F')
+ return lb - 'A' + 10;
+
+ return 0xff;
+}
+
+static LONG DecodeHexToBinaryW(const WCHAR *instr, DWORD slen,
+ BYTE *out, DWORD *outlen, DWORD *skip, DWORD *flags)
+{
+ BYTE un, ln;
+ const WCHAR delim[] = { ' ', '\n', '\r', '\t' };
+ const WCHAR *ptr = instr;
+ LONG ret = ERROR_SUCCESS;
+ DWORD i = 0, processed = 0;
+
+ if (!outlen || !slen)
+ return ERROR_INVALID_PARAMETER;
+
+ if (skip)
+ *skip = 0;
+
+ while (i < slen) {
+ while (strchrW(delim, *ptr) && *ptr) ptr++, i++;
+
+ if (i == slen)
+ break;
+
+ /* uneven amount of data */
+ if (i + 2 > slen)
+ {
+ if (!out)
+ *outlen = 0;
+ return ERROR_INVALID_DATA;
+ }
+
+ un = char_to_byte(*ptr);
+ ln = char_to_byte(*(ptr + 1));
+
+ if (un == 0xff || ln == 0xff)
+ {
+ if (!out)
+ *outlen = 0;
+ return ERROR_INVALID_DATA;
+ }
+
+ if (processed >= *outlen)
+ {
+ if (out)
+ return ERROR_MORE_DATA;
+ ret = ERROR_MORE_DATA;
+ }
+ else if (out)
+ out[processed] = (un << 4) | ln;
+
+ processed++;
+ ptr += 2;
+ i += 2;
+ }
+
+ *outlen = processed;
+ return ret;
+}
+
BOOL WINAPI CryptStringToBinaryW(LPCWSTR pszString,
DWORD cchString, DWORD dwFlags, BYTE *pbBinary, DWORD *pcbBinary,
DWORD *pdwSkip, DWORD *pdwFlags)
@@ -1081,6 +1156,8 @@ BOOL WINAPI CryptStringToBinaryW(LPCWSTR pszString,
decoder = DecodeAnyW;
break;
case CRYPT_STRING_HEX:
+ decoder = DecodeHexToBinaryW;
+ break;
case CRYPT_STRING_HEXASCII:
case CRYPT_STRING_HEXADDR:
case CRYPT_STRING_HEXASCIIADDR:
diff --git a/dlls/crypt32/tests/base64.c b/dlls/crypt32/tests/base64.c
index 981a7a0065..3b9b87a0c1 100644
--- a/dlls/crypt32/tests/base64.c
+++ b/dlls/crypt32/tests/base64.c
@@ -823,8 +823,8 @@ static void testStringToBinaryW(void)
data_len = 0xdeadbeef;
ret = CryptStringToBinaryW(input, 0, CRYPT_STRING_HEX, NULL, &data_len, &skip_, &flags);
ok(!ret, "Got %u, expected zero\n", ret);
- todo_wine ok(GetLastError() == ERROR_INVALID_DATA, "Got %d, expected 13\n", GetLastError());
- todo_wine ok(data_len == 0, "Got %u, expected 0\n", data_len);
+ ok(GetLastError() == ERROR_INVALID_DATA, "Got %d, expected 13\n", GetLastError());
+ ok(data_len == 0, "Got %u, expected 0\n", data_len);
/* length is uneven -> 13 */
SetLastError(0xdeadbeef);
@@ -832,8 +832,8 @@ static void testStringToBinaryW(void)
data_len = 0xdeadbeef;
ret = CryptStringToBinaryW(input, 3, CRYPT_STRING_HEX, NULL, &data_len, &skip_, &flags);
ok(!ret, "Got %u, expected zero\n", ret);
- todo_wine ok(GetLastError() == ERROR_INVALID_DATA, "Got %d, expected 13\n", GetLastError());
- todo_wine ok(data_len == 0, "Got %u, expected 0\n", data_len);
+ ok(GetLastError() == ERROR_INVALID_DATA, "Got %d, expected 13\n", GetLastError());
+ ok(data_len == 0, "Got %u, expected 0\n", data_len);
/* invalid 0x prefix -> 13 */
SetLastError(0xdeadbeef);
@@ -841,8 +841,8 @@ static void testStringToBinaryW(void)
data_len = 0xdeadbeef;
ret = CryptStringToBinaryW(input, 0, CRYPT_STRING_HEX, NULL, &data_len, &skip_, &flags);
ok(!ret, "Got %u, expected zero\n", ret);
- todo_wine ok(GetLastError() == ERROR_INVALID_DATA, "Got %d, expected 13\n", GetLastError());
- todo_wine ok(data_len == 0, "Got %u, expected 0\n", data_len);
+ ok(GetLastError() == ERROR_INVALID_DATA, "Got %d, expected 13\n", GetLastError());
+ ok(data_len == 0, "Got %u, expected 0\n", data_len);
/* invalid characters -> 13 */
SetLastError(0xdeadbeef);
@@ -850,8 +850,8 @@ static void testStringToBinaryW(void)
data_len = 0xdeadbeef;
ret = CryptStringToBinaryW(input, 0, CRYPT_STRING_HEX, NULL, &data_len, NULL, NULL);
ok(!ret, "Got %u, expected zero\n", ret);
- todo_wine ok(GetLastError() == ERROR_INVALID_DATA, "Got %d, expected 13\n", GetLastError());
- todo_wine ok(data_len == 0, "Got %u, expected 0\n", data_len);
+ ok(GetLastError() == ERROR_INVALID_DATA, "Got %d, expected 13\n", GetLastError());
+ ok(data_len == 0, "Got %u, expected 0\n", data_len);
/* insufficient buffer -> 234 */
SetLastError(0xdeadbeef);
@@ -864,18 +864,18 @@ static void testStringToBinaryW(void)
input = L"213c73796d6c696e6b3efffe";
ret = CryptStringToBinaryW(input, 24, CRYPT_STRING_HEX, out, &data_len, &skip_, &flags);
ok(!ret, "Got %u, expected zero\n", ret);
- todo_wine ok(GetLastError() == ERROR_MORE_DATA, "Got %d, expected 234\n", GetLastError());
+ ok(GetLastError() == ERROR_MORE_DATA, "Got %d, expected 234\n", GetLastError());
ok(data_len == 4, "Got %u, expected 4\n", data_len);
- todo_wine ok(!memcmp(out, expected, 4), "Invalid output from CryptStringToBinaryW()!\n");
+ ok(!memcmp(out, expected, 4), "Invalid output from CryptStringToBinaryW()!\n");
/* valid data */
SetLastError(0xdeadbeef);
input = L"213c73796d6c696e6b3efffe";
data_len = 0xdeadbeef;
ret = CryptStringToBinaryW(input, 24, CRYPT_STRING_HEX, NULL, &data_len, &skip_, &flags);
- todo_wine ok(ret, "Got %u, expected one\n", ret);
- todo_wine ok(GetLastError() == 0xdeadbeef, "Got %x, expected 0xdeadbeef\n", GetLastError());
- todo_wine ok(data_len == 12, "Got %u, expected 12\n", data_len);
+ ok(ret, "Got %u, expected one\n", ret);
+ ok(GetLastError() == 0xdeadbeef, "Got %x, expected 0xdeadbeef\n", GetLastError());
+ ok(data_len == 12, "Got %u, expected 12\n", data_len);
/* valid data with white spaces */
SetLastError(0xdeadbeef);
@@ -883,9 +883,9 @@ static void testStringToBinaryW(void)
data_len = 0xdeadbeef;
SetLastError(0xdeadbeef);
ret = CryptStringToBinaryW(input, 25, CRYPT_STRING_HEX, NULL, &data_len, &skip_, &flags);
- todo_wine ok(ret, "Got %u, expected one\n", ret);
- todo_wine ok(GetLastError() == 0xdeadbeef, "Got %d, expected 0xdeadbeef\n", GetLastError());
- todo_wine ok(data_len == 7, "Got %u, expected 7\n", data_len);
+ ok(ret, "Got %u, expected one\n", ret);
+ ok(GetLastError() == 0xdeadbeef, "Got %d, expected 0xdeadbeef\n", GetLastError());
+ ok(data_len == 7, "Got %u, expected 7\n", data_len);
/* valid data with white spaces but spacing breaks the valid data into invalid chunks */
SetLastError(0xdeadbeef);
@@ -893,8 +893,8 @@ static void testStringToBinaryW(void)
data_len = 0xdeadbeef;
ret = CryptStringToBinaryW(input, 0, CRYPT_STRING_HEX, NULL, &data_len, &skip_, &flags);
ok(!ret, "Got %u, expected zero\n", ret);
- todo_wine ok(GetLastError() == ERROR_INVALID_DATA, "Got %d, expected 13\n", GetLastError());
- todo_wine ok(data_len == 0, "Got %u, expected 0\n", data_len);
+ ok(GetLastError() == ERROR_INVALID_DATA, "Got %d, expected 13\n", GetLastError());
+ ok(data_len == 0, "Got %u, expected 0\n", data_len);
/* if "input" contains both valid and invalid data and "out" is valid, "out" shall contain all valid bytes
* until an invalid sequence is reached */
@@ -904,7 +904,7 @@ static void testStringToBinaryW(void)
input = L"21 3 c ff";
ret = CryptStringToBinaryW(input, 0, CRYPT_STRING_HEX, out, &data_len, &skip_, &flags);
ok(!ret, "Got %u, expected zero\n", ret);
- todo_wine ok(GetLastError() == ERROR_INVALID_DATA, "Got %d, expected 13\n", GetLastError());
+ ok(GetLastError() == ERROR_INVALID_DATA, "Got %d, expected 13\n", GetLastError());
ok(data_len == 4, "Got %u, expected 4\n", data_len);
/* valid data */
@@ -916,19 +916,19 @@ static void testStringToBinaryW(void)
input = L"213c73796d6c696e6b3efffe";
data_len = 256;
ret = CryptStringToBinaryW(input, 24, CRYPT_STRING_HEX, out, &data_len, &skip_, &flags);
- todo_wine ok(ret, "Got %u, expected one\n", ret);
- todo_wine ok(GetLastError() == 0xdeadbeef, "Got %x, expected 0xdeadbeef\n", GetLastError());
- todo_wine ok(data_len == 12, "Got %u, expected 12\n", data_len);
- todo_wine ok(!memcmp(out, expected, 12), "Invalid output from CryptStringToBinaryW()!\n");
+ ok(ret, "Got %u, expected one\n", ret);
+ ok(GetLastError() == 0xdeadbeef, "Got %x, expected 0xdeadbeef\n", GetLastError());
+ ok(data_len == 12, "Got %u, expected 12\n", data_len);
+ ok(!memcmp(out, expected, 12), "Invalid output from CryptStringToBinaryW()!\n");
/* invalid data but length small enough that it's never detected */
SetLastError(0xdeadbeef);
input = L"abcdefhhh";
data_len = 0xdeadbeef;
ret = CryptStringToBinaryW(input, 4, CRYPT_STRING_HEX, NULL, &data_len, NULL, NULL);
- todo_wine ok(ret, "Got %u, expected one\n", ret);
- todo_wine ok(GetLastError() == 0xdeadbeef, "Got %x, expected 0xdeadbeef\n", GetLastError());
- todo_wine ok(data_len == 2, "Got %u, expected 2\n", data_len);
+ ok(ret, "Got %u, expected one\n", ret);
+ ok(GetLastError() == 0xdeadbeef, "Got %x, expected 0xdeadbeef\n", GetLastError());
+ ok(data_len == 2, "Got %u, expected 2\n", data_len);
/* invalid data but length small enough that it's never detected, with whitespaces */
SetLastError(0xdeadbeef);
@@ -936,24 +936,24 @@ static void testStringToBinaryW(void)
input = L"\t\t21 fe f f f";
data_len = 256;
ret = CryptStringToBinaryW(input, 5, CRYPT_STRING_HEX, out, &data_len, &skip_, &flags);
- todo_wine ok(ret, "Got %u, expected one\n", ret);
- todo_wine ok(GetLastError() == 0xdeadbeef, "Got %x, expected 0xdeadbeef\n", GetLastError());
- todo_wine ok(data_len == 1, "Got %u, expected 1\n", data_len);
+ ok(ret, "Got %u, expected one\n", ret);
+ ok(GetLastError() == 0xdeadbeef, "Got %x, expected 0xdeadbeef\n", GetLastError());
+ ok(data_len == 1, "Got %u, expected 1\n", data_len);
SetLastError(0xdeadbeef);
data_len = 0xdeadbeef;
ret = CryptStringToBinaryW(winput1, 6, CRYPT_STRING_HEX, NULL, &data_len, NULL, NULL);
- todo_wine ok(ret || broken(!ret), "Got %u, expected one\n", ret);
- todo_wine ok(GetLastError() == 0xdeadbeef || broken(GetLastError() == 122),
+ ok(ret || broken(!ret), "Got %u, expected one\n", ret);
+ ok(GetLastError() == 0xdeadbeef || broken(GetLastError() == 122),
"Got %d, expected 13\n", GetLastError());
- todo_wine ok(data_len == 3 || broken(data_len == 0xdeadbeef), "Got %u, expected 3\n", data_len);
+ ok(data_len == 3 || broken(data_len == 0xdeadbeef), "Got %u, expected 3\n", data_len);
SetLastError(0xdeadbeef);
data_len = 0xdeadbeef;
ret = CryptStringToBinaryW(winput2, 6, CRYPT_STRING_HEX, NULL, &data_len, NULL, NULL);
ok(!ret, "Got %u, expected zero\n", ret);
- todo_wine ok(GetLastError() == ERROR_INVALID_DATA, "Got %d, expected 13\n", GetLastError());
- todo_wine ok(data_len == 0, "Got %u, expected 0\n", data_len);
+ ok(GetLastError() == ERROR_INVALID_DATA, "Got %d, expected 13\n", GetLastError());
+ ok(data_len == 0, "Got %u, expected 0\n", data_len);
/* valid data but parse only the first 6 bytes (12 chars) */
SetLastError(0xdeadbeef);
@@ -963,10 +963,10 @@ static void testStringToBinaryW(void)
input = L"213c73796d6c696e6b3efffe";
data_len = 256;
ret = CryptStringToBinaryW(input, 12, CRYPT_STRING_HEX, out, &data_len, &skip_, &flags);
- todo_wine ok(ret, "Got %u, expected one\n", ret);
- todo_wine ok(GetLastError() == 0xdeadbeef, "Got %x, expected 0xdeadbeef\n", GetLastError());
- todo_wine ok(data_len == 6, "Got %u, expected 6\n", data_len);
- todo_wine ok(!memcmp(out, expected, 6), "Invalid output from CryptStringToBinaryW()!\n");
+ ok(ret, "Got %u, expected one\n", ret);
+ ok(GetLastError() == 0xdeadbeef, "Got %x, expected 0xdeadbeef\n", GetLastError());
+ ok(data_len == 6, "Got %u, expected 6\n", data_len);
+ ok(!memcmp(out, expected, 6), "Invalid output from CryptStringToBinaryW()!\n");
}
START_TEST(base64)
--
2.25.2
More information about the wine-devel
mailing list