1 /*
2   zip_crypto_win.c -- Windows Crypto API wrapper.
3   Copyright (C) 2018-2019 Dieter Baron and Thomas Klausner
4 
5   This file is part of libzip, a library to manipulate ZIP archives.
6   The authors can be contacted at <libzip@nih.at>
7 
8   Redistribution and use in source and binary forms, with or without
9   modification, are permitted provided that the following conditions
10   are met:
11   1. Redistributions of source code must retain the above copyright
12   notice, this list of conditions and the following disclaimer.
13   2. Redistributions in binary form must reproduce the above copyright
14   notice, this list of conditions and the following disclaimer in
15   the documentation and/or other materials provided with the
16   distribution.
17   3. The names of the authors may not be used to endorse or promote
18   products derived from this software without specific prior
19   written permission.
20 
21   THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
22   OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23   WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24   ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
25   DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
27   GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
29   IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30   OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
31   IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33 #include <stdlib.h>
34 
35 #include "zipint.h"
36 
37 #include "zip_crypto.h"
38 
39 #define WIN32_LEAN_AND_MEAN
40 #define NOCRYPT
41 
42 #include <windows.h>
43 
44 #include <bcrypt.h>
45 
46 #pragma comment(lib, "bcrypt.lib")
47 
48 /*
49 
50 This code is using the Cryptography API: Next Generation (CNG)
51 https://docs.microsoft.com/en-us/windows/desktop/seccng/cng-portal
52 
53 This API is supported on
54  - Windows Vista or later (client OS)
55  - Windows Server 2008 (server OS)
56  - Windows Embedded Compact 2013 (don't know about Windows Embedded Compact 7)
57 
58 The code was developed for Windows Embedded Compact 2013 (WEC2013),
59 but should be working for all of the above mentioned OSes.
60 
61 There are 2 restrictions for WEC2013, Windows Vista and Windows Server 2008:
62 
63 1.) The function "BCryptDeriveKeyPBKDF2" is not available
64 
65 I found some code which is implementing this function using the deprecated Crypto API here:
66 https://www.idrix.fr/Root/content/view/37/54/
67 
68 I took this code and converted it to the newer CNG API. The original code was more
69 flexible, but this is not needed here so i refactored it a bit and just kept what is needed.
70 
71 The define "HAS_BCRYPTDERIVEKEYPBKDF2" controls whether "BCryptDeriveKeyPBKDF2"
72 of the CNG API is used or not. This define must not be set if you are compiling for WEC2013 or Windows Vista.
73 
74 
75 2.) "BCryptCreateHash" can't manage the memory needed for the hash object internally
76 
77 On Windows 7 or later it is possible to pass NULL for the hash object buffer.
78 This is not supported on WEC2013, so we have to handle the memory allocation/deallocation ourselves.
79 There is no #ifdef to control that, because this is working for all supported OSes.
80 
81 */
82 
83 #if !defined(WINCE) && !defined(__MINGW32__)
84 #define HAS_BCRYPTDERIVEKEYPBKDF2
85 #endif
86 
87 #ifdef HAS_BCRYPTDERIVEKEYPBKDF2
88 
89 bool
_zip_crypto_pbkdf2(const zip_uint8_t * key,zip_uint64_t key_length,const zip_uint8_t * salt,zip_uint16_t salt_length,zip_uint16_t iterations,zip_uint8_t * output,zip_uint16_t output_length)90 _zip_crypto_pbkdf2(const zip_uint8_t *key, zip_uint64_t key_length, const zip_uint8_t *salt, zip_uint16_t salt_length, zip_uint16_t iterations, zip_uint8_t *output, zip_uint16_t output_length) {
91     BCRYPT_ALG_HANDLE hAlgorithm = NULL;
92 
93     if (!BCRYPT_SUCCESS(BCryptOpenAlgorithmProvider(&hAlgorithm, BCRYPT_SHA1_ALGORITHM, NULL, BCRYPT_ALG_HANDLE_HMAC_FLAG))) {
94 	return false;
95     }
96 
97     bool result = BCRYPT_SUCCESS(BCryptDeriveKeyPBKDF2(hAlgorithm, (PUCHAR)key, (ULONG)key_length, (PUCHAR)salt, salt_length, iterations, output, output_length, 0));
98 
99     BCryptCloseAlgorithmProvider(hAlgorithm, 0);
100 
101     return result;
102 }
103 
104 #else
105 
106 #include <math.h>
107 
108 #define DIGEST_SIZE 20
109 #define BLOCK_SIZE 64
110 
111 typedef struct {
112     BCRYPT_ALG_HANDLE hAlgorithm;
113     BCRYPT_HASH_HANDLE hInnerHash;
114     BCRYPT_HASH_HANDLE hOuterHash;
115     ULONG cbHashObject;
116     PUCHAR pbInnerHash;
117     PUCHAR pbOuterHash;
118 } PRF_CTX;
119 
120 static void
hmacFree(PRF_CTX * pContext)121 hmacFree(PRF_CTX *pContext) {
122     if (pContext->hOuterHash)
123 	BCryptDestroyHash(pContext->hOuterHash);
124     if (pContext->hInnerHash)
125 	BCryptDestroyHash(pContext->hInnerHash);
126     free(pContext->pbOuterHash);
127     free(pContext->pbInnerHash);
128     if (pContext->hAlgorithm)
129 	BCryptCloseAlgorithmProvider(pContext->hAlgorithm, 0);
130 }
131 
132 static BOOL
hmacPrecomputeDigest(BCRYPT_HASH_HANDLE hHash,PUCHAR pbPassword,DWORD cbPassword,BYTE mask)133 hmacPrecomputeDigest(BCRYPT_HASH_HANDLE hHash, PUCHAR pbPassword, DWORD cbPassword, BYTE mask) {
134     BYTE buffer[BLOCK_SIZE];
135     DWORD i;
136 
137     if (cbPassword > BLOCK_SIZE) {
138 	return FALSE;
139     }
140 
141     memset(buffer, mask, sizeof(buffer));
142 
143     for (i = 0; i < cbPassword; ++i) {
144 	buffer[i] = (char)(pbPassword[i] ^ mask);
145     }
146 
147     return BCRYPT_SUCCESS(BCryptHashData(hHash, buffer, sizeof(buffer), 0));
148 }
149 
150 static BOOL
hmacInit(PRF_CTX * pContext,PUCHAR pbPassword,DWORD cbPassword)151 hmacInit(PRF_CTX *pContext, PUCHAR pbPassword, DWORD cbPassword) {
152     BOOL bStatus = FALSE;
153     ULONG cbResult;
154     BYTE key[DIGEST_SIZE];
155 
156     if (!BCRYPT_SUCCESS(BCryptOpenAlgorithmProvider(&pContext->hAlgorithm, BCRYPT_SHA1_ALGORITHM, NULL, 0)) || !BCRYPT_SUCCESS(BCryptGetProperty(pContext->hAlgorithm, BCRYPT_OBJECT_LENGTH, (PUCHAR)&pContext->cbHashObject, sizeof(pContext->cbHashObject), &cbResult, 0)) || ((pContext->pbInnerHash = malloc(pContext->cbHashObject)) == NULL) || ((pContext->pbOuterHash = malloc(pContext->cbHashObject)) == NULL) || !BCRYPT_SUCCESS(BCryptCreateHash(pContext->hAlgorithm, &pContext->hInnerHash, pContext->pbInnerHash, pContext->cbHashObject, NULL, 0, 0)) || !BCRYPT_SUCCESS(BCryptCreateHash(pContext->hAlgorithm, &pContext->hOuterHash, pContext->pbOuterHash, pContext->cbHashObject, NULL, 0, 0))) {
157 	goto hmacInit_end;
158     }
159 
160     if (cbPassword > BLOCK_SIZE) {
161 	BCRYPT_HASH_HANDLE hHash = NULL;
162 	PUCHAR pbHashObject = malloc(pContext->cbHashObject);
163 	if (pbHashObject == NULL) {
164 	    goto hmacInit_end;
165 	}
166 
167 	bStatus = BCRYPT_SUCCESS(BCryptCreateHash(pContext->hAlgorithm, &hHash, pbHashObject, pContext->cbHashObject, NULL, 0, 0)) && BCRYPT_SUCCESS(BCryptHashData(hHash, pbPassword, cbPassword, 0)) && BCRYPT_SUCCESS(BCryptGetProperty(hHash, BCRYPT_HASH_LENGTH, (PUCHAR)&cbPassword, sizeof(cbPassword), &cbResult, 0)) && BCRYPT_SUCCESS(BCryptFinishHash(hHash, key, cbPassword, 0));
168 
169 	if (hHash)
170 	    BCryptDestroyHash(hHash);
171 	free(pbHashObject);
172 
173 	if (!bStatus) {
174 	    goto hmacInit_end;
175 	}
176 
177 	pbPassword = key;
178     }
179 
180     bStatus = hmacPrecomputeDigest(pContext->hInnerHash, pbPassword, cbPassword, 0x36) && hmacPrecomputeDigest(pContext->hOuterHash, pbPassword, cbPassword, 0x5C);
181 
182 hmacInit_end:
183 
184     if (bStatus == FALSE)
185 	hmacFree(pContext);
186 
187     return bStatus;
188 }
189 
190 static BOOL
hmacCalculateInternal(BCRYPT_HASH_HANDLE hHashTemplate,PUCHAR pbData,DWORD cbData,PUCHAR pbOutput,DWORD cbOutput,DWORD cbHashObject)191 hmacCalculateInternal(BCRYPT_HASH_HANDLE hHashTemplate, PUCHAR pbData, DWORD cbData, PUCHAR pbOutput, DWORD cbOutput, DWORD cbHashObject) {
192     BOOL success = FALSE;
193     BCRYPT_HASH_HANDLE hHash = NULL;
194     PUCHAR pbHashObject = malloc(cbHashObject);
195 
196     if (pbHashObject == NULL) {
197 	return FALSE;
198     }
199 
200     if (BCRYPT_SUCCESS(BCryptDuplicateHash(hHashTemplate, &hHash, pbHashObject, cbHashObject, 0))) {
201 	success = BCRYPT_SUCCESS(BCryptHashData(hHash, pbData, cbData, 0)) && BCRYPT_SUCCESS(BCryptFinishHash(hHash, pbOutput, cbOutput, 0));
202 
203 	BCryptDestroyHash(hHash);
204     }
205 
206     free(pbHashObject);
207 
208     return success;
209 }
210 
211 static BOOL
hmacCalculate(PRF_CTX * pContext,PUCHAR pbData,DWORD cbData,PUCHAR pbDigest)212 hmacCalculate(PRF_CTX *pContext, PUCHAR pbData, DWORD cbData, PUCHAR pbDigest) {
213     DWORD cbResult;
214     DWORD cbHashObject;
215 
216     return BCRYPT_SUCCESS(BCryptGetProperty(pContext->hAlgorithm, BCRYPT_OBJECT_LENGTH, (PUCHAR)&cbHashObject, sizeof(cbHashObject), &cbResult, 0)) && hmacCalculateInternal(pContext->hInnerHash, pbData, cbData, pbDigest, DIGEST_SIZE, cbHashObject) && hmacCalculateInternal(pContext->hOuterHash, pbDigest, DIGEST_SIZE, pbDigest, DIGEST_SIZE, cbHashObject);
217 }
218 
219 static void
myxor(LPBYTE ptr1,LPBYTE ptr2,DWORD dwLen)220 myxor(LPBYTE ptr1, LPBYTE ptr2, DWORD dwLen) {
221     while (dwLen--)
222 	*ptr1++ ^= *ptr2++;
223 }
224 
225 BOOL
pbkdf2(PUCHAR pbPassword,ULONG cbPassword,PUCHAR pbSalt,ULONG cbSalt,DWORD cIterations,PUCHAR pbDerivedKey,ULONG cbDerivedKey)226 pbkdf2(PUCHAR pbPassword, ULONG cbPassword, PUCHAR pbSalt, ULONG cbSalt, DWORD cIterations, PUCHAR pbDerivedKey, ULONG cbDerivedKey) {
227     BOOL bStatus = FALSE;
228     DWORD l, r, dwULen, i, j;
229     BYTE Ti[DIGEST_SIZE];
230     BYTE V[DIGEST_SIZE];
231     LPBYTE U = malloc(max((cbSalt + 4), DIGEST_SIZE));
232     PRF_CTX prfCtx = {0};
233 
234     if (U == NULL) {
235 	return FALSE;
236     }
237 
238     if (pbPassword == NULL || cbPassword == 0 || pbSalt == NULL || cbSalt == 0 || cIterations == 0 || pbDerivedKey == NULL || cbDerivedKey == 0) {
239 	free(U);
240 	return FALSE;
241     }
242 
243     if (!hmacInit(&prfCtx, pbPassword, cbPassword)) {
244 	goto PBKDF2_end;
245     }
246 
247     l = (DWORD)ceil((double)cbDerivedKey / (double)DIGEST_SIZE);
248     r = cbDerivedKey - (l - 1) * DIGEST_SIZE;
249 
250     for (i = 1; i <= l; i++) {
251 	ZeroMemory(Ti, DIGEST_SIZE);
252 	for (j = 0; j < cIterations; j++) {
253 	    if (j == 0) {
254 		/* construct first input for PRF */
255 		memcpy(U, pbSalt, cbSalt);
256 		U[cbSalt] = (BYTE)((i & 0xFF000000) >> 24);
257 		U[cbSalt + 1] = (BYTE)((i & 0x00FF0000) >> 16);
258 		U[cbSalt + 2] = (BYTE)((i & 0x0000FF00) >> 8);
259 		U[cbSalt + 3] = (BYTE)((i & 0x000000FF));
260 		dwULen = cbSalt + 4;
261 	    }
262 	    else {
263 		memcpy(U, V, DIGEST_SIZE);
264 		dwULen = DIGEST_SIZE;
265 	    }
266 
267 	    if (!hmacCalculate(&prfCtx, U, dwULen, V)) {
268 		goto PBKDF2_end;
269 	    }
270 
271 	    myxor(Ti, V, DIGEST_SIZE);
272 	}
273 
274 	if (i != l) {
275 	    memcpy(&pbDerivedKey[(i - 1) * DIGEST_SIZE], Ti, DIGEST_SIZE);
276 	}
277 	else {
278 	    /* Take only the first r bytes */
279 	    memcpy(&pbDerivedKey[(i - 1) * DIGEST_SIZE], Ti, r);
280 	}
281     }
282 
283     bStatus = TRUE;
284 
285 PBKDF2_end:
286 
287     hmacFree(&prfCtx);
288     free(U);
289     return bStatus;
290 }
291 
292 bool
_zip_crypto_pbkdf2(const zip_uint8_t * key,zip_uint64_t key_length,const zip_uint8_t * salt,zip_uint16_t salt_length,zip_uint16_t iterations,zip_uint8_t * output,zip_uint16_t output_length)293 _zip_crypto_pbkdf2(const zip_uint8_t *key, zip_uint64_t key_length, const zip_uint8_t *salt, zip_uint16_t salt_length, zip_uint16_t iterations, zip_uint8_t *output, zip_uint16_t output_length) {
294     return (key_length <= ZIP_UINT32_MAX) && pbkdf2((PUCHAR)key, (ULONG)key_length, (PUCHAR)salt, salt_length, iterations, output, output_length);
295 }
296 
297 #endif
298 
299 
300 struct _zip_crypto_aes_s {
301     BCRYPT_ALG_HANDLE hAlgorithm;
302     BCRYPT_KEY_HANDLE hKey;
303     ULONG cbKeyObject;
304     PUCHAR pbKeyObject;
305 };
306 
307 _zip_crypto_aes_t *
_zip_crypto_aes_new(const zip_uint8_t * key,zip_uint16_t key_size,zip_error_t * error)308 _zip_crypto_aes_new(const zip_uint8_t *key, zip_uint16_t key_size, zip_error_t *error) {
309     _zip_crypto_aes_t *aes = (_zip_crypto_aes_t *)calloc(1, sizeof(*aes));
310 
311     ULONG cbResult;
312     ULONG key_length = key_size / 8;
313 
314     if (aes == NULL) {
315 	zip_error_set(error, ZIP_ER_MEMORY, 0);
316 	return NULL;
317     }
318 
319     if (!BCRYPT_SUCCESS(BCryptOpenAlgorithmProvider(&aes->hAlgorithm, BCRYPT_AES_ALGORITHM, NULL, 0))) {
320 	_zip_crypto_aes_free(aes);
321 	return NULL;
322     }
323 
324     if (!BCRYPT_SUCCESS(BCryptSetProperty(aes->hAlgorithm, BCRYPT_CHAINING_MODE, (PUCHAR)BCRYPT_CHAIN_MODE_ECB, sizeof(BCRYPT_CHAIN_MODE_ECB), 0))) {
325 	_zip_crypto_aes_free(aes);
326 	return NULL;
327     }
328 
329     if (!BCRYPT_SUCCESS(BCryptGetProperty(aes->hAlgorithm, BCRYPT_OBJECT_LENGTH, (PUCHAR)&aes->cbKeyObject, sizeof(aes->cbKeyObject), &cbResult, 0))) {
330 	_zip_crypto_aes_free(aes);
331 	return NULL;
332     }
333 
334     aes->pbKeyObject = malloc(aes->cbKeyObject);
335     if (aes->pbKeyObject == NULL) {
336 	_zip_crypto_aes_free(aes);
337 	zip_error_set(error, ZIP_ER_MEMORY, 0);
338 	return NULL;
339     }
340 
341     if (!BCRYPT_SUCCESS(BCryptGenerateSymmetricKey(aes->hAlgorithm, &aes->hKey, aes->pbKeyObject, aes->cbKeyObject, (PUCHAR)key, key_length, 0))) {
342 	_zip_crypto_aes_free(aes);
343 	return NULL;
344     }
345 
346     return aes;
347 }
348 
349 void
_zip_crypto_aes_free(_zip_crypto_aes_t * aes)350 _zip_crypto_aes_free(_zip_crypto_aes_t *aes) {
351     if (aes == NULL) {
352 	return;
353     }
354 
355     if (aes->hKey != NULL) {
356 	BCryptDestroyKey(aes->hKey);
357     }
358 
359     if (aes->pbKeyObject != NULL) {
360 	free(aes->pbKeyObject);
361     }
362 
363     if (aes->hAlgorithm != NULL) {
364 	BCryptCloseAlgorithmProvider(aes->hAlgorithm, 0);
365     }
366 
367     free(aes);
368 }
369 
370 bool
_zip_crypto_aes_encrypt_block(_zip_crypto_aes_t * aes,const zip_uint8_t * in,zip_uint8_t * out)371 _zip_crypto_aes_encrypt_block(_zip_crypto_aes_t *aes, const zip_uint8_t *in, zip_uint8_t *out) {
372     ULONG cbResult;
373     NTSTATUS status = BCryptEncrypt(aes->hKey, (PUCHAR)in, ZIP_CRYPTO_AES_BLOCK_LENGTH, NULL, NULL, 0, (PUCHAR)out, ZIP_CRYPTO_AES_BLOCK_LENGTH, &cbResult, 0);
374     return BCRYPT_SUCCESS(status);
375 }
376 
377 struct _zip_crypto_hmac_s {
378     BCRYPT_ALG_HANDLE hAlgorithm;
379     BCRYPT_HASH_HANDLE hHash;
380     DWORD cbHashObject;
381     PUCHAR pbHashObject;
382     DWORD cbHash;
383     PUCHAR pbHash;
384 };
385 
386 /* https://code.msdn.microsoft.com/windowsdesktop/Hmac-Computation-Sample-11fe8ec1/sourcecode?fileId=42820&pathId=283874677 */
387 
388 _zip_crypto_hmac_t *
_zip_crypto_hmac_new(const zip_uint8_t * secret,zip_uint64_t secret_length,zip_error_t * error)389 _zip_crypto_hmac_new(const zip_uint8_t *secret, zip_uint64_t secret_length, zip_error_t *error) {
390     NTSTATUS status;
391     ULONG cbResult;
392     _zip_crypto_hmac_t *hmac;
393 
394     if (secret_length > INT_MAX) {
395 	zip_error_set(error, ZIP_ER_INVAL, 0);
396 	return NULL;
397     }
398 
399     hmac = (_zip_crypto_hmac_t *)calloc(1, sizeof(*hmac));
400 
401     if (hmac == NULL) {
402 	zip_error_set(error, ZIP_ER_MEMORY, 0);
403 	return NULL;
404     }
405 
406     status = BCryptOpenAlgorithmProvider(&hmac->hAlgorithm, BCRYPT_SHA1_ALGORITHM, NULL, BCRYPT_ALG_HANDLE_HMAC_FLAG);
407     if (!BCRYPT_SUCCESS(status)) {
408 	_zip_crypto_hmac_free(hmac);
409 	return NULL;
410     }
411 
412     status = BCryptGetProperty(hmac->hAlgorithm, BCRYPT_OBJECT_LENGTH, (PUCHAR)&hmac->cbHashObject, sizeof(hmac->cbHashObject), &cbResult, 0);
413     if (!BCRYPT_SUCCESS(status)) {
414 	_zip_crypto_hmac_free(hmac);
415 	return NULL;
416     }
417 
418     hmac->pbHashObject = malloc(hmac->cbHashObject);
419     if (hmac->pbHashObject == NULL) {
420 	_zip_crypto_hmac_free(hmac);
421 	zip_error_set(error, ZIP_ER_MEMORY, 0);
422 	return NULL;
423     }
424 
425     status = BCryptGetProperty(hmac->hAlgorithm, BCRYPT_HASH_LENGTH, (PUCHAR)&hmac->cbHash, sizeof(hmac->cbHash), &cbResult, 0);
426     if (!BCRYPT_SUCCESS(status)) {
427 	_zip_crypto_hmac_free(hmac);
428 	return NULL;
429     }
430 
431     hmac->pbHash = malloc(hmac->cbHash);
432     if (hmac->pbHash == NULL) {
433 	_zip_crypto_hmac_free(hmac);
434 	zip_error_set(error, ZIP_ER_MEMORY, 0);
435 	return NULL;
436     }
437 
438     status = BCryptCreateHash(hmac->hAlgorithm, &hmac->hHash, hmac->pbHashObject, hmac->cbHashObject, (PUCHAR)secret, (ULONG)secret_length, 0);
439     if (!BCRYPT_SUCCESS(status)) {
440 	_zip_crypto_hmac_free(hmac);
441 	return NULL;
442     }
443 
444     return hmac;
445 }
446 
447 void
_zip_crypto_hmac_free(_zip_crypto_hmac_t * hmac)448 _zip_crypto_hmac_free(_zip_crypto_hmac_t *hmac) {
449     if (hmac == NULL) {
450 	return;
451     }
452 
453     if (hmac->hHash != NULL) {
454 	BCryptDestroyHash(hmac->hHash);
455     }
456 
457     if (hmac->pbHash != NULL) {
458 	free(hmac->pbHash);
459     }
460 
461     if (hmac->pbHashObject != NULL) {
462 	free(hmac->pbHashObject);
463     }
464 
465     if (hmac->hAlgorithm) {
466 	BCryptCloseAlgorithmProvider(hmac->hAlgorithm, 0);
467     }
468 
469     free(hmac);
470 }
471 
472 bool
_zip_crypto_hmac(_zip_crypto_hmac_t * hmac,zip_uint8_t * data,zip_uint64_t length)473 _zip_crypto_hmac(_zip_crypto_hmac_t *hmac, zip_uint8_t *data, zip_uint64_t length) {
474     if (hmac == NULL || length > ULONG_MAX) {
475 	return false;
476     }
477 
478     return BCRYPT_SUCCESS(BCryptHashData(hmac->hHash, data, (ULONG)length, 0));
479 }
480 
481 bool
_zip_crypto_hmac_output(_zip_crypto_hmac_t * hmac,zip_uint8_t * data)482 _zip_crypto_hmac_output(_zip_crypto_hmac_t *hmac, zip_uint8_t *data) {
483     if (hmac == NULL) {
484 	return false;
485     }
486 
487     return BCRYPT_SUCCESS(BCryptFinishHash(hmac->hHash, data, hmac->cbHash, 0));
488 }
489 
490 ZIP_EXTERN bool
zip_secure_random(zip_uint8_t * buffer,zip_uint16_t length)491 zip_secure_random(zip_uint8_t *buffer, zip_uint16_t length) {
492     return BCRYPT_SUCCESS(BCryptGenRandom(NULL, buffer, length, BCRYPT_USE_SYSTEM_PREFERRED_RNG));
493 }
494