Skip to content

Commit b9b9498

Browse files
committed
Updating WinRT to encrypt passwords.
1 parent 2ffb651 commit b9b9498

File tree

3 files changed

+88
-26
lines changed

3 files changed

+88
-26
lines changed

Release/include/cpprest/web_utilities.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,14 +49,16 @@ class zero_memory_deleter
4949
public:
5050
_ASYNCRTIMP void operator()(::utility::string_t *data) const;
5151
};
52-
typedef std::unique_ptr<std::wstring, zero_memory_deleter> password_string;
52+
typedef std::unique_ptr<std::wstring, zero_memory_deleter> plaintext_string;
5353
#if defined(__cplusplus_winrt)
5454
class winrt_encryption
5555
{
5656
public:
5757
winrt_encryption() {}
5858
_ASYNCRTIMP winrt_encryption(const std::wstring &data);
59-
_ASYNCRTIMP password_string decrypt() const;
59+
_ASYNCRTIMP plaintext_string decrypt() const;
60+
private:
61+
::pplx::task<Windows::Storage::Streams::IBuffer ^> m_buffer;
6062
};
6163
#else
6264
class win32_encryption
@@ -65,7 +67,7 @@ class win32_encryption
6567
win32_encryption() {}
6668
_ASYNCRTIMP win32_encryption(const std::wstring &data);
6769
_ASYNCRTIMP ~win32_encryption();
68-
_ASYNCRTIMP password_string decrypt() const;
70+
_ASYNCRTIMP plaintext_string decrypt() const;
6971
private:
7072
std::vector<char> m_buffer;
7173
size_t m_numCharacters;
@@ -128,7 +130,7 @@ class credentials
128130
friend class experimental::websockets::client::details::winrt_client;
129131

130132
#if defined(_MS_WINDOWS)
131-
details::password_string decrypt() const
133+
details::plaintext_string decrypt() const
132134
{
133135
return m_password.decrypt();
134136
}

Release/src/http/client/http_win8.cpp

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -395,30 +395,34 @@ class winrt_client : public _http_client_communicator
395395
return;
396396
}
397397

