12
12
****/
13
13
14
14
#include " stdafx.h"
15
+ #include < assert.h>
15
16
16
17
#if defined(_WIN32) && !defined(__cplusplus_winrt)
17
18
#include < Wincrypt.h>
@@ -92,23 +93,28 @@ plaintext_string winrt_encryption::decrypt() const
92
93
win32_encryption::win32_encryption (const std::wstring &data) :
93
94
m_numCharacters(data.size())
94
95
{
95
- // Early return because CryptProtectMemory crashs with empty string
96
+ // Early return because CryptProtectMemory crashes with empty string
96
97
if (m_numCharacters == 0 )
97
98
{
98
99
return ;
99
100
}
100
101
101
- const auto dataNumBytes = data.size () * sizeof (std::wstring::value_type);
102
- m_buffer.resize (dataNumBytes);
103
- memcpy_s (m_buffer.data (), m_buffer.size (), data.c_str (), dataNumBytes);
104
-
105
- // Buffer must be a multiple of CRYPTPROTECTMEMORY_BLOCK_SIZE
106
- const auto mod = m_buffer.size () % CRYPTPROTECTMEMORY_BLOCK_SIZE;
107
- if (mod != 0 )
102
+ if (data.size () > (std::numeric_limits<DWORD>::max)() / sizeof (wchar_t ))
108
103
{
109
- m_buffer. resize (m_buffer. size () + CRYPTPROTECTMEMORY_BLOCK_SIZE - mod );
104
+ throw std::length_error ( " Encryption string too long " );
110
105
}
111
- if (!CryptProtectMemory (m_buffer.data (), static_cast <DWORD>(m_buffer.size ()), CRYPTPROTECTMEMORY_SAME_PROCESS))
106
+
107
+ const auto dataSizeDword = static_cast <DWORD>(data.size () * sizeof (wchar_t ));
108
+
109
+ // Round up dataSizeDword to be a multiple of CRYPTPROTECTMEMORY_BLOCK_SIZE
110
+ static_assert (CRYPTPROTECTMEMORY_BLOCK_SIZE == 16 , " Power of 2 assumptions in this bit masking violated" );
111
+ const auto mask = static_cast <DWORD>(CRYPTPROTECTMEMORY_BLOCK_SIZE - 1u );
112
+ const auto dataNumBytes = (dataSizeDword & ~mask) + ((dataSizeDword & mask) != 0 ) * CRYPTPROTECTMEMORY_BLOCK_SIZE;
113
+ assert ((dataNumBytes % CRYPTPROTECTMEMORY_BLOCK_SIZE) == 0 );
114
+ assert (dataNumBytes >= dataSizeDword);
115
+ m_buffer.resize (dataNumBytes);
116
+ memcpy_s (m_buffer.data (), m_buffer.size (), data.c_str (), dataNumBytes);
117
+ if (!CryptProtectMemory (m_buffer.data (), dataNumBytes, CRYPTPROTECTMEMORY_SAME_PROCESS))
112
118
{
113
119
throw ::utility::details::create_system_error (GetLastError ());
114
120
}
@@ -121,20 +127,25 @@ win32_encryption::~win32_encryption()
121
127
122
128
plaintext_string win32_encryption::decrypt () const
123
129
{
124
- if (m_buffer.empty ())
125
- return plaintext_string (new std::wstring ());
126
-
127
130
// Copy the buffer and decrypt to avoid having to re-encrypt.
128
- auto data = plaintext_string (new std::wstring (reinterpret_cast <const std::wstring::value_type *>(m_buffer.data ()), m_buffer.size () / 2 ));
129
- if (!CryptUnprotectMemory (
130
- const_cast <std::wstring::value_type *>(data->c_str ()),
131
- static_cast <DWORD>(m_buffer.size ()),
132
- CRYPTPROTECTMEMORY_SAME_PROCESS))
133
- {
134
- throw ::utility::details::create_system_error (GetLastError ());
131
+ auto result = plaintext_string (new std::wstring (
132
+ reinterpret_cast <const std::wstring::value_type *>(m_buffer.data ()), m_buffer.size () / sizeof (wchar_t )));
133
+ auto & data = *result;
134
+ if (!m_buffer.empty ()) {
135
+ if (!CryptUnprotectMemory (
136
+ &data[0 ],
137
+ static_cast <DWORD>(m_buffer.size ()),
138
+ CRYPTPROTECTMEMORY_SAME_PROCESS))
139
+ {
140
+ throw ::utility::details::create_system_error (GetLastError ());
141
+ }
142
+
143
+ assert (m_numCharacters <= m_buffer.size ());
144
+ SecureZeroMemory (&data[m_numCharacters], data.size () - m_numCharacters);
145
+ data.erase (m_numCharacters);
135
146
}
136
- data-> resize (m_numCharacters);
137
- return std::move (data) ;
147
+
148
+ return result ;
138
149
}
139
150
#endif
140
151
#endif
@@ -143,12 +154,10 @@ void zero_memory_deleter::operator()(::utility::string_t *data) const
143
154
{
144
155
CASABLANCA_UNREFERENCED_PARAMETER (data);
145
156
#if defined(_WIN32)
146
- SecureZeroMemory (
147
- const_cast <::utility::string_t ::value_type *>(data->data ()),
148
- data->size () * sizeof (::utility::string_t ::value_type));
157
+ SecureZeroMemory (&(*data)[0 ], data->size () * sizeof (::utility::string_t ::value_type));
149
158
delete data;
150
159
#endif
151
160
}
152
161
}
153
162
154
- }
163
+ }
0 commit comments