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