[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