aboutsummaryrefslogtreecommitdiff
path: root/src/dutil/cryputil.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/dutil/cryputil.cpp')
-rw-r--r--src/dutil/cryputil.cpp379
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
5static PFN_RTLENCRYPTMEMORY vpfnRtlEncryptMemory = NULL;
6static PFN_RTLDECRYPTMEMORY vpfnRtlDecryptMemory = NULL;
7static PFN_CRYPTPROTECTMEMORY vpfnCryptProtectMemory = NULL;
8static PFN_CRYPTUNPROTECTMEMORY vpfnCryptUnprotectMemory = NULL;
9
10static HMODULE vhAdvApi32Dll = NULL;
11static HMODULE vhCrypt32Dll = NULL;
12static BOOL vfCrypInitialized = FALSE;
13
14// function definitions
15
16/********************************************************************
17 CrypInitialize - initializes cryputil
18
19*********************************************************************/
20extern "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
51LExit:
52 return hr;
53}
54
55
56/********************************************************************
57 CrypUninitialize - uninitializes cryputil
58
59*********************************************************************/
60extern "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
82extern "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
116LExit:
117 ReleaseMem(pvObject);
118
119 return hr;
120}
121
122
123extern "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
156LExit:
157 ReleaseMem(pv);
158
159 return hr;
160}
161
162
163extern "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
185LExit:
186 ReleaseFileHandle(hFile);
187
188 return hr;
189}
190
191
192extern "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
254LExit:
255 if (hHash)
256 {
257 ::CryptDestroyHash(hHash);
258 }
259 if (hProv)
260 {
261 ::CryptReleaseContext(hProv, 0);
262 }
263
264 return hr;
265}
266
267HRESULT 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
303LExit:
304 if (hHash)
305 {
306 ::CryptDestroyHash(hHash);
307 }
308 if (hProv)
309 {
310 ::CryptReleaseContext(hProv, 0);
311 }
312
313 return hr;
314}
315
316HRESULT 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");
344LExit:
345 return hr;
346}
347
348HRESULT 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");
376LExit:
377 return hr;
378}
379