]>
Commit | Line | Data |
---|---|---|
ad5611d8 TR |
1 | /* |
2 | * Copyright (C) the libgit2 contributors. All rights reserved. | |
3 | * | |
4 | * This file is part of libgit2, distributed under the GNU GPL v2 with | |
5 | * a Linking Exception. For full terms see the included COPYING file. | |
6 | */ | |
7 | ||
8 | #include "win32.h" | |
9 | ||
10 | #include "runtime.h" | |
11 | ||
12 | #include <wincrypt.h> | |
13 | #include <strsafe.h> | |
14 | ||
15 | #define GIT_HASH_CNG_DLL_NAME "bcrypt.dll" | |
16 | ||
17 | /* BCRYPT_SHA1_ALGORITHM */ | |
18 | #define GIT_HASH_CNG_SHA1_TYPE L"SHA1" | |
19 | #define GIT_HASH_CNG_SHA256_TYPE L"SHA256" | |
20 | ||
21 | /* BCRYPT_OBJECT_LENGTH */ | |
22 | #define GIT_HASH_CNG_HASH_OBJECT_LEN L"ObjectLength" | |
23 | ||
24 | /* BCRYPT_HASH_REUSEABLE_FLAGS */ | |
25 | #define GIT_HASH_CNG_HASH_REUSABLE 0x00000020 | |
26 | ||
27 | /* Definitions */ | |
28 | ||
29 | /* CryptoAPI is available for hashing on Windows XP and newer. */ | |
30 | struct cryptoapi_provider { | |
31 | HCRYPTPROV handle; | |
32 | }; | |
33 | ||
34 | /* | |
35 | * CNG (bcrypt.dll) is significantly more performant than CryptoAPI and is | |
36 | * preferred, however it is only available on Windows 2008 and newer and | |
37 | * must therefore be dynamically loaded, and we must inline constants that | |
38 | * would not exist when building in pre-Windows 2008 environments. | |
39 | */ | |
40 | ||
41 | /* Function declarations for CNG */ | |
42 | typedef NTSTATUS (WINAPI *cng_open_algorithm_provider_fn)( | |
43 | HANDLE /* BCRYPT_ALG_HANDLE */ *phAlgorithm, | |
44 | LPCWSTR pszAlgId, | |
45 | LPCWSTR pszImplementation, | |
46 | DWORD dwFlags); | |
47 | ||
48 | typedef NTSTATUS (WINAPI *cng_get_property_fn)( | |
49 | HANDLE /* BCRYPT_HANDLE */ hObject, | |
50 | LPCWSTR pszProperty, | |
51 | PUCHAR pbOutput, | |
52 | ULONG cbOutput, | |
53 | ULONG *pcbResult, | |
54 | ULONG dwFlags); | |
55 | ||
56 | typedef NTSTATUS (WINAPI *cng_create_hash_fn)( | |
57 | HANDLE /* BCRYPT_ALG_HANDLE */ hAlgorithm, | |
58 | HANDLE /* BCRYPT_HASH_HANDLE */ *phHash, | |
59 | PUCHAR pbHashObject, ULONG cbHashObject, | |
60 | PUCHAR pbSecret, | |
61 | ULONG cbSecret, | |
62 | ULONG dwFlags); | |
63 | ||
64 | typedef NTSTATUS (WINAPI *cng_finish_hash_fn)( | |
65 | HANDLE /* BCRYPT_HASH_HANDLE */ hHash, | |
66 | PUCHAR pbOutput, | |
67 | ULONG cbOutput, | |
68 | ULONG dwFlags); | |
69 | ||
70 | typedef NTSTATUS (WINAPI *cng_hash_data_fn)( | |
71 | HANDLE /* BCRYPT_HASH_HANDLE */ hHash, | |
72 | PUCHAR pbInput, | |
73 | ULONG cbInput, | |
74 | ULONG dwFlags); | |
75 | ||
76 | typedef NTSTATUS (WINAPI *cng_destroy_hash_fn)( | |
77 | HANDLE /* BCRYPT_HASH_HANDLE */ hHash); | |
78 | ||
79 | typedef NTSTATUS (WINAPI *cng_close_algorithm_provider_fn)( | |
80 | HANDLE /* BCRYPT_ALG_HANDLE */ hAlgorithm, | |
81 | ULONG dwFlags); | |
82 | ||
83 | struct cng_provider { | |
84 | /* DLL for CNG */ | |
85 | HINSTANCE dll; | |
86 | ||
87 | /* Function pointers for CNG */ | |
88 | cng_open_algorithm_provider_fn open_algorithm_provider; | |
89 | cng_get_property_fn get_property; | |
90 | cng_create_hash_fn create_hash; | |
91 | cng_finish_hash_fn finish_hash; | |
92 | cng_hash_data_fn hash_data; | |
93 | cng_destroy_hash_fn destroy_hash; | |
94 | cng_close_algorithm_provider_fn close_algorithm_provider; | |
95 | ||
96 | HANDLE /* BCRYPT_ALG_HANDLE */ sha1_handle; | |
97 | DWORD sha1_object_size; | |
98 | ||
99 | HANDLE /* BCRYPT_ALG_HANDLE */ sha256_handle; | |
100 | DWORD sha256_object_size; | |
101 | }; | |
102 | ||
103 | typedef struct { | |
104 | git_hash_win32_provider_t type; | |
105 | ||
106 | union { | |
107 | struct cryptoapi_provider cryptoapi; | |
108 | struct cng_provider cng; | |
109 | } provider; | |
110 | } hash_win32_provider; | |
111 | ||
112 | /* Hash provider definition */ | |
113 | ||
114 | static hash_win32_provider hash_provider = {0}; | |
115 | ||
116 | /* Hash initialization */ | |
117 | ||
118 | /* Initialize CNG, if available */ | |
119 | GIT_INLINE(int) cng_provider_init(void) | |
120 | { | |
121 | char dll_path[MAX_PATH]; | |
122 | DWORD dll_path_len, size_len; | |
123 | ||
124 | /* Only use CNG on Windows 2008 / Vista SP1 or better (Windows 6.0 SP1) */ | |
125 | if (!git_has_win32_version(6, 0, 1)) { | |
126 | git_error_set(GIT_ERROR_SHA, "CryptoNG is not supported on this platform"); | |
127 | return -1; | |
128 | } | |
129 | ||
130 | /* Load bcrypt.dll explicitly from the system directory */ | |
131 | if ((dll_path_len = GetSystemDirectory(dll_path, MAX_PATH)) == 0 || | |
132 | dll_path_len > MAX_PATH || | |
133 | StringCchCat(dll_path, MAX_PATH, "\\") < 0 || | |
134 | StringCchCat(dll_path, MAX_PATH, GIT_HASH_CNG_DLL_NAME) < 0 || | |
135 | (hash_provider.provider.cng.dll = LoadLibrary(dll_path)) == NULL) { | |
136 | git_error_set(GIT_ERROR_SHA, "CryptoNG library could not be loaded"); | |
137 | return -1; | |
138 | } | |
139 | ||
140 | /* Load the function addresses */ | |
141 | if ((hash_provider.provider.cng.open_algorithm_provider = (cng_open_algorithm_provider_fn)((void *)GetProcAddress(hash_provider.provider.cng.dll, "BCryptOpenAlgorithmProvider"))) == NULL || | |
142 | (hash_provider.provider.cng.get_property = (cng_get_property_fn)((void *)GetProcAddress(hash_provider.provider.cng.dll, "BCryptGetProperty"))) == NULL || | |
143 | (hash_provider.provider.cng.create_hash = (cng_create_hash_fn)((void *)GetProcAddress(hash_provider.provider.cng.dll, "BCryptCreateHash"))) == NULL || | |
144 | (hash_provider.provider.cng.finish_hash = (cng_finish_hash_fn)((void *)GetProcAddress(hash_provider.provider.cng.dll, "BCryptFinishHash"))) == NULL || | |
145 | (hash_provider.provider.cng.hash_data = (cng_hash_data_fn)((void *)GetProcAddress(hash_provider.provider.cng.dll, "BCryptHashData"))) == NULL || | |
146 | (hash_provider.provider.cng.destroy_hash = (cng_destroy_hash_fn)((void *)GetProcAddress(hash_provider.provider.cng.dll, "BCryptDestroyHash"))) == NULL || | |
147 | (hash_provider.provider.cng.close_algorithm_provider = (cng_close_algorithm_provider_fn)((void *)GetProcAddress(hash_provider.provider.cng.dll, "BCryptCloseAlgorithmProvider"))) == NULL) { | |
148 | FreeLibrary(hash_provider.provider.cng.dll); | |
149 | ||
150 | git_error_set(GIT_ERROR_OS, "CryptoNG functions could not be loaded"); | |
151 | return -1; | |
152 | } | |
153 | ||
154 | /* Load the SHA1 algorithm */ | |
155 | if (hash_provider.provider.cng.open_algorithm_provider(&hash_provider.provider.cng.sha1_handle, GIT_HASH_CNG_SHA1_TYPE, NULL, GIT_HASH_CNG_HASH_REUSABLE) < 0 || | |
156 | hash_provider.provider.cng.get_property(hash_provider.provider.cng.sha1_handle, GIT_HASH_CNG_HASH_OBJECT_LEN, (PBYTE)&hash_provider.provider.cng.sha1_object_size, sizeof(DWORD), &size_len, 0) < 0) { | |
157 | git_error_set(GIT_ERROR_OS, "algorithm provider could not be initialized"); | |
158 | goto on_error; | |
159 | } | |
160 | ||
161 | /* Load the SHA256 algorithm */ | |
162 | if (hash_provider.provider.cng.open_algorithm_provider(&hash_provider.provider.cng.sha256_handle, GIT_HASH_CNG_SHA256_TYPE, NULL, GIT_HASH_CNG_HASH_REUSABLE) < 0 || | |
163 | hash_provider.provider.cng.get_property(hash_provider.provider.cng.sha256_handle, GIT_HASH_CNG_HASH_OBJECT_LEN, (PBYTE)&hash_provider.provider.cng.sha256_object_size, sizeof(DWORD), &size_len, 0) < 0) { | |
164 | git_error_set(GIT_ERROR_OS, "algorithm provider could not be initialized"); | |
165 | goto on_error; | |
166 | } | |
167 | ||
168 | hash_provider.type = GIT_HASH_WIN32_CNG; | |
169 | return 0; | |
170 | ||
171 | on_error: | |
172 | if (hash_provider.provider.cng.sha1_handle) | |
173 | hash_provider.provider.cng.close_algorithm_provider(hash_provider.provider.cng.sha1_handle, 0); | |
174 | ||
175 | if (hash_provider.provider.cng.sha256_handle) | |
176 | hash_provider.provider.cng.close_algorithm_provider(hash_provider.provider.cng.sha256_handle, 0); | |
177 | ||
178 | if (hash_provider.provider.cng.dll) | |
179 | FreeLibrary(hash_provider.provider.cng.dll); | |
180 | ||
181 | return -1; | |
182 | } | |
183 | ||
184 | GIT_INLINE(void) cng_provider_shutdown(void) | |
185 | { | |
186 | if (hash_provider.type == GIT_HASH_WIN32_INVALID) | |
187 | return; | |
188 | ||
189 | hash_provider.provider.cng.close_algorithm_provider(hash_provider.provider.cng.sha1_handle, 0); | |
190 | hash_provider.provider.cng.close_algorithm_provider(hash_provider.provider.cng.sha256_handle, 0); | |
191 | FreeLibrary(hash_provider.provider.cng.dll); | |
192 | ||
193 | hash_provider.type = GIT_HASH_WIN32_INVALID; | |
194 | } | |
195 | ||
196 | /* Initialize CryptoAPI */ | |
197 | GIT_INLINE(int) cryptoapi_provider_init(void) | |
198 | { | |
199 | if (!CryptAcquireContext(&hash_provider.provider.cryptoapi.handle, NULL, 0, PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) { | |
200 | git_error_set(GIT_ERROR_OS, "legacy hash context could not be started"); | |
201 | return -1; | |
202 | } | |
203 | ||
204 | hash_provider.type = GIT_HASH_WIN32_CRYPTOAPI; | |
205 | return 0; | |
206 | } | |
207 | ||
208 | GIT_INLINE(void) cryptoapi_provider_shutdown(void) | |
209 | { | |
210 | if (hash_provider.type == GIT_HASH_WIN32_INVALID) | |
211 | return; | |
212 | ||
213 | CryptReleaseContext(hash_provider.provider.cryptoapi.handle, 0); | |
214 | ||
215 | hash_provider.type = GIT_HASH_WIN32_INVALID; | |
216 | } | |
217 | ||
218 | static void hash_provider_shutdown(void) | |
219 | { | |
220 | if (hash_provider.type == GIT_HASH_WIN32_CNG) | |
221 | cng_provider_shutdown(); | |
222 | else if (hash_provider.type == GIT_HASH_WIN32_CRYPTOAPI) | |
223 | cryptoapi_provider_shutdown(); | |
224 | } | |
225 | ||
226 | static int hash_provider_init(void) | |
227 | { | |
228 | int error = 0; | |
229 | ||
230 | if (hash_provider.type != GIT_HASH_WIN32_INVALID) | |
231 | return 0; | |
232 | ||
233 | if ((error = cng_provider_init()) < 0) | |
234 | error = cryptoapi_provider_init(); | |
235 | ||
236 | if (!error) | |
237 | error = git_runtime_shutdown_register(hash_provider_shutdown); | |
238 | ||
239 | return error; | |
240 | } | |
241 | ||
242 | git_hash_win32_provider_t git_hash_win32_provider(void) | |
243 | { | |
244 | return hash_provider.type; | |
245 | } | |
246 | ||
247 | int git_hash_win32_set_provider(git_hash_win32_provider_t provider) | |
248 | { | |
249 | if (provider == hash_provider.type) | |
250 | return 0; | |
251 | ||
252 | hash_provider_shutdown(); | |
253 | ||
254 | if (provider == GIT_HASH_WIN32_CNG) | |
255 | return cng_provider_init(); | |
256 | else if (provider == GIT_HASH_WIN32_CRYPTOAPI) | |
257 | return cryptoapi_provider_init(); | |
258 | ||
259 | git_error_set(GIT_ERROR_SHA, "unsupported win32 provider"); | |
260 | return -1; | |
261 | } | |
262 | ||
263 | /* CryptoAPI: available in Windows XP and newer */ | |
264 | ||
265 | GIT_INLINE(int) hash_cryptoapi_init(git_hash_win32_ctx *ctx) | |
266 | { | |
267 | if (ctx->ctx.cryptoapi.valid) | |
268 | CryptDestroyHash(ctx->ctx.cryptoapi.hash_handle); | |
269 | ||
270 | if (!CryptCreateHash(hash_provider.provider.cryptoapi.handle, ctx->algorithm, 0, 0, &ctx->ctx.cryptoapi.hash_handle)) { | |
271 | ctx->ctx.cryptoapi.valid = 0; | |
272 | git_error_set(GIT_ERROR_OS, "legacy hash implementation could not be created"); | |
273 | return -1; | |
274 | } | |
275 | ||
276 | ctx->ctx.cryptoapi.valid = 1; | |
277 | return 0; | |
278 | } | |
279 | ||
280 | GIT_INLINE(int) hash_cryptoapi_update(git_hash_win32_ctx *ctx, const void *_data, size_t len) | |
281 | { | |
282 | const BYTE *data = (BYTE *)_data; | |
283 | ||
284 | GIT_ASSERT(ctx->ctx.cryptoapi.valid); | |
285 | ||
286 | while (len > 0) { | |
287 | DWORD chunk = (len > MAXDWORD) ? MAXDWORD : (DWORD)len; | |
288 | ||
289 | if (!CryptHashData(ctx->ctx.cryptoapi.hash_handle, data, chunk, 0)) { | |
290 | git_error_set(GIT_ERROR_OS, "legacy hash data could not be updated"); | |
291 | return -1; | |
292 | } | |
293 | ||
294 | data += chunk; | |
295 | len -= chunk; | |
296 | } | |
297 | ||
298 | return 0; | |
299 | } | |
300 | ||
301 | GIT_INLINE(int) hash_cryptoapi_final(unsigned char *out, git_hash_win32_ctx *ctx) | |
302 | { | |
303 | DWORD len = ctx->algorithm == CALG_SHA_256 ? GIT_HASH_SHA256_SIZE : GIT_HASH_SHA1_SIZE; | |
304 | int error = 0; | |
305 | ||
306 | GIT_ASSERT(ctx->ctx.cryptoapi.valid); | |
307 | ||
308 | if (!CryptGetHashParam(ctx->ctx.cryptoapi.hash_handle, HP_HASHVAL, out, &len, 0)) { | |
309 | git_error_set(GIT_ERROR_OS, "legacy hash data could not be finished"); | |
310 | error = -1; | |
311 | } | |
312 | ||
313 | CryptDestroyHash(ctx->ctx.cryptoapi.hash_handle); | |
314 | ctx->ctx.cryptoapi.valid = 0; | |
315 | ||
316 | return error; | |
317 | } | |
318 | ||
319 | GIT_INLINE(void) hash_ctx_cryptoapi_cleanup(git_hash_win32_ctx *ctx) | |
320 | { | |
321 | if (ctx->ctx.cryptoapi.valid) | |
322 | CryptDestroyHash(ctx->ctx.cryptoapi.hash_handle); | |
323 | } | |
324 | ||
325 | GIT_INLINE(int) hash_sha1_cryptoapi_ctx_init_init(git_hash_win32_ctx *ctx) | |
326 | { | |
327 | ctx->algorithm = CALG_SHA1; | |
328 | return hash_cryptoapi_init(ctx); | |
329 | } | |
330 | ||
331 | GIT_INLINE(int) hash_sha256_cryptoapi_ctx_init(git_hash_win32_ctx *ctx) | |
332 | { | |
333 | ctx->algorithm = CALG_SHA_256; | |
334 | return hash_cryptoapi_init(ctx); | |
335 | } | |
336 | ||
337 | /* CNG: Available in Windows Server 2008 and newer */ | |
338 | ||
339 | GIT_INLINE(int) hash_sha1_cng_ctx_init(git_hash_win32_ctx *ctx) | |
340 | { | |
341 | if ((ctx->ctx.cng.hash_object = git__malloc(hash_provider.provider.cng.sha1_object_size)) == NULL) | |
342 | return -1; | |
343 | ||
344 | if (hash_provider.provider.cng.create_hash(hash_provider.provider.cng.sha1_handle, &ctx->ctx.cng.hash_handle, ctx->ctx.cng.hash_object, hash_provider.provider.cng.sha1_object_size, NULL, 0, 0) < 0) { | |
345 | git__free(ctx->ctx.cng.hash_object); | |
346 | ||
347 | git_error_set(GIT_ERROR_OS, "sha1 implementation could not be created"); | |
348 | return -1; | |
349 | } | |
350 | ||
351 | ctx->algorithm = CALG_SHA1; | |
352 | return 0; | |
353 | } | |
354 | ||
355 | GIT_INLINE(int) hash_sha256_cng_ctx_init(git_hash_win32_ctx *ctx) | |
356 | { | |
357 | if ((ctx->ctx.cng.hash_object = git__malloc(hash_provider.provider.cng.sha256_object_size)) == NULL) | |
358 | return -1; | |
359 | ||
360 | if (hash_provider.provider.cng.create_hash(hash_provider.provider.cng.sha256_handle, &ctx->ctx.cng.hash_handle, ctx->ctx.cng.hash_object, hash_provider.provider.cng.sha256_object_size, NULL, 0, 0) < 0) { | |
361 | git__free(ctx->ctx.cng.hash_object); | |
362 | ||
363 | git_error_set(GIT_ERROR_OS, "sha256 implementation could not be created"); | |
364 | return -1; | |
365 | } | |
366 | ||
367 | ctx->algorithm = CALG_SHA_256; | |
368 | return 0; | |
369 | } | |
370 | ||
371 | GIT_INLINE(int) hash_cng_init(git_hash_win32_ctx *ctx) | |
372 | { | |
373 | BYTE hash[GIT_HASH_SHA256_SIZE]; | |
374 | ULONG size = ctx->algorithm == CALG_SHA_256 ? GIT_HASH_SHA256_SIZE : GIT_HASH_SHA1_SIZE; | |
375 | ||
376 | if (!ctx->ctx.cng.updated) | |
377 | return 0; | |
378 | ||
379 | /* CNG needs to be finished to restart */ | |
380 | if (hash_provider.provider.cng.finish_hash(ctx->ctx.cng.hash_handle, hash, size, 0) < 0) { | |
381 | git_error_set(GIT_ERROR_OS, "hash implementation could not be finished"); | |
382 | return -1; | |
383 | } | |
384 | ||
385 | ctx->ctx.cng.updated = 0; | |
386 | ||
387 | return 0; | |
388 | } | |
389 | ||
390 | GIT_INLINE(int) hash_cng_update(git_hash_win32_ctx *ctx, const void *_data, size_t len) | |
391 | { | |
392 | PBYTE data = (PBYTE)_data; | |
393 | ||
394 | while (len > 0) { | |
395 | ULONG chunk = (len > ULONG_MAX) ? ULONG_MAX : (ULONG)len; | |
396 | ||
397 | if (hash_provider.provider.cng.hash_data(ctx->ctx.cng.hash_handle, data, chunk, 0) < 0) { | |
398 | git_error_set(GIT_ERROR_OS, "hash could not be updated"); | |
399 | return -1; | |
400 | } | |
401 | ||
402 | data += chunk; | |
403 | len -= chunk; | |
404 | } | |
405 | ||
406 | return 0; | |
407 | } | |
408 | ||
409 | GIT_INLINE(int) hash_cng_final(unsigned char *out, git_hash_win32_ctx *ctx) | |
410 | { | |
411 | ULONG size = ctx->algorithm == CALG_SHA_256 ? GIT_HASH_SHA256_SIZE : GIT_HASH_SHA1_SIZE; | |
412 | ||
413 | if (hash_provider.provider.cng.finish_hash(ctx->ctx.cng.hash_handle, out, size, 0) < 0) { | |
414 | git_error_set(GIT_ERROR_OS, "hash could not be finished"); | |
415 | return -1; | |
416 | } | |
417 | ||
418 | ctx->ctx.cng.updated = 0; | |
419 | ||
420 | return 0; | |
421 | } | |
422 | ||
423 | GIT_INLINE(void) hash_ctx_cng_cleanup(git_hash_win32_ctx *ctx) | |
424 | { | |
425 | hash_provider.provider.cng.destroy_hash(ctx->ctx.cng.hash_handle); | |
426 | git__free(ctx->ctx.cng.hash_object); | |
427 | } | |
428 | ||
429 | /* Indirection between CryptoAPI and CNG */ | |
430 | ||
431 | GIT_INLINE(int) hash_sha1_win32_ctx_init(git_hash_win32_ctx *ctx) | |
432 | { | |
433 | GIT_ASSERT_ARG(hash_provider.type); | |
434 | ||
435 | memset(ctx, 0x0, sizeof(git_hash_win32_ctx)); | |
436 | return (hash_provider.type == GIT_HASH_WIN32_CNG) ? hash_sha1_cng_ctx_init(ctx) : hash_sha1_cryptoapi_ctx_init_init(ctx); | |
437 | } | |
438 | ||
439 | GIT_INLINE(int) hash_sha256_win32_ctx_init(git_hash_win32_ctx *ctx) | |
440 | { | |
441 | GIT_ASSERT_ARG(hash_provider.type); | |
442 | ||
443 | memset(ctx, 0x0, sizeof(git_hash_win32_ctx)); | |
444 | return (hash_provider.type == GIT_HASH_WIN32_CNG) ? hash_sha256_cng_ctx_init(ctx) : hash_sha256_cryptoapi_ctx_init(ctx); | |
445 | } | |
446 | ||
447 | GIT_INLINE(int) hash_win32_init(git_hash_win32_ctx *ctx) | |
448 | { | |
449 | return (hash_provider.type == GIT_HASH_WIN32_CNG) ? hash_cng_init(ctx) : hash_cryptoapi_init(ctx); | |
450 | } | |
451 | ||
452 | GIT_INLINE(int) hash_win32_update(git_hash_win32_ctx *ctx, const void *data, size_t len) | |
453 | { | |
454 | return (hash_provider.type == GIT_HASH_WIN32_CNG) ? hash_cng_update(ctx, data, len) : hash_cryptoapi_update(ctx, data, len); | |
455 | } | |
456 | ||
457 | GIT_INLINE(int) hash_win32_final(unsigned char *out, git_hash_win32_ctx *ctx) | |
458 | { | |
459 | GIT_ASSERT_ARG(ctx); | |
460 | return (hash_provider.type == GIT_HASH_WIN32_CNG) ? hash_cng_final(out, ctx) : hash_cryptoapi_final(out, ctx); | |
461 | } | |
462 | ||
463 | GIT_INLINE(void) hash_win32_cleanup(git_hash_win32_ctx *ctx) | |
464 | { | |
465 | if (hash_provider.type == GIT_HASH_WIN32_CNG) | |
466 | hash_ctx_cng_cleanup(ctx); | |
467 | else if(hash_provider.type == GIT_HASH_WIN32_CRYPTOAPI) | |
468 | hash_ctx_cryptoapi_cleanup(ctx); | |
469 | } | |
470 | ||
471 | #ifdef GIT_SHA1_WIN32 | |
472 | ||
473 | int git_hash_sha1_global_init(void) | |
474 | { | |
475 | return hash_provider_init(); | |
476 | } | |
477 | ||
478 | int git_hash_sha1_ctx_init(git_hash_sha1_ctx *ctx) | |
479 | { | |
480 | GIT_ASSERT_ARG(ctx); | |
481 | return hash_sha1_win32_ctx_init(&ctx->win32); | |
482 | } | |
483 | ||
484 | int git_hash_sha1_init(git_hash_sha1_ctx *ctx) | |
485 | { | |
486 | GIT_ASSERT_ARG(ctx); | |
487 | return hash_win32_init(&ctx->win32); | |
488 | } | |
489 | ||
490 | int git_hash_sha1_update(git_hash_sha1_ctx *ctx, const void *data, size_t len) | |
491 | { | |
492 | GIT_ASSERT_ARG(ctx); | |
493 | return hash_win32_update(&ctx->win32, data, len); | |
494 | } | |
495 | ||
496 | int git_hash_sha1_final(unsigned char *out, git_hash_sha1_ctx *ctx) | |
497 | { | |
498 | GIT_ASSERT_ARG(ctx); | |
499 | return hash_win32_final(out, &ctx->win32); | |
500 | } | |
501 | ||
502 | void git_hash_sha1_ctx_cleanup(git_hash_sha1_ctx *ctx) | |
503 | { | |
504 | if (!ctx) | |
505 | return; | |
506 | hash_win32_cleanup(&ctx->win32); | |
507 | } | |
508 | ||
509 | #endif | |
510 | ||
511 | #ifdef GIT_SHA256_WIN32 | |
512 | ||
513 | int git_hash_sha256_global_init(void) | |
514 | { | |
515 | return hash_provider_init(); | |
516 | } | |
517 | ||
518 | int git_hash_sha256_ctx_init(git_hash_sha256_ctx *ctx) | |
519 | { | |
520 | GIT_ASSERT_ARG(ctx); | |
521 | return hash_sha256_win32_ctx_init(&ctx->win32); | |
522 | } | |
523 | ||
524 | int git_hash_sha256_init(git_hash_sha256_ctx *ctx) | |
525 | { | |
526 | GIT_ASSERT_ARG(ctx); | |
527 | return hash_win32_init(&ctx->win32); | |
528 | } | |
529 | ||
530 | int git_hash_sha256_update(git_hash_sha256_ctx *ctx, const void *data, size_t len) | |
531 | { | |
532 | GIT_ASSERT_ARG(ctx); | |
533 | return hash_win32_update(&ctx->win32, data, len); | |
534 | } | |
535 | ||
536 | int git_hash_sha256_final(unsigned char *out, git_hash_sha256_ctx *ctx) | |
537 | { | |
538 | GIT_ASSERT_ARG(ctx); | |
539 | return hash_win32_final(out, &ctx->win32); | |
540 | } | |
541 | ||
542 | void git_hash_sha256_ctx_cleanup(git_hash_sha256_ctx *ctx) | |
543 | { | |
544 | if (!ctx) | |
545 | return; | |
546 | hash_win32_cleanup(&ctx->win32); | |
547 | } | |
548 | ||
549 | #endif |