aboutsummaryrefslogtreecommitdiff
path: root/src/libs/dutil/WixToolset.DUtil/cryputil.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/dutil/WixToolset.DUtil/cryputil.cpp')
-rw-r--r--src/libs/dutil/WixToolset.DUtil/cryputil.cpp404
1 files changed, 404 insertions, 0 deletions
diff --git a/src/libs/dutil/WixToolset.DUtil/cryputil.cpp b/src/libs/dutil/WixToolset.DUtil/cryputil.cpp
new file mode 100644
index 00000000..24bb83f1
--- /dev/null
+++ b/src/libs/dutil/WixToolset.DUtil/cryputil.cpp
@@ -0,0 +1,404 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3#include "precomp.h"
4
5
6// Exit macros
7#define CrypExitOnLastError(x, s, ...) ExitOnLastErrorSource(DUTIL_SOURCE_CRYPUTIL, x, s, __VA_ARGS__)
8#define CrypExitOnLastErrorDebugTrace(x, s, ...) ExitOnLastErrorDebugTraceSource(DUTIL_SOURCE_CRYPUTIL, x, s, __VA_ARGS__)
9#define CrypExitWithLastError(x, s, ...) ExitWithLastErrorSource(DUTIL_SOURCE_CRYPUTIL, x, s, __VA_ARGS__)
10#define CrypExitOnFailure(x, s, ...) ExitOnFailureSource(DUTIL_SOURCE_CRYPUTIL, x, s, __VA_ARGS__)
11#define CrypExitOnRootFailure(x, s, ...) ExitOnRootFailureSource(DUTIL_SOURCE_CRYPUTIL, x, s, __VA_ARGS__)
12#define CrypExitOnFailureDebugTrace(x, s, ...) ExitOnFailureDebugTraceSource(DUTIL_SOURCE_CRYPUTIL, x, s, __VA_ARGS__)
13#define CrypExitOnNull(p, x, e, s, ...) ExitOnNullSource(DUTIL_SOURCE_CRYPUTIL, p, x, e, s, __VA_ARGS__)
14#define CrypExitOnNullWithLastError(p, x, s, ...) ExitOnNullWithLastErrorSource(DUTIL_SOURCE_CRYPUTIL, p, x, s, __VA_ARGS__)
15#define CrypExitOnNullDebugTrace(p, x, e, s, ...) ExitOnNullDebugTraceSource(DUTIL_SOURCE_CRYPUTIL, p, x, e, s, __VA_ARGS__)
16#define CrypExitOnInvalidHandleWithLastError(p, x, s, ...) ExitOnInvalidHandleWithLastErrorSource(DUTIL_SOURCE_CRYPUTIL, p, x, s, __VA_ARGS__)
17#define CrypExitOnWin32Error(e, x, s, ...) ExitOnWin32ErrorSource(DUTIL_SOURCE_CRYPUTIL, e, x, s, __VA_ARGS__)
18#define CrypExitOnGdipFailure(g, x, s, ...) ExitOnGdipFailureSource(DUTIL_SOURCE_CRYPUTIL, g, x, s, __VA_ARGS__)
19
20static PFN_RTLENCRYPTMEMORY vpfnRtlEncryptMemory = NULL;
21static PFN_RTLDECRYPTMEMORY vpfnRtlDecryptMemory = NULL;
22static PFN_CRYPTPROTECTMEMORY vpfnCryptProtectMemory = NULL;
23static PFN_CRYPTUNPROTECTMEMORY vpfnCryptUnprotectMemory = NULL;
24
25static HMODULE vhAdvApi32Dll = NULL;
26static HMODULE vhCrypt32Dll = NULL;
27static BOOL vfCrypInitialized = FALSE;
28
29// function definitions
30
31/********************************************************************
32 CrypInitialize - initializes cryputil
33
34*********************************************************************/
35extern "C" HRESULT DAPI CrypInitialize(
36 )
37{
38 HRESULT hr = S_OK;
39
40 hr = LoadSystemLibrary(L"AdvApi32.dll", &vhAdvApi32Dll);
41 if (SUCCEEDED(hr))
42 {
43 // Ignore failures - if these don't exist, we'll try the Crypt methods.
44 vpfnRtlEncryptMemory = reinterpret_cast<PFN_RTLENCRYPTMEMORY>(::GetProcAddress(vhAdvApi32Dll, "SystemFunction040"));
45 vpfnRtlDecryptMemory = reinterpret_cast<PFN_RTLDECRYPTMEMORY>(::GetProcAddress(vhAdvApi32Dll, "SystemFunction041"));
46 }
47 if (!vpfnRtlEncryptMemory || !vpfnRtlDecryptMemory)
48 {
49 hr = LoadSystemLibrary(L"Crypt32.dll", &vhCrypt32Dll);
50 CrypExitOnFailure(hr, "Failed to load Crypt32.dll");
51
52 vpfnCryptProtectMemory = reinterpret_cast<PFN_CRYPTPROTECTMEMORY>(::GetProcAddress(vhCrypt32Dll, "CryptProtectMemory"));
53 if (!vpfnRtlEncryptMemory && !vpfnCryptProtectMemory)
54 {
55 CrypExitWithLastError(hr, "Failed to load an encryption method");
56 }
57 vpfnCryptUnprotectMemory = reinterpret_cast<PFN_CRYPTUNPROTECTMEMORY>(::GetProcAddress(vhCrypt32Dll, "CryptUnprotectMemory"));
58 if (!vpfnRtlDecryptMemory && !vpfnCryptUnprotectMemory)
59 {
60 CrypExitWithLastError(hr, "Failed to load a decryption method");
61 }
62 }
63
64 vfCrypInitialized = TRUE;
65
66LExit:
67 return hr;
68}
69
70
71/********************************************************************
72 CrypUninitialize - uninitializes cryputil
73
74*********************************************************************/
75extern "C" void DAPI CrypUninitialize(
76 )
77{
78 if (vhAdvApi32Dll)
79 {
80 ::FreeLibrary(vhAdvApi32Dll);
81 vhAdvApi32Dll = NULL;
82 vpfnRtlEncryptMemory = NULL;
83 vpfnRtlDecryptMemory = NULL;
84 }
85
86 if (vhCrypt32Dll)
87 {
88 ::FreeLibrary(vhCrypt32Dll);
89 vhCrypt32Dll = NULL;
90 vpfnCryptProtectMemory = NULL;
91 vpfnCryptUnprotectMemory = NULL;
92 }
93
94 vfCrypInitialized = FALSE;
95}
96
97extern "C" HRESULT DAPI CrypDecodeObject(
98 __in_z LPCSTR szStructType,
99 __in_ecount(cbData) const BYTE* pbData,
100 __in DWORD cbData,
101 __in DWORD dwFlags,
102 __out LPVOID* ppvObject,
103 __out_opt DWORD* pcbObject
104 )
105{
106 HRESULT hr = S_OK;
107 LPVOID pvObject = NULL;
108 DWORD cbObject = 0;
109
110 if (!::CryptDecodeObject(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, szStructType, pbData, cbData, dwFlags, NULL, &cbObject))
111 {
112 CrypExitWithLastError(hr, "Failed to decode object to determine size.");
113 }
114
115 pvObject = MemAlloc(cbObject, TRUE);
116 CrypExitOnNull(pvObject, hr, E_OUTOFMEMORY, "Failed to allocate memory for decoded object.");
117
118 if (!::CryptDecodeObject(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, szStructType, pbData, cbData, dwFlags, pvObject, &cbObject))
119 {
120 CrypExitWithLastError(hr, "Failed to decode object.");
121 }
122
123 *ppvObject = pvObject;
124 pvObject = NULL;
125
126 if (pcbObject)
127 {
128 *pcbObject = cbObject;
129 }
130
131LExit:
132 ReleaseMem(pvObject);
133
134 return hr;
135}
136
137
138extern "C" HRESULT DAPI CrypMsgGetParam(
139 __in HCRYPTMSG hCryptMsg,
140 __in DWORD dwType,
141 __in DWORD dwIndex,
142 __out LPVOID* ppvData,
143 __out_opt DWORD* pcbData
144 )
145{
146 HRESULT hr = S_OK;
147 LPVOID pv = NULL;
148 DWORD cb = 0;
149
150 if (!::CryptMsgGetParam(hCryptMsg, dwType, dwIndex, NULL, &cb))
151 {
152 CrypExitWithLastError(hr, "Failed to get crypt message parameter data size.");
153 }
154
155 pv = MemAlloc(cb, TRUE);
156 CrypExitOnNull(pv, hr, E_OUTOFMEMORY, "Failed to allocate memory for crypt message parameter.");
157
158 if (!::CryptMsgGetParam(hCryptMsg, dwType, dwIndex, pv, &cb))
159 {
160 CrypExitWithLastError(hr, "Failed to get crypt message parameter.");
161 }
162
163 *ppvData = pv;
164 pv = NULL;
165
166 if (pcbData)
167 {
168 *pcbData = cb;
169 }
170
171LExit:
172 ReleaseMem(pv);
173
174 return hr;
175}
176
177
178extern "C" HRESULT DAPI CrypHashFile(
179 __in_z LPCWSTR wzFilePath,
180 __in DWORD dwProvType,
181 __in ALG_ID algid,
182 __out_bcount(cbHash) BYTE* pbHash,
183 __in DWORD cbHash,
184 __out_opt DWORD64* pqwBytesHashed
185 )
186{
187 HRESULT hr = S_OK;
188 HANDLE hFile = INVALID_HANDLE_VALUE;
189
190 // open input file
191 hFile = ::CreateFileW(wzFilePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
192 if (INVALID_HANDLE_VALUE == hFile)
193 {
194 CrypExitWithLastError(hr, "Failed to open input file.");
195 }
196
197 hr = CrypHashFileHandle(hFile, dwProvType, algid, pbHash, cbHash, pqwBytesHashed);
198 CrypExitOnFailure(hr, "Failed to hash file: %ls", wzFilePath);
199
200LExit:
201 ReleaseFileHandle(hFile);
202
203 return hr;
204}
205
206
207extern "C" HRESULT DAPI CrypHashFileHandle(
208 __in HANDLE hFile,
209 __in DWORD dwProvType,
210 __in ALG_ID algid,
211 __out_bcount(cbHash) BYTE* pbHash,
212 __in DWORD cbHash,
213 __out_opt DWORD64* pqwBytesHashed
214 )
215{
216 HRESULT hr = S_OK;
217 HCRYPTPROV hProv = NULL;
218 HCRYPTHASH hHash = NULL;
219 DWORD cbRead = 0;
220 BYTE rgbBuffer[4096] = { };
221 const LARGE_INTEGER liZero = { };
222
223 // get handle to the crypto provider
224 if (!::CryptAcquireContextW(&hProv, NULL, NULL, dwProvType, CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
225 {
226 CrypExitWithLastError(hr, "Failed to acquire crypto context.");
227 }
228
229 // initiate hash
230 if (!::CryptCreateHash(hProv, algid, 0, 0, &hHash))
231 {
232 CrypExitWithLastError(hr, "Failed to initiate hash.");
233 }
234
235 for (;;)
236 {
237 // read data block
238 if (!::ReadFile(hFile, rgbBuffer, sizeof(rgbBuffer), &cbRead, NULL))
239 {
240 CrypExitWithLastError(hr, "Failed to read data block.");
241 }
242
243 if (!cbRead)
244 {
245 break; // end of file
246 }
247
248 // hash data block
249 if (!::CryptHashData(hHash, rgbBuffer, cbRead, 0))
250 {
251 CrypExitWithLastError(hr, "Failed to hash data block.");
252 }
253 }
254
255 // get hash value
256 if (!::CryptGetHashParam(hHash, HP_HASHVAL, pbHash, &cbHash, 0))
257 {
258 CrypExitWithLastError(hr, "Failed to get hash value.");
259 }
260
261 if (pqwBytesHashed)
262 {
263 if (!::SetFilePointerEx(hFile, liZero, (LARGE_INTEGER*)pqwBytesHashed, FILE_CURRENT))
264 {
265 CrypExitWithLastError(hr, "Failed to get file pointer.");
266 }
267 }
268
269LExit:
270 if (hHash)
271 {
272 ::CryptDestroyHash(hHash);
273 }
274 if (hProv)
275 {
276 ::CryptReleaseContext(hProv, 0);
277 }
278
279 return hr;
280}
281
282HRESULT DAPI CrypHashBuffer(
283 __in_bcount(cbBuffer) const BYTE* pbBuffer,
284 __in SIZE_T cbBuffer,
285 __in DWORD dwProvType,
286 __in ALG_ID algid,
287 __out_bcount(cbHash) BYTE* pbHash,
288 __in DWORD cbHash
289 )
290{
291 HRESULT hr = S_OK;
292 HCRYPTPROV hProv = NULL;
293 HCRYPTHASH hHash = NULL;
294 DWORD cbDataHashed = 0;
295 SIZE_T cbTotal = 0;
296 SIZE_T cbRemaining = 0;
297
298 // get handle to the crypto provider
299 if (!::CryptAcquireContextW(&hProv, NULL, NULL, dwProvType, CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
300 {
301 CrypExitWithLastError(hr, "Failed to acquire crypto context.");
302 }
303
304 // initiate hash
305 if (!::CryptCreateHash(hProv, algid, 0, 0, &hHash))
306 {
307 CrypExitWithLastError(hr, "Failed to initiate hash.");
308 }
309
310 do
311 {
312 cbRemaining = cbBuffer - cbTotal;
313 cbDataHashed = (DWORD)min(DWORD_MAX, cbRemaining);
314 if (!::CryptHashData(hHash, pbBuffer + cbTotal, cbDataHashed, 0))
315 {
316 CrypExitWithLastError(hr, "Failed to hash data.");
317 }
318
319 cbTotal += cbDataHashed;
320 } while (cbTotal < cbBuffer);
321
322 // get hash value
323 if (!::CryptGetHashParam(hHash, HP_HASHVAL, pbHash, &cbHash, 0))
324 {
325 CrypExitWithLastError(hr, "Failed to get hash value.");
326 }
327
328LExit:
329 if (hHash)
330 {
331 ::CryptDestroyHash(hHash);
332 }
333 if (hProv)
334 {
335 ::CryptReleaseContext(hProv, 0);
336 }
337
338 return hr;
339}
340
341HRESULT DAPI CrypEncryptMemory(
342 __inout LPVOID pData,
343 __in DWORD cbData,
344 __in DWORD dwFlags
345 )
346{
347 HRESULT hr = E_FAIL;
348
349 if (0 != cbData % CRYP_ENCRYPT_MEMORY_SIZE)
350 {
351 hr = E_INVALIDARG;
352 }
353 else if (vpfnRtlEncryptMemory)
354 {
355 hr = static_cast<HRESULT>(vpfnRtlEncryptMemory(pData, cbData, dwFlags));
356 }
357 else if (vpfnCryptProtectMemory)
358 {
359 if (vpfnCryptProtectMemory(pData, cbData, dwFlags))
360 {
361 hr = S_OK;
362 }
363 else
364 {
365 hr = HRESULT_FROM_WIN32(::GetLastError());
366 }
367 }
368 CrypExitOnFailure(hr, "Failed to encrypt memory");
369LExit:
370 return hr;
371}
372
373HRESULT DAPI CrypDecryptMemory(
374 __inout LPVOID pData,
375 __in DWORD cbData,
376 __in DWORD dwFlags
377 )
378{
379 HRESULT hr = E_FAIL;
380
381 if (0 != cbData % CRYP_ENCRYPT_MEMORY_SIZE)
382 {
383 hr = E_INVALIDARG;
384 }
385 else if (vpfnRtlDecryptMemory)
386 {
387 hr = static_cast<HRESULT>(vpfnRtlDecryptMemory(pData, cbData, dwFlags));
388 }
389 else if (vpfnCryptUnprotectMemory)
390 {
391 if (vpfnCryptUnprotectMemory(pData, cbData, dwFlags))
392 {
393 hr = S_OK;
394 }
395 else
396 {
397 hr = HRESULT_FROM_WIN32(::GetLastError());
398 }
399 }
400 CrypExitOnFailure(hr, "Failed to decrypt memory");
401LExit:
402 return hr;
403}
404