Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=55759
-- v8: cryptowinrt: Implement ICryptographicBufferStatics::EncodeToBase64String().
From: Mohamad Al-Jaf mohamadaljaf@gmail.com
Implementation patch from Nikolay Sivov.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=55759 --- dlls/cryptowinrt/Makefile.in | 1 + dlls/cryptowinrt/main.c | 45 +++++++++++++++++++++++-- dlls/cryptowinrt/tests/crypto.c | 58 ++++++++++++++++++++++++++++++++- 3 files changed, 101 insertions(+), 3 deletions(-)
diff --git a/dlls/cryptowinrt/Makefile.in b/dlls/cryptowinrt/Makefile.in index 5101fc88bf3..95df467e763 100644 --- a/dlls/cryptowinrt/Makefile.in +++ b/dlls/cryptowinrt/Makefile.in @@ -1,5 +1,6 @@ MODULE = cryptowinrt.dll IMPORTS = combase bcrypt uuid +DELAYIMPORTS = crypt32
SOURCES = \ async.c \ diff --git a/dlls/cryptowinrt/main.c b/dlls/cryptowinrt/main.c index e6f811b5d12..fad3666acc6 100644 --- a/dlls/cryptowinrt/main.c +++ b/dlls/cryptowinrt/main.c @@ -25,9 +25,11 @@ #include "objbase.h"
#include "bcrypt.h" +#include "wincrypt.h"
#define WIDL_using_Windows_Security_Cryptography #include "windows.security.cryptography.h" +#include "robuffer.h"
WINE_DEFAULT_DEBUG_CHANNEL(crypto);
@@ -203,9 +205,48 @@ static HRESULT STDMETHODCALLTYPE cryptobuffer_statics_DecodeFromBase64String( static HRESULT STDMETHODCALLTYPE cryptobuffer_statics_EncodeToBase64String( ICryptographicBufferStatics *iface, IBuffer *buffer, HSTRING *value) { - FIXME("iface %p, buffer %p, value %p stub!\n", iface, buffer, value); + IBufferByteAccess *buffer_access; + HSTRING_BUFFER str_buffer; + void *data = NULL; + UINT32 length = 0; + DWORD ret_length; + WCHAR *str; + HRESULT hr;
- return E_NOTIMPL; + TRACE("iface %p, buffer %p, value %p.\n", iface, buffer, value); + + if (buffer) + { + IBuffer_get_Length(buffer, &length); + if (length) + { + if (SUCCEEDED(IBuffer_QueryInterface(buffer, &IID_IBufferByteAccess, (void **)&buffer_access))) + { + IBufferByteAccess_Buffer(buffer_access, (byte **)&data); + IBufferByteAccess_Release(buffer_access); + } + } + } + + if (!length) + return WindowsCreateString(NULL, 0, value); + + if (!data) + return E_FAIL; + + if (!CryptBinaryToStringW(data, length, CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF, NULL, &ret_length)) + return E_FAIL; + + if (FAILED(hr = WindowsPreallocateStringBuffer(ret_length, &str, &str_buffer))) + return hr; + + if (!CryptBinaryToStringW(data, length, CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF, str, &ret_length)) + { + WindowsDeleteStringBuffer(str_buffer); + return E_FAIL; + } + + return WindowsPromoteStringBuffer(str_buffer, value); }
static HRESULT STDMETHODCALLTYPE cryptobuffer_statics_ConvertStringToBinary( diff --git a/dlls/cryptowinrt/tests/crypto.c b/dlls/cryptowinrt/tests/crypto.c index 260287dbd23..5f92722144d 100644 --- a/dlls/cryptowinrt/tests/crypto.c +++ b/dlls/cryptowinrt/tests/crypto.c @@ -34,6 +34,7 @@ #include "windows.security.cryptography.h" #define WIDL_using_Windows_Security_Credentials #include "windows.security.credentials.h" +#include "robuffer.h"
#include "wine/test.h"
@@ -208,9 +209,16 @@ static struct bool_async_handler default_bool_async_handler = {{&bool_async_hand static void test_CryptobufferStatics(void) { static const WCHAR *cryptobuffer_statics_name = L"Windows.Security.Cryptography.CryptographicBuffer"; + static const WCHAR *buffer_name = L"Windows.Storage.Streams.Buffer"; ICryptographicBufferStatics *cryptobuffer_statics; - IActivationFactory *factory; + IActivationFactory *factory, *factory2; + IBufferByteAccess *buffer_access; + IBufferFactory *buffer_factory; + const WCHAR *base64_str; + IBuffer *buffer; HSTRING str; + byte *data; + UINT32 len; HRESULT hr; LONG ref;
@@ -233,6 +241,54 @@ static void test_CryptobufferStatics(void) hr = IActivationFactory_QueryInterface( factory, &IID_ICryptographicBufferStatics, (void **)&cryptobuffer_statics ); ok( hr == S_OK, "got hr %#lx.\n", hr );
+ /* NULL buffer */ + hr = ICryptographicBufferStatics_EncodeToBase64String( cryptobuffer_statics, NULL, &str ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + base64_str = WindowsGetStringRawBuffer( str, &len ); + ok( !wcscmp( L"", base64_str ) && !len, "got str %s, len %d.\n", wine_dbgstr_w( base64_str ), len ); + WindowsDeleteString( str ); + + hr = WindowsCreateString( buffer_name, wcslen( buffer_name ), &str ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + hr = RoGetActivationFactory( str, &IID_IActivationFactory, (void **)&factory2 ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + hr = IActivationFactory_QueryInterface( factory2, &IID_IBufferFactory, (void **)&buffer_factory ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + WindowsDeleteString( str ); + + /* Empty buffer */ + hr = IBufferFactory_Create( buffer_factory, 0, &buffer ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + hr = ICryptographicBufferStatics_EncodeToBase64String( cryptobuffer_statics, buffer, &str ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + base64_str = WindowsGetStringRawBuffer( str, &len ); + ok( !wcscmp( L"", base64_str ) && !len, "got str %s, len %d.\n", wine_dbgstr_w( base64_str ), len ); + WindowsDeleteString( str ); + IBuffer_Release( buffer ); + + /* Test with contents */ + hr = IBufferFactory_Create( buffer_factory, 16, &buffer ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + hr = IBuffer_QueryInterface( buffer, &IID_IBufferByteAccess, (void **)&buffer_access ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + hr = IBufferByteAccess_Buffer( buffer_access, &data ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + for (int i = 0; i < 16; ++i) + data[i] = i; + hr = IBuffer_put_Length( buffer, 16 ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + IBufferByteAccess_Release( buffer_access ); + + hr = ICryptographicBufferStatics_EncodeToBase64String( cryptobuffer_statics, buffer, &str ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + base64_str = WindowsGetStringRawBuffer( str, &len ); + ok( !wcscmp( L"AAECAwQFBgcICQoLDA0ODw==", base64_str ), "got str %s, len %d.\n", wine_dbgstr_w( base64_str ), len ); + WindowsDeleteString( str ); + IBuffer_Release( buffer ); + + IBufferFactory_Release( buffer_factory ); + IActivationFactory_Release( factory2 ); + ref = ICryptographicBufferStatics_Release( cryptobuffer_statics ); ok( ref == 2, "got ref %ld.\n", ref ); ref = IActivationFactory_Release( factory );
On Sun Aug 3 06:30:41 2025 +0000, Nikolay Sivov wrote:
You don't need to check for null buffer, length check is enough.
Yeah, that was redundant.
On Sun Aug 3 06:31:35 2025 +0000, Nikolay Sivov wrote:
This is short enough and seems to work. Please squash everything together. [0001-.txt](/uploads/1cb55a388c51f5bb00bbae1e8a11067f/0001-.txt)
Thanks, looks good, just missing an `IBuffer_Release( buffer )`. I've squashed the commits together and added your name in the description. FWIW, I thought the Wine policy was to implement functions only if an application needs them.
This merge request was approved by Nikolay Sivov.