main
cpp 404 lines 11.1 KB
Raw
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