398-
// New scope to ensure plaintext password is cleared as soon as possible.
398+
// New scope to ensure plain text password is cleared as soon as possible.
399399
{
400400
utility::string_t username, proxy_username;
401-
::web::details::password_string password, proxy_password;
401+
const utility::char_t *password = nullptr;
402+
const utility::char_t *proxy_password = nullptr;
403+
::web::details::plaintext_string password_plaintext, proxy_password_plaintext;
402404

403405
if (client_cred.is_set())
404406
{
405407
username = client_cred.username();
406-
password = client_cred.decrypt();
408+
password_plaintext = client_cred.decrypt();
409+
password = password_plaintext->c_str();
407410
}
408411
if (proxy_cred.is_set())
409412
{
410413
proxy_username = proxy_cred.username();
411-
proxy_password = proxy_cred.decrypt();
414+
proxy_password_plaintext = proxy_cred.decrypt();
415+
proxy_password = proxy_password_plaintext->c_str();
412416
}
413417

414418
hr = winrt_context->m_hRequest->Open(
415419
msg.method().c_str(),
416420
encoded_resource.c_str(),
417421
Make<HttpRequestCallback>(winrt_context).Get(),
418422
username.c_str(),
419-
password->c_str(),
423+
password,
420424
proxy_username.c_str(),
421-
proxy_password->c_str());
425+
proxy_password);
422426
}
423427
if (FAILED(hr))
424428
{

Release/src/utilities/web_utilities.cpp

Lines changed: 72 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -29,33 +29,76 @@
2929
#include <Wincrypt.h>
3030
#endif
3131

32+
#if defined(__cplusplus_winrt)
33+
#include <robuffer.h>
34+
#endif
35+
3236
#include "cpprest\web_utilities.h"
3337

3438
namespace web
3539
{
3640
namespace details
3741
{
3842
#if defined(_MS_WINDOWS)
39-
void zero_memory_deleter::operator()(::utility::string_t *data) const
40-
{
4143
#if defined(__cplusplus_winrt)
42-
SecureZeroMemory(reinterpret_cast<void *>(const_cast<::utility::string_t::value_type *>(data->data())), data->size());
43-
#else
44-
// TODO
45-
#endif
46-
delete data;
44+
45+
// Helper function since SecureZeroMemory isn't available.
46+
void winrt_secure_zero_memory(_Out_writes_(count) void *buffer, _In_ size_t count)
47+
{
48+
auto vptr = reinterpret_cast<volatile char *>(buffer);
49+
while (count != 0)
50+
{
51+
*vptr = 0;
52+
++vptr;
53+
--count;
54+
}
55+
}
56+
void winrt_secure_zero_buffer(Windows::Storage::Streams::IBuffer ^buffer)
57+
{
58+
Microsoft::WRL::ComPtr<IInspectable> bufferInspectable(reinterpret_cast<IInspectable *>(buffer));
59+
Microsoft::WRL::ComPtr<Windows::Storage::Streams::IBufferByteAccess> bufferByteAccess;
60+
bufferInspectable.As(&bufferByteAccess);
61+
byte * rawBytes;
62+
bufferByteAccess->Buffer(&rawBytes);
63+
winrt_secure_zero_memory(rawBytes, buffer->Length);
4764
}
4865

49-
#if defined(__cplusplus_winrt)
5066
winrt_encryption::winrt_encryption(const std::wstring &data)
5167
{
52-
// TODO
68+
auto provider = ref new Windows::Security::Cryptography::DataProtection::DataProtectionProvider(ref new Platform::String(L"Local=user"));
69+
70+
// Create buffer containing plain text password.
71+
Platform::ArrayReference<unsigned char> arrayref(
72+
reinterpret_cast<unsigned char *>(const_cast<std::wstring::value_type *>(data.c_str())),
73+
data.size() * sizeof(std::wstring::value_type));
74+
Windows::Storage::Streams::IBuffer ^plaintext = Windows::Security::Cryptography::CryptographicBuffer::CreateFromByteArray(arrayref);
75+
m_buffer = pplx::create_task(provider->ProtectAsync(plaintext));
76+
m_buffer.then([plaintext](pplx::task<Windows::Storage::Streams::IBuffer ^>)
77+
{
78+
winrt_secure_zero_buffer(plaintext);
79+
});
5380
}
5481

55-
password_string winrt_encryption::decrypt() const
82+
plaintext_string winrt_encryption::decrypt() const
5683
{
57-
auto data = password_string(new std::wstring());
58-
// TODO
84+
// To fully guarantee asynchrony would require significant impact on existing code. This code path
85+
// is never run on a user's thread and is only done once when setting up a connection.
86+
auto encrypted = m_buffer.get();
87+
auto provider = ref new Windows::Security::Cryptography::DataProtection::DataProtectionProvider();
88+
auto plaintext = pplx::create_task(provider->UnprotectAsync(encrypted)).get();
89+
90+
// Get access to raw bytes in plain text buffer.
91+
Microsoft::WRL::ComPtr<IInspectable> bufferInspectable(reinterpret_cast<IInspectable *>(plaintext));
92+
Microsoft::WRL::ComPtr<Windows::Storage::Streams::IBufferByteAccess> bufferByteAccess;
93+
bufferInspectable.As(&bufferByteAccess);
94+
byte * rawPlaintext;
95+
bufferByteAccess->Buffer(&rawPlaintext);
96+
97+
// Construct string and zero out memory from plain text buffer.
98+
auto data = plaintext_string(new std::wstring(
99+
reinterpret_cast<const std::wstring::value_type *>(rawPlaintext),
100+
plaintext->Length / 2));
101+
winrt_secure_zero_memory(rawPlaintext, plaintext->Length);
59102
return std::move(data);
60103
}
61104
#else
@@ -72,7 +115,7 @@ win32_encryption::win32_encryption(const std::wstring &data) :
72115
{
73116
m_buffer.resize(m_buffer.size() + CRYPTPROTECTMEMORY_BLOCK_SIZE - mod);
74117
}
75-
if (!CryptProtectMemory(reinterpret_cast<void *>(m_buffer.data()), m_buffer.size(), CRYPTPROTECTMEMORY_SAME_PROCESS))
118+
if (!CryptProtectMemory(m_buffer.data(), m_buffer.size(), CRYPTPROTECTMEMORY_SAME_PROCESS))
76119
{
77120
throw ::utility::details::create_system_error(GetLastError());
78121
}
@@ -83,12 +126,12 @@ win32_encryption::~win32_encryption()
83126
SecureZeroMemory(m_buffer.data(), m_buffer.size());
84127
}
85128

86-
password_string win32_encryption::decrypt() const
129+
plaintext_string win32_encryption::decrypt() const
87130
{
88131
// Copy the buffer and decrypt to avoid having to re-encrypt.
89-
auto data = password_string(new std::wstring(reinterpret_cast<const std::wstring::value_type *>(m_buffer.data()), m_buffer.size() / 2));
132+
auto data = plaintext_string(new std::wstring(reinterpret_cast<const std::wstring::value_type *>(m_buffer.data()), m_buffer.size() / 2));
90133
if (!CryptUnprotectMemory(
91-
reinterpret_cast<void *>(const_cast<std::wstring::value_type *>(data->c_str())),
134+
const_cast<std::wstring::value_type *>(data->c_str()),
92135
m_buffer.size(),
93136
CRYPTPROTECTMEMORY_SAME_PROCESS))
94137
{
@@ -98,6 +141,19 @@ password_string win32_encryption::decrypt() const
98141
return std::move(data);
99142
}
100143
#endif
144+
145+
void zero_memory_deleter::operator()(::utility::string_t *data) const
146+
{
147+
#if defined(__cplusplus_winrt)
148+
winrt_secure_zero_memory(
149+
#else
150+
SecureZeroMemory(
151+
#endif
152+
const_cast<::utility::string_t::value_type *>(data->data()),
153+
data->size() * sizeof(::utility::string_t::value_type));
154+
delete data;
155+
}
156+
101157
#endif
102158
}
103159

0 commit comments

Comments
 (0)