diff options
Diffstat (limited to 'src/libs/dutil/WixToolset.DUtil/cryputil.cpp')
-rw-r--r-- | src/libs/dutil/WixToolset.DUtil/cryputil.cpp | 404 |
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 | |||
20 | static PFN_RTLENCRYPTMEMORY vpfnRtlEncryptMemory = NULL; | ||
21 | static PFN_RTLDECRYPTMEMORY vpfnRtlDecryptMemory = NULL; | ||
22 | static PFN_CRYPTPROTECTMEMORY vpfnCryptProtectMemory = NULL; | ||
23 | static PFN_CRYPTUNPROTECTMEMORY vpfnCryptUnprotectMemory = NULL; | ||
24 | |||
25 | static HMODULE vhAdvApi32Dll = NULL; | ||
26 | static HMODULE vhCrypt32Dll = NULL; | ||
27 | static BOOL vfCrypInitialized = FALSE; | ||
28 | |||
29 | // function definitions | ||
30 | |||
31 | /******************************************************************** | ||
32 | CrypInitialize - initializes cryputil | ||
33 | |||
34 | *********************************************************************/ | ||
35 | extern "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 | |||
66 | LExit: | ||
67 | return hr; | ||
68 | } | ||
69 | |||
70 | |||
71 | /******************************************************************** | ||
72 | CrypUninitialize - uninitializes cryputil | ||
73 | |||
74 | *********************************************************************/ | ||
75 | extern "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 | |||
97 | extern "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 | |||
131 | LExit: | ||
132 | ReleaseMem(pvObject); | ||
133 | |||
134 | return hr; | ||
135 | } | ||
136 | |||
137 | |||
138 | extern "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 | |||
171 | LExit: | ||
172 | ReleaseMem(pv); | ||
173 | |||
174 | return hr; | ||
175 | } | ||
176 | |||
177 | |||
178 | extern "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 | |||
200 | LExit: | ||
201 | ReleaseFileHandle(hFile); | ||
202 | |||
203 | return hr; | ||
204 | } | ||
205 | |||
206 | |||
207 | extern "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 | |||
269 | LExit: | ||
270 | if (hHash) | ||
271 | { | ||
272 | ::CryptDestroyHash(hHash); | ||
273 | } | ||
274 | if (hProv) | ||
275 | { | ||
276 | ::CryptReleaseContext(hProv, 0); | ||
277 | } | ||
278 | |||
279 | return hr; | ||
280 | } | ||
281 | |||
282 | HRESULT 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 | |||
328 | LExit: | ||
329 | if (hHash) | ||
330 | { | ||
331 | ::CryptDestroyHash(hHash); | ||
332 | } | ||
333 | if (hProv) | ||
334 | { | ||
335 | ::CryptReleaseContext(hProv, 0); | ||
336 | } | ||
337 | |||
338 | return hr; | ||
339 | } | ||
340 | |||
341 | HRESULT 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"); | ||
369 | LExit: | ||
370 | return hr; | ||
371 | } | ||
372 | |||
373 | HRESULT 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"); | ||
401 | LExit: | ||
402 | return hr; | ||
403 | } | ||
404 | |||