From 23791c2510e8d06c9bc1b1323e070eb6b3cc39ff Mon Sep 17 00:00:00 2001 From: Juan Lang Date: Wed, 31 May 2006 00:31:10 -0700 Subject: [PATCH] crypt32: Implement CryptBinaryToStringA and CryptStringToBinaryA. Implement CryptBinaryToStringA and CryptStringToBinaryA based on Kai Blin's base64 encoder/decoder. --- dlls/crypt32/Makefile.in | 1 + dlls/crypt32/base64.c | 579 +++++++++++++++++++++++++++++++++ dlls/crypt32/crypt32.spec | 4 + dlls/crypt32/tests/.gitignore | 1 + dlls/crypt32/tests/Makefile.in | 1 + dlls/crypt32/tests/base64.c | 456 ++++++++++++++++++++++++++ include/wincrypt.h | 29 ++ 7 files changed, 1071 insertions(+) create mode 100644 dlls/crypt32/base64.c create mode 100644 dlls/crypt32/tests/base64.c diff --git a/dlls/crypt32/Makefile.in b/dlls/crypt32/Makefile.in index 5e1862e240c..6c340c0efa9 100644 --- a/dlls/crypt32/Makefile.in +++ b/dlls/crypt32/Makefile.in @@ -8,6 +8,7 @@ IMPORTLIB = libcrypt32.$(IMPLIBEXT) IMPORTS = user32 advapi32 kernel32 ntdll C_SRCS = \ + base64.c \ cert.c \ crl.c \ context.c \ diff --git a/dlls/crypt32/base64.c b/dlls/crypt32/base64.c new file mode 100644 index 00000000000..e4c2dd49255 --- /dev/null +++ b/dlls/crypt32/base64.c @@ -0,0 +1,579 @@ +/* + * base64 encoder/decoder + * + * Copyright 2005 by Kai Blin + * Copyright 2006 Juan Lang + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "wincrypt.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(crypt); + +#define CERT_HEADER "-----BEGIN CERTIFICATE-----" +#define CERT_TRAILER "-----END CERTIFICATE-----" +#define CERT_REQUEST_HEADER "-----BEGIN NEW CERTIFICATE REQUEST-----" +#define CERT_REQUEST_TRAILER "-----END NEW CERTIFICATE REQUEST-----" +#define X509_HEADER "-----BEGIN X509 CRL-----" +#define X509_TRAILER "-----END X509 CRL-----" + +static const char b64[] = +"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +typedef BOOL (*BinaryToStringAFunc)(const BYTE *pbBinary, + DWORD cbBinary, DWORD dwFlags, LPSTR pszString, DWORD *pcchString); + +static BOOL EncodeBinaryToBinaryA(const BYTE *pbBinary, + DWORD cbBinary, DWORD dwFlags, LPSTR pszString, DWORD *pcchString) +{ + BOOL ret = TRUE; + + if (*pcchString < cbBinary) + { + if (!pszString) + *pcchString = cbBinary; + else + { + SetLastError(ERROR_INSUFFICIENT_BUFFER); + *pcchString = cbBinary; + ret = FALSE; + } + } + else + { + if (cbBinary) + memcpy(pszString, pbBinary, cbBinary); + *pcchString = cbBinary; + } + return ret; +} + +static LONG 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; + + TRACE("bytes is %d, pad bytes is %d\n", bytes, pad_bytes); + needed = bytes + pad_bytes + 1; + needed += (needed / 64 + 1) * strlen(sep); + + if (needed > *out_len) + { + *out_len = needed; + return ERROR_INSUFFICIENT_BUFFER; + } + else + *out_len = needed; + + /* Three bytes of input give 4 chars of output */ + div = in_len / 3; + + ptr = out_buf; + i = 0; + while (div > 0) + { + if (i && i % 64 == 0) + { + strcpy(ptr, sep); + ptr += strlen(sep); + } + /* first char is the first 6 bits of the first byte*/ + *ptr++ = 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)]; + /* 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)]; + /* fourth char is the remaining 6 bits of the third byte */ + *ptr++ = b64[ d[2] & 0x3f]; + i += 4; + d += 3; + div--; + } + + switch(pad_bytes) + { + case 1: + /* first char is the first 6 bits of the first byte*/ + *ptr++ = 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)]; + /* third char is the last 4 bits of the second byte padded with + * two zeroes */ + *ptr++ = b64[ ((d[1] << 2) & 0x3c) ]; + /* fourth char is a = to indicate one byte of padding */ + *ptr++ = '='; + break; + case 2: + /* first char is the first 6 bits of the first byte*/ + *ptr++ = 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)]; + /* third char is = to indicate padding */ + *ptr++ = '='; + /* fourth char is = to indicate padding */ + *ptr++ = '='; + break; + } + strcpy(ptr, sep); + + return ERROR_SUCCESS; +} + +static BOOL BinaryToBase64A(const BYTE *pbBinary, + DWORD cbBinary, DWORD dwFlags, LPSTR pszString, DWORD *pcchString) +{ + static const char crlf[] = "\r\n", lf[] = "\n"; + BOOL ret = TRUE; + LPCSTR header = NULL, trailer = NULL, sep = NULL; + DWORD charsNeeded; + + if (dwFlags & CRYPT_STRING_NOCR) + sep = lf; + else + sep = crlf; + switch (dwFlags & 0x7fffffff) + { + case CRYPT_STRING_BASE64: + /* no header or footer */ + break; + case CRYPT_STRING_BASE64HEADER: + header = CERT_HEADER; + trailer = CERT_TRAILER; + break; + case CRYPT_STRING_BASE64REQUESTHEADER: + header = CERT_REQUEST_HEADER; + trailer = CERT_REQUEST_TRAILER; + break; + case CRYPT_STRING_BASE64X509CRLHEADER: + header = X509_HEADER; + trailer = X509_TRAILER; + break; + } + + charsNeeded = 0; + encodeBase64A(pbBinary, cbBinary, sep, NULL, &charsNeeded); + charsNeeded += strlen(sep); + if (header) + charsNeeded += strlen(header) + strlen(sep); + if (trailer) + charsNeeded += strlen(trailer) + strlen(sep); + 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); + ptr += strlen(sep); + } + *pcchString = charsNeeded - 1; + } + else if (pszString) + { + *pcchString = charsNeeded; + SetLastError(ERROR_INSUFFICIENT_BUFFER); + ret = FALSE; + } + else + *pcchString = charsNeeded; + return ret; +} + +BOOL WINAPI CryptBinaryToStringA(const BYTE *pbBinary, + DWORD cbBinary, DWORD dwFlags, LPSTR pszString, DWORD *pcchString) +{ + BinaryToStringAFunc encoder = NULL; + + TRACE("(%p, %ld, %08lx, %p, %p)\n", pbBinary, cbBinary, dwFlags, pszString, + pcchString); + + if (!pbBinary) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + if (!pcchString) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + switch (dwFlags & 0x7fffffff) + { + case CRYPT_STRING_BINARY: + encoder = EncodeBinaryToBinaryA; + break; + case CRYPT_STRING_BASE64: + case CRYPT_STRING_BASE64HEADER: + case CRYPT_STRING_BASE64REQUESTHEADER: + case CRYPT_STRING_BASE64X509CRLHEADER: + encoder = BinaryToBase64A; + break; + case CRYPT_STRING_HEX: + case CRYPT_STRING_HEXASCII: + case CRYPT_STRING_HEXADDR: + case CRYPT_STRING_HEXASCIIADDR: + FIXME("Unimplemented type %ld\n", dwFlags & 0x7fffffff); + /* fall through */ + default: + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + return encoder(pbBinary, cbBinary, dwFlags, pszString, pcchString); +} + +static inline BYTE decodeBase64Byte(char c) +{ + BYTE ret; + + if (c >= 'A' && c <= 'Z') + ret = c - 'A'; + else if (c >= 'a' && c <= 'z') + ret = c - 'a' + 26; + else if (c >= '0' && c <= '9') + ret = c - '0' + 52; + else if (c == '+') + ret = 62; + else if (c == '/') + ret = 63; + else + ret = 64; + return ret; +} + +static LONG decodeBase64Block(const char *in_buf, int in_len, + const char **nextBlock, PBYTE out_buf, DWORD *out_len) +{ + int len = in_len, i; + const char *d = in_buf; + int ip0, ip1, ip2, ip3; + + if (len < 4) + return ERROR_INVALID_DATA; + + i = 0; + if (d[2] == '=') + { + if ((ip0 = decodeBase64Byte(d[0])) > 63) + return ERROR_INVALID_DATA; + if ((ip1 = decodeBase64Byte(d[1])) > 63) + return ERROR_INVALID_DATA; + + if (out_buf) + out_buf[i] = (ip0 << 2) | (ip1 >> 4); + i++; + } + else if (d[3] == '=') + { + if ((ip0 = decodeBase64Byte(d[0])) > 63) + return ERROR_INVALID_DATA; + if ((ip1 = decodeBase64Byte(d[1])) > 63) + return ERROR_INVALID_DATA; + if ((ip2 = decodeBase64Byte(d[2])) > 63) + return ERROR_INVALID_DATA; + + if (out_buf) + { + out_buf[i + 0] = (ip0 << 2) | (ip1 >> 4); + out_buf[i + 1] = (ip1 << 4) | (ip2 >> 2); + } + i += 2; + } + else + { + if ((ip0 = decodeBase64Byte(d[0])) > 63) + return ERROR_INVALID_DATA; + if ((ip1 = decodeBase64Byte(d[1])) > 63) + return ERROR_INVALID_DATA; + if ((ip2 = decodeBase64Byte(d[2])) > 63) + return ERROR_INVALID_DATA; + if ((ip3 = decodeBase64Byte(d[3])) > 63) + return ERROR_INVALID_DATA; + + if (out_buf) + { + out_buf[i + 0] = (ip0 << 2) | (ip1 >> 4); + out_buf[i + 1] = (ip1 << 4) | (ip2 >> 2); + out_buf[i + 2] = (ip2 << 6) | ip3; + } + i += 3; + } + if (len >= 6 && d[4] == '\r' && d[5] == '\n') + *nextBlock = d + 6; + else if (len >= 5 && d[4] == '\n') + *nextBlock = d + 5; + else if (len >= 4 && d[4]) + *nextBlock = d + 4; + else + *nextBlock = NULL; + *out_len = i; + return ERROR_SUCCESS; +} + +/* Unlike CryptStringToBinaryA, cchString is guaranteed to be the length of the + * string to convert. + */ +typedef LONG (*StringToBinaryAFunc)(LPCSTR pszString, DWORD cchString, + BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags); + +static LONG Base64ToBinaryA(LPCSTR pszString, DWORD cchString, + BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags) +{ + LONG ret = ERROR_SUCCESS; + const char *nextBlock; + DWORD outLen = 0; + + nextBlock = pszString; + while (nextBlock && !ret) + { + DWORD len = 0; + + ret = decodeBase64Block(nextBlock, cchString - (nextBlock - pszString), + &nextBlock, pbBinary ? pbBinary + outLen : NULL, &len); + if (!ret) + outLen += len; + if (cchString - (nextBlock - pszString) <= 0) + nextBlock = NULL; + } + *pcbBinary = outLen; + if (!ret) + { + if (pdwSkip) + *pdwSkip = 0; + if (pdwFlags) + *pdwFlags = CRYPT_STRING_BASE64; + } + else if (ret == ERROR_INSUFFICIENT_BUFFER) + { + if (!pbBinary) + ret = ERROR_SUCCESS; + } + return ret; +} + +static LONG Base64WithHeaderAndTrailerToBinaryA(LPCSTR pszString, + DWORD cchString, LPCSTR header, LPCSTR trailer, BYTE *pbBinary, + DWORD *pcbBinary, DWORD *pdwSkip) +{ + LONG ret; + LPCSTR ptr; + + if (cchString > strlen(header) + strlen(trailer) + && (ptr = strstr(pszString, header)) != NULL) + { + LPCSTR trailerSpot = pszString + cchString - strlen(trailer); + + if (pszString[cchString - 1] == '\n') + { + cchString--; + trailerSpot--; + } + if (pszString[cchString - 1] == '\r') + { + cchString--; + trailerSpot--; + } + if (!strncmp(trailerSpot, trailer, strlen(trailer))) + { + if (pdwSkip) + *pdwSkip = ptr - pszString; + ptr += strlen(header); + if (*ptr == '\r') ptr++; + if (*ptr == '\n') ptr++; + cchString -= ptr - pszString + strlen(trailer); + ret = Base64ToBinaryA(ptr, cchString, pbBinary, pcbBinary, NULL, + NULL); + } + else + ret = ERROR_INVALID_DATA; + } + else + ret = ERROR_INVALID_DATA; + return ret; +} + +static LONG Base64HeaderToBinaryA(LPCSTR pszString, DWORD cchString, + BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags) +{ + LONG ret = Base64WithHeaderAndTrailerToBinaryA(pszString, cchString, + CERT_HEADER, CERT_TRAILER, pbBinary, pcbBinary, pdwSkip); + + if (!ret && pdwFlags) + *pdwFlags = CRYPT_STRING_BASE64HEADER; + return ret; +} + +static LONG Base64RequestHeaderToBinaryA(LPCSTR pszString, DWORD cchString, + BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags) +{ + LONG ret = Base64WithHeaderAndTrailerToBinaryA(pszString, cchString, + CERT_REQUEST_HEADER, CERT_REQUEST_TRAILER, pbBinary, pcbBinary, pdwSkip); + + if (!ret && pdwFlags) + *pdwFlags = CRYPT_STRING_BASE64REQUESTHEADER; + return ret; +} + +static LONG Base64X509HeaderToBinaryA(LPCSTR pszString, DWORD cchString, + BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags) +{ + LONG ret = Base64WithHeaderAndTrailerToBinaryA(pszString, cchString, + X509_HEADER, X509_TRAILER, pbBinary, pcbBinary, pdwSkip); + + if (!ret && pdwFlags) + *pdwFlags = CRYPT_STRING_BASE64X509CRLHEADER; + return ret; +} + +static LONG Base64AnyToBinaryA(LPCSTR pszString, DWORD cchString, + BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags) +{ + LONG ret; + + ret = Base64HeaderToBinaryA(pszString, cchString, pbBinary, pcbBinary, + pdwSkip, pdwFlags); + if (ret == ERROR_INVALID_DATA) + ret = Base64ToBinaryA(pszString, cchString, pbBinary, pcbBinary, + pdwSkip, pdwFlags); + return ret; +} + +static LONG DecodeBinaryToBinaryA(LPCSTR pszString, DWORD cchString, + BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags) +{ + LONG ret = ERROR_SUCCESS; + + if (*pcbBinary < cchString) + { + if (!pbBinary) + *pcbBinary = cchString; + else + { + ret = ERROR_INSUFFICIENT_BUFFER; + *pcbBinary = cchString; + } + } + else + { + if (cchString) + memcpy(pbBinary, pszString, cchString); + *pcbBinary = cchString; + } + return ret; +} + +static LONG DecodeAnyA(LPCSTR pszString, DWORD cchString, + BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags) +{ + LONG ret; + + ret = Base64HeaderToBinaryA(pszString, cchString, pbBinary, pcbBinary, + pdwSkip, pdwFlags); + if (ret == ERROR_INVALID_DATA) + ret = Base64ToBinaryA(pszString, cchString, pbBinary, pcbBinary, + pdwSkip, pdwFlags); + if (ret == ERROR_INVALID_DATA) + ret = DecodeBinaryToBinaryA(pszString, cchString, pbBinary, pcbBinary, + pdwSkip, pdwFlags); + return ret; +} + +BOOL WINAPI CryptStringToBinaryA(LPCSTR pszString, + DWORD cchString, DWORD dwFlags, BYTE *pbBinary, DWORD *pcbBinary, + DWORD *pdwSkip, DWORD *pdwFlags) +{ + StringToBinaryAFunc decoder; + LONG ret; + + TRACE("(%s, %ld, %08lx, %p, %p, %p, %p)\n", debugstr_a(pszString), + cchString, dwFlags, pbBinary, pcbBinary, pdwSkip, pdwFlags); + + if (!pszString) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + /* Only the bottom byte contains valid types */ + if (dwFlags & 0xfffffff0) + { + SetLastError(ERROR_INVALID_DATA); + return FALSE; + } + switch (dwFlags) + { + case CRYPT_STRING_BASE64_ANY: + decoder = Base64AnyToBinaryA; + break; + case CRYPT_STRING_BASE64: + decoder = Base64ToBinaryA; + break; + case CRYPT_STRING_BASE64HEADER: + decoder = Base64HeaderToBinaryA; + break; + case CRYPT_STRING_BASE64REQUESTHEADER: + decoder = Base64RequestHeaderToBinaryA; + break; + case CRYPT_STRING_BASE64X509CRLHEADER: + decoder = Base64X509HeaderToBinaryA; + break; + case CRYPT_STRING_BINARY: + decoder = DecodeBinaryToBinaryA; + break; + case CRYPT_STRING_ANY: + decoder = DecodeAnyA; + break; + case CRYPT_STRING_HEX: + case CRYPT_STRING_HEXASCII: + case CRYPT_STRING_HEXADDR: + case CRYPT_STRING_HEXASCIIADDR: + FIXME("Unimplemented type %ld\n", dwFlags & 0x7fffffff); + /* fall through */ + default: + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + if (!cchString) + cchString = strlen(pszString); + ret = decoder(pszString, cchString, pbBinary, pcbBinary, pdwSkip, pdwFlags); + if (ret) + SetLastError(ret); + return (ret == ERROR_SUCCESS) ? TRUE : FALSE; +} diff --git a/dlls/crypt32/crypt32.spec b/dlls/crypt32/crypt32.spec index a525c65eeac..e7198786a22 100644 --- a/dlls/crypt32/crypt32.spec +++ b/dlls/crypt32/crypt32.spec @@ -88,6 +88,10 @@ @ stdcall CertVerifyTimeValidity(ptr ptr) @ stub CertVerifyValidityNesting @ stub CreateFileU +@ stdcall CryptBinaryToStringA(ptr long long ptr ptr) +@ stub CryptBinaryToStringW # (ptr long long ptr ptr) +@ stdcall CryptStringToBinaryA(str long long ptr ptr ptr ptr) +@ stub CryptStringToBinaryW # (wstr long long ptr ptr ptr ptr) @ stub CryptAcquireContextU @ stub CryptCloseAsyncHandle @ stub CryptCreateAsyncHandle diff --git a/dlls/crypt32/tests/.gitignore b/dlls/crypt32/tests/.gitignore index c8836b56aed..9e3f1bc539a 100644 --- a/dlls/crypt32/tests/.gitignore +++ b/dlls/crypt32/tests/.gitignore @@ -1,4 +1,5 @@ Makefile +base64.ok cert.ok encode.ok main.ok diff --git a/dlls/crypt32/tests/Makefile.in b/dlls/crypt32/tests/Makefile.in index ffb0100e676..833327a7df1 100644 --- a/dlls/crypt32/tests/Makefile.in +++ b/dlls/crypt32/tests/Makefile.in @@ -6,6 +6,7 @@ TESTDLL = crypt32.dll IMPORTS = crypt32 advapi32 kernel32 CTESTS = \ + base64.c \ cert.c \ encode.c \ main.c \ diff --git a/dlls/crypt32/tests/base64.c b/dlls/crypt32/tests/base64.c new file mode 100644 index 00000000000..9f948c1e3fd --- /dev/null +++ b/dlls/crypt32/tests/base64.c @@ -0,0 +1,456 @@ +/* + * Unit test suite for crypt32.dll's CryptStringToBinary and CryptBinaryToString + * functions. + * + * Copyright 2006 Juan Lang + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ +#include +#include +#include +#include +#include +#include + +#include "wine/test.h" + +#define CERT_HEADER "-----BEGIN CERTIFICATE-----\r\n" +#define CERT_TRAILER "-----END CERTIFICATE-----\r\n" +#define CERT_REQUEST_HEADER "-----BEGIN NEW CERTIFICATE REQUEST-----\r\n" +#define CERT_REQUEST_TRAILER "-----END NEW CERTIFICATE REQUEST-----\r\n" +#define X509_HEADER "-----BEGIN X509 CRL-----\r\n" +#define X509_TRAILER "-----END X509 CRL-----\r\n" +#define CERT_HEADER_NOCR "-----BEGIN CERTIFICATE-----\n" +#define CERT_TRAILER_NOCR "-----END CERTIFICATE-----\n" +#define CERT_REQUEST_HEADER_NOCR "-----BEGIN NEW CERTIFICATE REQUEST-----\n" +#define CERT_REQUEST_TRAILER_NOCR "-----END NEW CERTIFICATE REQUEST-----\n" +#define X509_HEADER_NOCR "-----BEGIN X509 CRL-----\n" +#define X509_TRAILER_NOCR "-----END X509 CRL-----\n" + +typedef BOOL (WINAPI *CryptBinaryToStringAFunc)(const BYTE *pbBinary, + DWORD cbBinary, DWORD dwFlags, LPSTR pszString, DWORD *pcchString); +typedef BOOL (WINAPI *CryptStringToBinaryAFunc)(LPCSTR pszString, + DWORD cchString, DWORD dwFlags, BYTE *pbBinary, DWORD *pcbBinary, + DWORD *pdwSkip, DWORD *pdwFlags); + +CryptBinaryToStringAFunc pCryptBinaryToStringA; +CryptStringToBinaryAFunc pCryptStringToBinaryA; + +struct BinTests +{ + const BYTE *toEncode; + DWORD toEncodeLen; + const char *base64; +}; + +static const BYTE toEncode1[] = { 0 }; +static const BYTE toEncode2[] = { 1,2 }; +static const BYTE toEncode3[] = { 1,2,3 }; +static const BYTE toEncode4[] = + "abcdefghijlkmnopqrstuvwxyz01234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890" + "abcdefghijlkmnopqrstuvwxyz01234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890" + "abcdefghijlkmnopqrstuvwxyz01234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890"; + +struct BinTests tests[] = { + { toEncode1, sizeof(toEncode1), "AA==\r\n", }, + { toEncode2, sizeof(toEncode2), "AQI=\r\n", }, + { toEncode3, sizeof(toEncode3), "AQID\r\n", }, + { toEncode4, sizeof(toEncode4), + "YWJjZGVmZ2hpamxrbW5vcHFyc3R1dnd4eXowMTIzNDU2Nzg5MEFCQ0RFRkdISUpL\r\n" + "TE1OT1BRUlNUVVZXWFlaMDEyMzQ1Njc4OTBhYmNkZWZnaGlqbGttbm9wcXJzdHV2\r\n" + "d3h5ejAxMjM0NTY3ODkwQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVowMTIzNDU2\r\n" + "Nzg5MGFiY2RlZmdoaWpsa21ub3BxcnN0dXZ3eHl6MDEyMzQ1Njc4OTBBQkNERUZH\r\n" + "SElKS0xNTk9QUVJTVFVWV1hZWjAxMjM0NTY3ODkwAA==\r\n" }, +}; + +struct BinTests testsNoCR[] = { + { toEncode1, sizeof(toEncode1), "AA==\n", }, + { toEncode2, sizeof(toEncode2), "AQI=\n", }, + { toEncode3, sizeof(toEncode3), "AQID\n", }, + { toEncode4, sizeof(toEncode4), + "YWJjZGVmZ2hpamxrbW5vcHFyc3R1dnd4eXowMTIzNDU2Nzg5MEFCQ0RFRkdISUpL\n" + "TE1OT1BRUlNUVVZXWFlaMDEyMzQ1Njc4OTBhYmNkZWZnaGlqbGttbm9wcXJzdHV2\n" + "d3h5ejAxMjM0NTY3ODkwQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVowMTIzNDU2\n" + "Nzg5MGFiY2RlZmdoaWpsa21ub3BxcnN0dXZ3eHl6MDEyMzQ1Njc4OTBBQkNERUZH\n" + "SElKS0xNTk9QUVJTVFVWV1hZWjAxMjM0NTY3ODkwAA==\n" }, +}; + +static void encodeAndCompareBase64_A(const BYTE *toEncode, DWORD toEncodeLen, + DWORD format, const char *expected, const char *header, const char *trailer) +{ + DWORD strLen = 0; + LPSTR str = NULL; + BOOL ret; + + ret = pCryptBinaryToStringA(toEncode, toEncodeLen, format, NULL, &strLen); + ok(ret, "CryptBinaryToStringA failed: %ld\n", GetLastError()); + str = HeapAlloc(GetProcessHeap(), 0, strLen); + if (str) + { + DWORD strLen2 = strLen; + LPCSTR ptr = str; + + ret = pCryptBinaryToStringA(toEncode, toEncodeLen, format, str, + &strLen2); + ok(ret, "CryptBinaryToStringA failed: %ld\n", GetLastError()); + ok(strLen2 == strLen - 1, "Expected length %ld, got %ld\n", + strLen - 1, strLen); + if (header) + { + ok(!strncmp(header, ptr, strlen(header)), + "Expected header %s, got %s\n", header, ptr); + ptr += strlen(header); + } + ok(!strncmp(expected, ptr, strlen(expected)), + "Expected %s, got %s\n", expected, ptr); + ptr += strlen(expected); + if (trailer) + { + ok(!strncmp(trailer, ptr, strlen(trailer)), + "Expected trailer %s, got %s\n", trailer, ptr); + ptr += strlen(trailer); + } + HeapFree(GetProcessHeap(), 0, str); + } +} + +static void testBinaryToStringA(void) +{ + BOOL ret; + DWORD strLen = 0, i; + + ret = pCryptBinaryToStringA(NULL, 0, 0, NULL, NULL); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError()); + ret = pCryptBinaryToStringA(NULL, 0, 0, NULL, &strLen); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError()); + for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) + { + DWORD strLen = 0; + LPSTR str = NULL; + BOOL ret; + + ret = pCryptBinaryToStringA(tests[i].toEncode, tests[i].toEncodeLen, + CRYPT_STRING_BINARY, NULL, &strLen); + ok(ret, "CryptBinaryToStringA failed: %ld\n", GetLastError()); + str = HeapAlloc(GetProcessHeap(), 0, strLen); + if (str) + { + DWORD strLen2 = strLen; + + ret = pCryptBinaryToStringA(tests[i].toEncode, tests[i].toEncodeLen, + CRYPT_STRING_BINARY, str, &strLen2); + ok(strLen == strLen2, "Expected length %ld, got %ld\n", strLen, + strLen2); + ok(!memcmp(str, tests[i].toEncode, tests[i].toEncodeLen), + "Unexpected value\n"); + HeapFree(GetProcessHeap(), 0, str); + } + encodeAndCompareBase64_A(tests[i].toEncode, tests[i].toEncodeLen, + CRYPT_STRING_BASE64, tests[i].base64, NULL, NULL); + encodeAndCompareBase64_A(tests[i].toEncode, tests[i].toEncodeLen, + CRYPT_STRING_BASE64HEADER, tests[i].base64, CERT_HEADER, + CERT_TRAILER); + encodeAndCompareBase64_A(tests[i].toEncode, tests[i].toEncodeLen, + CRYPT_STRING_BASE64REQUESTHEADER, tests[i].base64, + CERT_REQUEST_HEADER, CERT_REQUEST_TRAILER); + encodeAndCompareBase64_A(tests[i].toEncode, tests[i].toEncodeLen, + CRYPT_STRING_BASE64X509CRLHEADER, tests[i].base64, X509_HEADER, + X509_TRAILER); + } + for (i = 0; i < sizeof(testsNoCR) / sizeof(testsNoCR[0]); i++) + { + DWORD strLen = 0; + LPSTR str = NULL; + BOOL ret; + + ret = pCryptBinaryToStringA(testsNoCR[i].toEncode, + testsNoCR[i].toEncodeLen, CRYPT_STRING_BINARY | CRYPT_STRING_NOCR, + NULL, &strLen); + ok(ret, "CryptBinaryToStringA failed: %ld\n", GetLastError()); + str = HeapAlloc(GetProcessHeap(), 0, strLen); + if (str) + { + DWORD strLen2 = strLen; + + ret = pCryptBinaryToStringA(testsNoCR[i].toEncode, + testsNoCR[i].toEncodeLen, CRYPT_STRING_BINARY | CRYPT_STRING_NOCR, + str, &strLen2); + ok(strLen == strLen2, "Expected length %ld, got %ld\n", strLen, + strLen2); + ok(!memcmp(str, testsNoCR[i].toEncode, testsNoCR[i].toEncodeLen), + "Unexpected value\n"); + HeapFree(GetProcessHeap(), 0, str); + } + encodeAndCompareBase64_A(testsNoCR[i].toEncode, + testsNoCR[i].toEncodeLen, CRYPT_STRING_BASE64 | CRYPT_STRING_NOCR, + testsNoCR[i].base64, NULL, NULL); + encodeAndCompareBase64_A(testsNoCR[i].toEncode, + testsNoCR[i].toEncodeLen, + CRYPT_STRING_BASE64HEADER | CRYPT_STRING_NOCR, testsNoCR[i].base64, + CERT_HEADER_NOCR, CERT_TRAILER_NOCR); + encodeAndCompareBase64_A(testsNoCR[i].toEncode, + testsNoCR[i].toEncodeLen, + CRYPT_STRING_BASE64REQUESTHEADER | CRYPT_STRING_NOCR, + testsNoCR[i].base64, CERT_REQUEST_HEADER_NOCR, + CERT_REQUEST_TRAILER_NOCR); + encodeAndCompareBase64_A(testsNoCR[i].toEncode, + testsNoCR[i].toEncodeLen, + CRYPT_STRING_BASE64X509CRLHEADER | CRYPT_STRING_NOCR, + testsNoCR[i].base64, X509_HEADER_NOCR, X509_TRAILER_NOCR); + } +} + +static void decodeAndCompareBase64_A(LPCSTR toDecode, LPCSTR header, + LPCSTR trailer, DWORD useFormat, DWORD expectedFormat, const BYTE *expected, + DWORD expectedLen) +{ + static const char garbage[] = "garbage\r\n"; + LPSTR str; + DWORD len = strlen(toDecode) + strlen(garbage) + 1; + + if (header) + len += strlen(header); + if (trailer) + len += strlen(trailer); + str = HeapAlloc(GetProcessHeap(), 0, len); + if (str) + { + LPBYTE buf; + DWORD bufLen = 0; + BOOL ret; + + if (header) + strcpy(str, header); + else + *str = 0; + strcat(str, toDecode); + if (trailer) + strcat(str, trailer); + ret = pCryptStringToBinaryA(str, 0, useFormat, NULL, &bufLen, NULL, + NULL); + ok(ret, "CryptStringToBinaryA failed: %ld\n", GetLastError()); + buf = HeapAlloc(GetProcessHeap(), 0, bufLen); + if (buf) + { + DWORD skipped, usedFormat; + + /* check as normal, make sure last two parameters are optional */ + ret = pCryptStringToBinaryA(str, 0, useFormat, buf, &bufLen, NULL, + NULL); + ok(ret, "CryptStringToBinaryA failed: %ld\n", GetLastError()); + ok(bufLen == expectedLen, + "Expected length %ld, got %ld\n", expectedLen, bufLen); + ok(!memcmp(buf, expected, bufLen), "Unexpected value\n"); + /* check last two params */ + ret = pCryptStringToBinaryA(str, 0, useFormat, buf, &bufLen, + &skipped, &usedFormat); + ok(ret, "CryptStringToBinaryA failed: %ld\n", GetLastError()); + ok(skipped == 0, "Expected skipped 0, got %ld\n", skipped); + ok(usedFormat == expectedFormat, "Expected format %ld, got %ld\n", + expectedFormat, usedFormat); + HeapFree(GetProcessHeap(), 0, buf); + } + + /* Check again, but with garbage up front */ + strcpy(str, garbage); + if (header) + strcat(str, header); + strcat(str, toDecode); + if (trailer) + strcat(str, trailer); + ret = pCryptStringToBinaryA(str, 0, useFormat, NULL, &bufLen, NULL, + NULL); + /* expect failure with no header, and success with one */ + if (header) + ok(ret, "CryptStringToBinaryA failed: %ld\n", GetLastError()); + else + ok(!ret && GetLastError() == ERROR_INVALID_DATA, + "Expected ERROR_INVALID_DATA, got %ld\n", GetLastError()); + if (ret) + { + buf = HeapAlloc(GetProcessHeap(), 0, bufLen); + if (buf) + { + DWORD skipped, usedFormat; + + ret = pCryptStringToBinaryA(str, 0, useFormat, buf, &bufLen, + &skipped, &usedFormat); + ok(skipped == strlen(garbage), + "Expected %d characters skipped, got %ld\n", strlen(garbage), + skipped); + HeapFree(GetProcessHeap(), 0, buf); + } + } + HeapFree(GetProcessHeap(), 0, str); + } +} + +struct BadString +{ + const char *str; + DWORD format; +}; + +struct BadString badStrings[] = { + { "A\r\nA\r\n=\r\n=\r\n", CRYPT_STRING_BASE64 }, + { "AA\r\n=\r\n=\r\n", CRYPT_STRING_BASE64 }, + { "AA=\r\n=\r\n", CRYPT_STRING_BASE64 }, + { "-----BEGIN X509 CRL-----\r\nAA==\r\n", CRYPT_STRING_BASE64X509CRLHEADER }, +}; + +static void testStringToBinaryA(void) +{ + BOOL ret; + DWORD bufLen = 0, i; + + ret = pCryptStringToBinaryA(NULL, 0, 0, NULL, NULL, NULL, NULL); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError()); + ret = pCryptStringToBinaryA(NULL, 0, 0, NULL, &bufLen, NULL, NULL); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError()); + /* Bogus format */ + ret = pCryptStringToBinaryA(tests[0].base64, 0, 0, NULL, &bufLen, NULL, + NULL); + ok(!ret && GetLastError() == ERROR_INVALID_DATA, + "Expected ERROR_INVALID_DATA, got %ld\n", GetLastError()); + /* Decoding doesn't expect the NOCR flag to be specified */ + ret = pCryptStringToBinaryA(tests[0].base64, 1, + CRYPT_STRING_BASE64 | CRYPT_STRING_NOCR, NULL, &bufLen, NULL, NULL); + ok(!ret && GetLastError() == ERROR_INVALID_DATA, + "Expected ERROR_INVALID_DATA, got %ld\n", GetLastError()); + /* Bad strings */ + for (i = 0; i < sizeof(badStrings) / sizeof(badStrings[0]); i++) + { + bufLen = 0; + ret = pCryptStringToBinaryA(badStrings[i].str, 0, badStrings[i].format, + NULL, &bufLen, NULL, NULL); + ok(!ret && GetLastError() == ERROR_INVALID_DATA, + "Expected ERROR_INVALID_DATA, got %ld\n", GetLastError()); + } + /* Good strings */ + for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) + { + bufLen = 0; + /* Bogus length--oddly enough, that succeeds, even though it's not + * properly padded. + */ + ret = pCryptStringToBinaryA(tests[i].base64, 1, CRYPT_STRING_BASE64, + NULL, &bufLen, NULL, NULL); + todo_wine ok(ret, "CryptStringToBinaryA failed: %ld\n", GetLastError()); + /* Check with the precise format */ + decodeAndCompareBase64_A(tests[i].base64, NULL, NULL, + CRYPT_STRING_BASE64, CRYPT_STRING_BASE64, tests[i].toEncode, + tests[i].toEncodeLen); + decodeAndCompareBase64_A(tests[i].base64, CERT_HEADER, CERT_TRAILER, + CRYPT_STRING_BASE64HEADER, CRYPT_STRING_BASE64HEADER, + tests[i].toEncode, tests[i].toEncodeLen); + decodeAndCompareBase64_A(tests[i].base64, CERT_REQUEST_HEADER, + CERT_REQUEST_TRAILER, CRYPT_STRING_BASE64REQUESTHEADER, + CRYPT_STRING_BASE64REQUESTHEADER, tests[i].toEncode, + tests[i].toEncodeLen); + decodeAndCompareBase64_A(tests[i].base64, X509_HEADER, X509_TRAILER, + CRYPT_STRING_BASE64X509CRLHEADER, CRYPT_STRING_BASE64X509CRLHEADER, + tests[i].toEncode, tests[i].toEncodeLen); + /* And check with the "any" formats */ + decodeAndCompareBase64_A(tests[i].base64, NULL, NULL, + CRYPT_STRING_BASE64_ANY, CRYPT_STRING_BASE64, tests[i].toEncode, + tests[i].toEncodeLen); + /* Don't check with no header and the string_any format, that'll + * always succeed. + */ + decodeAndCompareBase64_A(tests[i].base64, CERT_HEADER, CERT_TRAILER, + CRYPT_STRING_BASE64_ANY, CRYPT_STRING_BASE64HEADER, tests[i].toEncode, + tests[i].toEncodeLen); + decodeAndCompareBase64_A(tests[i].base64, CERT_HEADER, CERT_TRAILER, + CRYPT_STRING_ANY, CRYPT_STRING_BASE64HEADER, tests[i].toEncode, + tests[i].toEncodeLen); + /* oddly, these seem to decode using the wrong format + decodeAndCompareBase64_A(tests[i].base64, CERT_REQUEST_HEADER, + CERT_REQUEST_TRAILER, CRYPT_STRING_BASE64_ANY, + CRYPT_STRING_BASE64REQUESTHEADER, tests[i].toEncode, + tests[i].toEncodeLen); + decodeAndCompareBase64_A(tests[i].base64, CERT_REQUEST_HEADER, + CERT_REQUEST_TRAILER, CRYPT_STRING_ANY, + CRYPT_STRING_BASE64REQUESTHEADER, tests[i].toEncode, + tests[i].toEncodeLen); + decodeAndCompareBase64_A(tests[i].base64, X509_HEADER, X509_TRAILER, + CRYPT_STRING_BASE64_ANY, CRYPT_STRING_BASE64X509CRLHEADER, + tests[i].toEncode, tests[i].toEncodeLen); + decodeAndCompareBase64_A(tests[i].base64, X509_HEADER, X509_TRAILER, + CRYPT_STRING_ANY, CRYPT_STRING_BASE64X509CRLHEADER, tests[i].toEncode, + tests[i].toEncodeLen); + */ + } + /* And again, with no CR--decoding handles this automatically */ + for (i = 0; i < sizeof(testsNoCR) / sizeof(testsNoCR[0]); i++) + { + bufLen = 0; + /* Bogus length--oddly enough, that succeeds, even though it's not + * properly padded. + */ + ret = pCryptStringToBinaryA(testsNoCR[i].base64, 1, CRYPT_STRING_BASE64, + NULL, &bufLen, NULL, NULL); + todo_wine ok(ret, "CryptStringToBinaryA failed: %ld\n", GetLastError()); + /* Check with the precise format */ + decodeAndCompareBase64_A(testsNoCR[i].base64, NULL, NULL, + CRYPT_STRING_BASE64, CRYPT_STRING_BASE64, testsNoCR[i].toEncode, + testsNoCR[i].toEncodeLen); + decodeAndCompareBase64_A(testsNoCR[i].base64, CERT_HEADER, CERT_TRAILER, + CRYPT_STRING_BASE64HEADER, CRYPT_STRING_BASE64HEADER, + testsNoCR[i].toEncode, testsNoCR[i].toEncodeLen); + decodeAndCompareBase64_A(testsNoCR[i].base64, CERT_REQUEST_HEADER, + CERT_REQUEST_TRAILER, CRYPT_STRING_BASE64REQUESTHEADER, + CRYPT_STRING_BASE64REQUESTHEADER, testsNoCR[i].toEncode, + testsNoCR[i].toEncodeLen); + decodeAndCompareBase64_A(testsNoCR[i].base64, X509_HEADER, X509_TRAILER, + CRYPT_STRING_BASE64X509CRLHEADER, CRYPT_STRING_BASE64X509CRLHEADER, + testsNoCR[i].toEncode, testsNoCR[i].toEncodeLen); + /* And check with the "any" formats */ + decodeAndCompareBase64_A(testsNoCR[i].base64, NULL, NULL, + CRYPT_STRING_BASE64_ANY, CRYPT_STRING_BASE64, testsNoCR[i].toEncode, + testsNoCR[i].toEncodeLen); + /* Don't check with no header and the string_any format, that'll + * always succeed. + */ + decodeAndCompareBase64_A(testsNoCR[i].base64, CERT_HEADER, CERT_TRAILER, + CRYPT_STRING_BASE64_ANY, CRYPT_STRING_BASE64HEADER, + testsNoCR[i].toEncode, testsNoCR[i].toEncodeLen); + decodeAndCompareBase64_A(testsNoCR[i].base64, CERT_HEADER, CERT_TRAILER, + CRYPT_STRING_ANY, CRYPT_STRING_BASE64HEADER, testsNoCR[i].toEncode, + testsNoCR[i].toEncodeLen); + } +} + +START_TEST(base64) +{ + HMODULE lib = LoadLibraryA("crypt32"); + + if (lib) + { + pCryptBinaryToStringA = (CryptBinaryToStringAFunc)GetProcAddress(lib, + "CryptBinaryToStringA"); + pCryptStringToBinaryA = (CryptStringToBinaryAFunc)GetProcAddress(lib, + "CryptStringToBinaryA"); + + testBinaryToStringA(); + testStringToBinaryA(); + + FreeLibrary(lib); + } +} diff --git a/include/wincrypt.h b/include/wincrypt.h index 771ec9914eb..85dc780a28b 100644 --- a/include/wincrypt.h +++ b/include/wincrypt.h @@ -1968,6 +1968,21 @@ typedef struct _CRL_FIND_ISSUED_FOR_PARA #define CERT_STORE_CRL_CONTEXT_FLAG (1 << CERT_STORE_CRL_CONTEXT) #define CERT_STORE_CTL_CONTEXT_FLAG (1 << CERT_STORE_CTL_CONTEXT) +/* CryptBinaryToString/CryptStringToBinary flags */ +#define CRYPT_STRING_BASE64HEADER 0x00000000 +#define CRYPT_STRING_BASE64 0x00000001 +#define CRYPT_STRING_BINARY 0x00000002 +#define CRYPT_STRING_BASE64REQUESTHEADER 0x00000003 +#define CRYPT_STRING_HEX 0x00000004 +#define CRYPT_STRING_HEXASCII 0x00000005 +#define CRYPT_STRING_BASE64_ANY 0x00000006 +#define CRYPT_STRING_ANY 0x00000007 +#define CRYPT_STRING_HEX_ANY 0x00000008 +#define CRYPT_STRING_BASE64X509CRLHEADER 0x00000009 +#define CRYPT_STRING_HEXADDR 0x0000000a +#define CRYPT_STRING_HEXASCIIADDR 0x0000000b +#define CRYPT_STRING_NOCR 0x80000000 + /* OIDs */ #define szOID_RSA "1.2.840.113549" #define szOID_PKCS "1.2.840.113549.1" @@ -2540,6 +2555,20 @@ LPVOID WINAPI CryptMemAlloc(ULONG cbSize); LPVOID WINAPI CryptMemRealloc(LPVOID pv, ULONG cbSize); VOID WINAPI CryptMemFree(LPVOID pv); +BOOL WINAPI CryptBinaryToStringA(const BYTE *pbBinary, + DWORD cbBinary, DWORD dwFlags, LPSTR pszString, DWORD *pcchString); +BOOL WINAPI CryptBinaryToStringW(const BYTE *pbBinary, + DWORD cbBinary, DWORD dwFlags, LPWSTR pszString, DWORD *pcchString); +#define CryptBinaryToString WINELIB_NAME_AW(CryptBinaryToString) + +BOOL WINAPI CryptStringToBinaryA(LPCSTR pszString, + DWORD cchString, DWORD dwFlags, BYTE *pbBinary, DWORD *pcbBinary, + DWORD *pdwSkip, DWORD *pdwFlags); +BOOL WINAPI CryptStringToBinaryW(LPCWSTR pszString, + DWORD cchString, DWORD dwFlags, BYTE *pbBinary, DWORD *pcbBinary, + DWORD *pdwSkip, DWORD *pdwFlags); +#define CryptStringToBinary WINELIB_NAME_AW(CryptStringToBinary) + BOOL WINAPI CryptRegisterDefaultOIDFunction(DWORD,LPCSTR,DWORD,LPCWSTR); BOOL WINAPI CryptRegisterOIDFunction(DWORD,LPCSTR,LPCSTR,LPCWSTR,LPCSTR); BOOL WINAPI CryptGetOIDFunctionValue(DWORD dwEncodingType, LPCSTR pszFuncName,