msvcp120: Fix _Xtime_diff_to_millis2 overflow behavior.
[wine.git] / dlls / bcrypt / bcrypt_main.c
blobb631128e5e05cbf146081d66ae1d167f15b60c81
1 /*
2 * Copyright 2009 Henri Verbeet for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #include "config.h"
21 #include "wine/port.h"
23 #include <stdarg.h>
24 #ifdef HAVE_COMMONCRYPTO_COMMONDIGEST_H
25 #include <CommonCrypto/CommonDigest.h>
26 #include <CommonCrypto/CommonHMAC.h>
27 #elif defined(SONAME_LIBGNUTLS)
28 #include <gnutls/gnutls.h>
29 #include <gnutls/crypto.h>
30 #endif
32 #include "ntstatus.h"
33 #define WIN32_NO_STATUS
34 #include "windef.h"
35 #include "winbase.h"
36 #include "ntsecapi.h"
37 #include "bcrypt.h"
39 #include "bcrypt_internal.h"
41 #include "wine/debug.h"
42 #include "wine/library.h"
43 #include "wine/unicode.h"
45 WINE_DEFAULT_DEBUG_CHANNEL(bcrypt);
47 static HINSTANCE instance;
49 #if defined(HAVE_GNUTLS_CIPHER_INIT) && !defined(HAVE_COMMONCRYPTO_COMMONDIGEST_H)
50 WINE_DECLARE_DEBUG_CHANNEL(winediag);
52 static void *libgnutls_handle;
53 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
54 MAKE_FUNCPTR(gnutls_cipher_decrypt2);
55 MAKE_FUNCPTR(gnutls_cipher_deinit);
56 MAKE_FUNCPTR(gnutls_cipher_encrypt2);
57 MAKE_FUNCPTR(gnutls_cipher_init);
58 MAKE_FUNCPTR(gnutls_global_deinit);
59 MAKE_FUNCPTR(gnutls_global_init);
60 MAKE_FUNCPTR(gnutls_global_set_log_function);
61 MAKE_FUNCPTR(gnutls_global_set_log_level);
62 MAKE_FUNCPTR(gnutls_perror);
63 #undef MAKE_FUNCPTR
65 static void gnutls_log( int level, const char *msg )
67 TRACE( "<%d> %s", level, msg );
70 static BOOL gnutls_initialize(void)
72 int ret;
74 if (!(libgnutls_handle = wine_dlopen( SONAME_LIBGNUTLS, RTLD_NOW, NULL, 0 )))
76 ERR_(winediag)( "failed to load libgnutls, no support for encryption\n" );
77 return FALSE;
80 #define LOAD_FUNCPTR(f) \
81 if (!(p##f = wine_dlsym( libgnutls_handle, #f, NULL, 0 ))) \
82 { \
83 ERR( "failed to load %s\n", #f ); \
84 goto fail; \
87 LOAD_FUNCPTR(gnutls_cipher_decrypt2)
88 LOAD_FUNCPTR(gnutls_cipher_deinit)
89 LOAD_FUNCPTR(gnutls_cipher_encrypt2)
90 LOAD_FUNCPTR(gnutls_cipher_init)
91 LOAD_FUNCPTR(gnutls_global_deinit)
92 LOAD_FUNCPTR(gnutls_global_init)
93 LOAD_FUNCPTR(gnutls_global_set_log_function)
94 LOAD_FUNCPTR(gnutls_global_set_log_level)
95 LOAD_FUNCPTR(gnutls_perror)
96 #undef LOAD_FUNCPTR
98 if ((ret = pgnutls_global_init()) != GNUTLS_E_SUCCESS)
100 pgnutls_perror( ret );
101 goto fail;
104 if (TRACE_ON( bcrypt ))
106 pgnutls_global_set_log_level( 4 );
107 pgnutls_global_set_log_function( gnutls_log );
110 return TRUE;
112 fail:
113 wine_dlclose( libgnutls_handle, NULL, 0 );
114 libgnutls_handle = NULL;
115 return FALSE;
118 static void gnutls_uninitialize(void)
120 pgnutls_global_deinit();
121 wine_dlclose( libgnutls_handle, NULL, 0 );
122 libgnutls_handle = NULL;
124 #endif /* HAVE_GNUTLS_CIPHER_INIT && !HAVE_COMMONCRYPTO_COMMONDIGEST_H */
126 NTSTATUS WINAPI BCryptEnumAlgorithms(ULONG dwAlgOperations, ULONG *pAlgCount,
127 BCRYPT_ALGORITHM_IDENTIFIER **ppAlgList, ULONG dwFlags)
129 FIXME("%08x, %p, %p, %08x - stub\n", dwAlgOperations, pAlgCount, ppAlgList, dwFlags);
131 *ppAlgList=NULL;
132 *pAlgCount=0;
134 return STATUS_NOT_IMPLEMENTED;
137 #define MAGIC_ALG (('A' << 24) | ('L' << 16) | ('G' << 8) | '0')
138 #define MAGIC_HASH (('H' << 24) | ('A' << 16) | ('S' << 8) | 'H')
139 #define MAGIC_KEY (('K' << 24) | ('E' << 16) | ('Y' << 8) | '0')
140 struct object
142 ULONG magic;
145 enum alg_id
147 ALG_ID_AES,
148 ALG_ID_MD5,
149 ALG_ID_RNG,
150 ALG_ID_SHA1,
151 ALG_ID_SHA256,
152 ALG_ID_SHA384,
153 ALG_ID_SHA512
156 #define MAX_HASH_OUTPUT_BYTES 64
157 #define MAX_HASH_BLOCK_BITS 1024
159 static const struct {
160 ULONG object_length;
161 ULONG hash_length;
162 ULONG block_bits;
163 const WCHAR *alg_name;
164 } alg_props[] = {
165 /* ALG_ID_AES */ { 654, 0, 0, BCRYPT_AES_ALGORITHM },
166 /* ALG_ID_MD5 */ { 274, 16, 512, BCRYPT_MD5_ALGORITHM },
167 /* ALG_ID_RNG */ { 0, 0, 0, BCRYPT_RNG_ALGORITHM },
168 /* ALG_ID_SHA1 */ { 278, 20, 512, BCRYPT_SHA1_ALGORITHM },
169 /* ALG_ID_SHA256 */ { 286, 32, 512, BCRYPT_SHA256_ALGORITHM },
170 /* ALG_ID_SHA384 */ { 382, 48, 1024, BCRYPT_SHA384_ALGORITHM },
171 /* ALG_ID_SHA512 */ { 382, 64, 1024, BCRYPT_SHA512_ALGORITHM }
174 struct algorithm
176 struct object hdr;
177 enum alg_id id;
178 BOOL hmac;
181 NTSTATUS WINAPI BCryptGenRandom(BCRYPT_ALG_HANDLE handle, UCHAR *buffer, ULONG count, ULONG flags)
183 const DWORD supported_flags = BCRYPT_USE_SYSTEM_PREFERRED_RNG;
184 struct algorithm *algorithm = handle;
186 TRACE("%p, %p, %u, %08x - semi-stub\n", handle, buffer, count, flags);
188 if (!algorithm)
190 /* It's valid to call without an algorithm if BCRYPT_USE_SYSTEM_PREFERRED_RNG
191 * is set. In this case the preferred system RNG is used.
193 if (!(flags & BCRYPT_USE_SYSTEM_PREFERRED_RNG))
194 return STATUS_INVALID_HANDLE;
196 else if (algorithm->hdr.magic != MAGIC_ALG || algorithm->id != ALG_ID_RNG)
197 return STATUS_INVALID_HANDLE;
199 if (!buffer)
200 return STATUS_INVALID_PARAMETER;
202 if (flags & ~supported_flags)
203 FIXME("unsupported flags %08x\n", flags & ~supported_flags);
205 if (algorithm)
206 FIXME("ignoring selected algorithm\n");
208 /* When zero bytes are requested the function returns success too. */
209 if (!count)
210 return STATUS_SUCCESS;
212 if (algorithm || (flags & BCRYPT_USE_SYSTEM_PREFERRED_RNG))
214 if (RtlGenRandom(buffer, count))
215 return STATUS_SUCCESS;
218 FIXME("called with unsupported parameters, returning error\n");
219 return STATUS_NOT_IMPLEMENTED;
222 NTSTATUS WINAPI BCryptOpenAlgorithmProvider( BCRYPT_ALG_HANDLE *handle, LPCWSTR id, LPCWSTR implementation, DWORD flags )
224 const DWORD supported_flags = BCRYPT_ALG_HANDLE_HMAC_FLAG;
225 struct algorithm *alg;
226 enum alg_id alg_id;
228 TRACE( "%p, %s, %s, %08x\n", handle, wine_dbgstr_w(id), wine_dbgstr_w(implementation), flags );
230 if (!handle || !id) return STATUS_INVALID_PARAMETER;
231 if (flags & ~supported_flags)
233 FIXME( "unsupported flags %08x\n", flags & ~supported_flags);
234 return STATUS_NOT_IMPLEMENTED;
237 if (!strcmpW( id, BCRYPT_AES_ALGORITHM )) alg_id = ALG_ID_AES;
238 else if (!strcmpW( id, BCRYPT_MD5_ALGORITHM )) alg_id = ALG_ID_MD5;
239 else if (!strcmpW( id, BCRYPT_RNG_ALGORITHM )) alg_id = ALG_ID_RNG;
240 else if (!strcmpW( id, BCRYPT_SHA1_ALGORITHM )) alg_id = ALG_ID_SHA1;
241 else if (!strcmpW( id, BCRYPT_SHA256_ALGORITHM )) alg_id = ALG_ID_SHA256;
242 else if (!strcmpW( id, BCRYPT_SHA384_ALGORITHM )) alg_id = ALG_ID_SHA384;
243 else if (!strcmpW( id, BCRYPT_SHA512_ALGORITHM )) alg_id = ALG_ID_SHA512;
244 else
246 FIXME( "algorithm %s not supported\n", debugstr_w(id) );
247 return STATUS_NOT_IMPLEMENTED;
249 if (implementation && strcmpW( implementation, MS_PRIMITIVE_PROVIDER ))
251 FIXME( "implementation %s not supported\n", debugstr_w(implementation) );
252 return STATUS_NOT_IMPLEMENTED;
255 if (!(alg = HeapAlloc( GetProcessHeap(), 0, sizeof(*alg) ))) return STATUS_NO_MEMORY;
256 alg->hdr.magic = MAGIC_ALG;
257 alg->id = alg_id;
258 alg->hmac = flags & BCRYPT_ALG_HANDLE_HMAC_FLAG;
260 *handle = alg;
261 return STATUS_SUCCESS;
264 NTSTATUS WINAPI BCryptCloseAlgorithmProvider( BCRYPT_ALG_HANDLE handle, DWORD flags )
266 struct algorithm *alg = handle;
268 TRACE( "%p, %08x\n", handle, flags );
270 if (!alg || alg->hdr.magic != MAGIC_ALG) return STATUS_INVALID_HANDLE;
271 HeapFree( GetProcessHeap(), 0, alg );
272 return STATUS_SUCCESS;
275 NTSTATUS WINAPI BCryptGetFipsAlgorithmMode(BOOLEAN *enabled)
277 FIXME("%p - semi-stub\n", enabled);
279 if (!enabled)
280 return STATUS_INVALID_PARAMETER;
282 *enabled = FALSE;
283 return STATUS_SUCCESS;
286 struct hash_impl
288 union
290 MD5_CTX md5;
291 SHA_CTX sha1;
292 SHA256_CTX sha256;
293 SHA512_CTX sha512;
294 } u;
297 static NTSTATUS hash_init( struct hash_impl *hash, enum alg_id alg_id )
299 switch (alg_id)
301 case ALG_ID_MD5:
302 MD5Init( &hash->u.md5 );
303 break;
305 case ALG_ID_SHA1:
306 A_SHAInit( &hash->u.sha1 );
307 break;
309 case ALG_ID_SHA256:
310 sha256_init( &hash->u.sha256 );
311 break;
313 case ALG_ID_SHA384:
314 sha384_init( &hash->u.sha512 );
315 break;
317 case ALG_ID_SHA512:
318 sha512_init( &hash->u.sha512 );
319 break;
321 default:
322 ERR( "unhandled id %u\n", alg_id );
323 return STATUS_NOT_IMPLEMENTED;
325 return STATUS_SUCCESS;
328 static NTSTATUS hash_update( struct hash_impl *hash, enum alg_id alg_id,
329 UCHAR *input, ULONG size )
331 switch (alg_id)
333 case ALG_ID_MD5:
334 MD5Update( &hash->u.md5, input, size );
335 break;
337 case ALG_ID_SHA1:
338 A_SHAUpdate( &hash->u.sha1, input, size );
339 break;
341 case ALG_ID_SHA256:
342 sha256_update( &hash->u.sha256, input, size );
343 break;
345 case ALG_ID_SHA384:
346 sha384_update( &hash->u.sha512, input, size );
347 break;
349 case ALG_ID_SHA512:
350 sha512_update( &hash->u.sha512, input, size );
351 break;
353 default:
354 ERR( "unhandled id %u\n", alg_id );
355 return STATUS_NOT_IMPLEMENTED;
357 return STATUS_SUCCESS;
360 static NTSTATUS hash_finish( struct hash_impl *hash, enum alg_id alg_id,
361 UCHAR *output, ULONG size )
363 switch (alg_id)
365 case ALG_ID_MD5:
366 MD5Final( &hash->u.md5 );
367 memcpy( output, hash->u.md5.digest, 16 );
368 break;
370 case ALG_ID_SHA1:
371 A_SHAFinal( &hash->u.sha1, (ULONG *)output );
372 break;
374 case ALG_ID_SHA256:
375 sha256_finalize( &hash->u.sha256, output );
376 break;
378 case ALG_ID_SHA384:
379 sha384_finalize( &hash->u.sha512, output );
380 break;
382 case ALG_ID_SHA512:
383 sha512_finalize( &hash->u.sha512, output );
384 break;
386 default:
387 ERR( "unhandled id %u\n", alg_id );
388 return STATUS_NOT_IMPLEMENTED;
390 return STATUS_SUCCESS;
393 struct hash
395 struct object hdr;
396 enum alg_id alg_id;
397 BOOL hmac;
398 struct hash_impl outer;
399 struct hash_impl inner;
402 #define BLOCK_LENGTH_AES 16
404 static NTSTATUS generic_alg_property( enum alg_id id, const WCHAR *prop, UCHAR *buf, ULONG size, ULONG *ret_size )
406 if (!strcmpW( prop, BCRYPT_OBJECT_LENGTH ))
408 if (!alg_props[id].object_length)
409 return STATUS_NOT_SUPPORTED;
410 *ret_size = sizeof(ULONG);
411 if (size < sizeof(ULONG))
412 return STATUS_BUFFER_TOO_SMALL;
413 if (buf)
414 *(ULONG *)buf = alg_props[id].object_length;
415 return STATUS_SUCCESS;
418 if (!strcmpW( prop, BCRYPT_HASH_LENGTH ))
420 if (!alg_props[id].hash_length)
421 return STATUS_NOT_SUPPORTED;
422 *ret_size = sizeof(ULONG);
423 if (size < sizeof(ULONG))
424 return STATUS_BUFFER_TOO_SMALL;
425 if(buf)
426 *(ULONG*)buf = alg_props[id].hash_length;
427 return STATUS_SUCCESS;
430 if (!strcmpW( prop, BCRYPT_ALGORITHM_NAME ))
432 *ret_size = (strlenW(alg_props[id].alg_name)+1)*sizeof(WCHAR);
433 if (size < *ret_size)
434 return STATUS_BUFFER_TOO_SMALL;
435 if(buf)
436 memcpy(buf, alg_props[id].alg_name, *ret_size);
437 return STATUS_SUCCESS;
440 return STATUS_NOT_IMPLEMENTED;
443 static NTSTATUS get_alg_property( enum alg_id id, const WCHAR *prop, UCHAR *buf, ULONG size, ULONG *ret_size )
445 NTSTATUS status;
447 status = generic_alg_property( id, prop, buf, size, ret_size );
448 if (status != STATUS_NOT_IMPLEMENTED)
449 return status;
451 switch (id)
453 case ALG_ID_AES:
454 if (!strcmpW( prop, BCRYPT_BLOCK_LENGTH ))
456 *ret_size = sizeof(ULONG);
457 if (size < sizeof(ULONG))
458 return STATUS_BUFFER_TOO_SMALL;
459 if (buf)
460 *(ULONG *)buf = BLOCK_LENGTH_AES;
461 return STATUS_SUCCESS;
463 if (!strcmpW( prop, BCRYPT_CHAINING_MODE ))
465 if (size >= sizeof(BCRYPT_CHAIN_MODE_CBC))
467 memcpy(buf, BCRYPT_CHAIN_MODE_CBC, sizeof(BCRYPT_CHAIN_MODE_CBC));
468 *ret_size = sizeof(BCRYPT_CHAIN_MODE_CBC) * sizeof(WCHAR);
469 return STATUS_SUCCESS;
471 else
473 *ret_size = sizeof(BCRYPT_CHAIN_MODE_CBC) * sizeof(WCHAR);
474 return STATUS_BUFFER_TOO_SMALL;
477 if (!strcmpW( prop, BCRYPT_KEY_LENGTHS ))
479 BCRYPT_KEY_LENGTHS_STRUCT *key_lengths = (void *)buf;
480 *ret_size = sizeof(*key_lengths);
481 if (key_lengths && size < *ret_size) return STATUS_BUFFER_TOO_SMALL;
482 if (key_lengths)
484 key_lengths->dwMinLength = 128;
485 key_lengths->dwMaxLength = 256;
486 key_lengths->dwIncrement = 64;
488 return STATUS_SUCCESS;
490 break;
492 default:
493 break;
496 FIXME( "unsupported property %s\n", debugstr_w(prop) );
497 return STATUS_NOT_IMPLEMENTED;
500 static NTSTATUS get_hash_property( enum alg_id id, const WCHAR *prop, UCHAR *buf, ULONG size, ULONG *ret_size )
502 NTSTATUS status;
504 status = generic_alg_property( id, prop, buf, size, ret_size );
505 if (status == STATUS_NOT_IMPLEMENTED)
506 FIXME( "unsupported property %s\n", debugstr_w(prop) );
507 return status;
510 NTSTATUS WINAPI BCryptGetProperty( BCRYPT_HANDLE handle, LPCWSTR prop, UCHAR *buffer, ULONG count, ULONG *res, ULONG flags )
512 struct object *object = handle;
514 TRACE( "%p, %s, %p, %u, %p, %08x\n", handle, wine_dbgstr_w(prop), buffer, count, res, flags );
516 if (!object) return STATUS_INVALID_HANDLE;
517 if (!prop || !res) return STATUS_INVALID_PARAMETER;
519 switch (object->magic)
521 case MAGIC_ALG:
523 const struct algorithm *alg = (const struct algorithm *)object;
524 return get_alg_property( alg->id, prop, buffer, count, res );
526 case MAGIC_HASH:
528 const struct hash *hash = (const struct hash *)object;
529 return get_hash_property( hash->alg_id, prop, buffer, count, res );
531 default:
532 WARN( "unknown magic %08x\n", object->magic );
533 return STATUS_INVALID_HANDLE;
537 NTSTATUS WINAPI BCryptSetProperty( BCRYPT_HANDLE handle, const WCHAR *prop, UCHAR *value, ULONG size, ULONG flags )
539 FIXME( "%p, %s, %p, %u, %08x\n", handle, debugstr_w(prop), value, size, flags );
540 return STATUS_NOT_IMPLEMENTED;
543 NTSTATUS WINAPI BCryptCreateHash( BCRYPT_ALG_HANDLE algorithm, BCRYPT_HASH_HANDLE *handle, UCHAR *object, ULONG objectlen,
544 UCHAR *secret, ULONG secretlen, ULONG flags )
546 struct algorithm *alg = algorithm;
547 UCHAR buffer[MAX_HASH_BLOCK_BITS / 8] = {0};
548 struct hash *hash;
549 int block_bytes;
550 NTSTATUS status;
551 int i;
553 TRACE( "%p, %p, %p, %u, %p, %u, %08x - stub\n", algorithm, handle, object, objectlen,
554 secret, secretlen, flags );
555 if (flags)
557 FIXME( "unimplemented flags %08x\n", flags );
558 return STATUS_NOT_IMPLEMENTED;
561 if (!alg || alg->hdr.magic != MAGIC_ALG) return STATUS_INVALID_HANDLE;
562 if (object) FIXME( "ignoring object buffer\n" );
564 if (!(hash = HeapAlloc( GetProcessHeap(), 0, sizeof(*hash) ))) return STATUS_NO_MEMORY;
565 hash->hdr.magic = MAGIC_HASH;
566 hash->alg_id = alg->id;
567 hash->hmac = alg->hmac;
569 /* initialize hash */
570 if ((status = hash_init( &hash->inner, hash->alg_id ))) goto end;
571 if (!hash->hmac) goto end;
573 /* initialize hmac */
574 if ((status = hash_init( &hash->outer, hash->alg_id ))) goto end;
575 block_bytes = alg_props[hash->alg_id].block_bits / 8;
576 if (secretlen > block_bytes)
578 struct hash_impl temp;
579 if ((status = hash_init( &temp, hash->alg_id ))) goto end;
580 if ((status = hash_update( &temp, hash->alg_id, secret, secretlen ))) goto end;
581 if ((status = hash_finish( &temp, hash->alg_id, buffer,
582 alg_props[hash->alg_id].hash_length ))) goto end;
584 else
586 memcpy( buffer, secret, secretlen );
588 for (i = 0; i < block_bytes; i++) buffer[i] ^= 0x5c;
589 if ((status = hash_update( &hash->outer, hash->alg_id, buffer, block_bytes ))) goto end;
590 for (i = 0; i < block_bytes; i++) buffer[i] ^= (0x5c ^ 0x36);
591 status = hash_update( &hash->inner, hash->alg_id, buffer, block_bytes );
593 end:
594 if (status != STATUS_SUCCESS)
596 HeapFree( GetProcessHeap(), 0, hash );
597 return status;
600 *handle = hash;
601 return STATUS_SUCCESS;
604 NTSTATUS WINAPI BCryptDuplicateHash( BCRYPT_HASH_HANDLE handle, BCRYPT_HASH_HANDLE *handle_copy,
605 UCHAR *object, ULONG objectlen, ULONG flags )
607 struct hash *hash_orig = handle;
608 struct hash *hash_copy;
610 TRACE( "%p, %p, %p, %u, %u\n", handle, handle_copy, object, objectlen, flags );
612 if (!hash_orig || hash_orig->hdr.magic != MAGIC_HASH) return STATUS_INVALID_HANDLE;
613 if (!handle_copy) return STATUS_INVALID_PARAMETER;
614 if (object) FIXME( "ignoring object buffer\n" );
616 if (!(hash_copy = HeapAlloc( GetProcessHeap(), 0, sizeof(*hash_copy) )))
617 return STATUS_NO_MEMORY;
619 memcpy( hash_copy, hash_orig, sizeof(*hash_orig) );
621 *handle_copy = hash_copy;
622 return STATUS_SUCCESS;
625 NTSTATUS WINAPI BCryptDestroyHash( BCRYPT_HASH_HANDLE handle )
627 struct hash *hash = handle;
629 TRACE( "%p\n", handle );
631 if (!hash || hash->hdr.magic != MAGIC_HASH) return STATUS_INVALID_HANDLE;
632 HeapFree( GetProcessHeap(), 0, hash );
633 return STATUS_SUCCESS;
636 NTSTATUS WINAPI BCryptHashData( BCRYPT_HASH_HANDLE handle, UCHAR *input, ULONG size, ULONG flags )
638 struct hash *hash = handle;
640 TRACE( "%p, %p, %u, %08x\n", handle, input, size, flags );
642 if (!hash || hash->hdr.magic != MAGIC_HASH) return STATUS_INVALID_HANDLE;
643 if (!input) return STATUS_SUCCESS;
645 return hash_update( &hash->inner, hash->alg_id, input, size );
648 NTSTATUS WINAPI BCryptFinishHash( BCRYPT_HASH_HANDLE handle, UCHAR *output, ULONG size, ULONG flags )
650 UCHAR buffer[MAX_HASH_OUTPUT_BYTES];
651 struct hash *hash = handle;
652 NTSTATUS status;
653 int hash_length;
655 TRACE( "%p, %p, %u, %08x\n", handle, output, size, flags );
657 if (!hash || hash->hdr.magic != MAGIC_HASH) return STATUS_INVALID_HANDLE;
658 if (!output) return STATUS_INVALID_PARAMETER;
660 if (!hash->hmac)
661 return hash_finish( &hash->inner, hash->alg_id, output, size );
663 hash_length = alg_props[hash->alg_id].hash_length;
664 if ((status = hash_finish( &hash->inner, hash->alg_id, buffer, hash_length ))) return status;
665 if ((status = hash_update( &hash->outer, hash->alg_id, buffer, hash_length ))) return status;
666 return hash_finish( &hash->outer, hash->alg_id, output, size );
669 NTSTATUS WINAPI BCryptHash( BCRYPT_ALG_HANDLE algorithm, UCHAR *secret, ULONG secretlen,
670 UCHAR *input, ULONG inputlen, UCHAR *output, ULONG outputlen )
672 NTSTATUS status;
673 BCRYPT_HASH_HANDLE handle;
675 TRACE( "%p, %p, %u, %p, %u, %p, %u\n", algorithm, secret, secretlen,
676 input, inputlen, output, outputlen );
678 status = BCryptCreateHash( algorithm, &handle, NULL, 0, secret, secretlen, 0);
679 if (status != STATUS_SUCCESS)
681 return status;
684 status = BCryptHashData( handle, input, inputlen, 0 );
685 if (status != STATUS_SUCCESS)
687 BCryptDestroyHash( handle );
688 return status;
691 status = BCryptFinishHash( handle, output, outputlen, 0 );
692 if (status != STATUS_SUCCESS)
694 BCryptDestroyHash( handle );
695 return status;
698 return BCryptDestroyHash( handle );
701 #if defined(HAVE_GNUTLS_CIPHER_INIT) && !defined(HAVE_COMMONCRYPTO_COMMONDIGEST_H)
702 struct key
704 struct object hdr;
705 enum alg_id alg_id;
706 ULONG block_size;
707 gnutls_cipher_hd_t handle;
708 UCHAR *secret;
709 ULONG secret_len;
712 static ULONG get_block_size( enum alg_id alg )
714 ULONG ret = 0, size = sizeof(ret);
715 get_alg_property( alg, BCRYPT_BLOCK_LENGTH, (UCHAR *)&ret, sizeof(ret), &size );
716 return ret;
719 static NTSTATUS key_init( struct key *key, enum alg_id id, const UCHAR *secret, ULONG secret_len )
721 UCHAR *buffer;
723 if (!libgnutls_handle) return STATUS_INTERNAL_ERROR;
725 switch (id)
727 case ALG_ID_AES:
728 break;
730 default:
731 FIXME( "algorithm %u not supported\n", id );
732 return STATUS_NOT_SUPPORTED;
735 if (!(key->block_size = get_block_size( id ))) return STATUS_INVALID_PARAMETER;
736 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, secret_len ))) return STATUS_NO_MEMORY;
737 memcpy( buffer, secret, secret_len );
739 key->alg_id = id;
740 key->handle = 0; /* initialized on first use */
741 key->secret = buffer;
742 key->secret_len = secret_len;
744 return STATUS_SUCCESS;
747 static gnutls_cipher_algorithm_t get_gnutls_cipher( const struct key *key )
749 switch (key->alg_id)
751 case ALG_ID_AES:
752 FIXME( "handle block size and chaining mode\n" );
753 return GNUTLS_CIPHER_AES_128_CBC;
755 default:
756 FIXME( "algorithm %u not supported\n", key->alg_id );
757 return GNUTLS_CIPHER_UNKNOWN;
761 static NTSTATUS key_set_params( struct key *key, UCHAR *iv, ULONG iv_len )
763 gnutls_cipher_algorithm_t cipher;
764 gnutls_datum_t secret, vector;
765 int ret;
767 if (key->handle)
769 pgnutls_cipher_deinit( key->handle );
770 key->handle = NULL;
773 if ((cipher = get_gnutls_cipher( key )) == GNUTLS_CIPHER_UNKNOWN)
774 return STATUS_NOT_SUPPORTED;
776 secret.data = key->secret;
777 secret.size = key->secret_len;
778 if (iv)
780 vector.data = iv;
781 vector.size = iv_len;
784 if ((ret = pgnutls_cipher_init( &key->handle, cipher, &secret, iv ? &vector : NULL )))
786 pgnutls_perror( ret );
787 return STATUS_INTERNAL_ERROR;
790 return STATUS_SUCCESS;
793 static NTSTATUS key_encrypt( struct key *key, const UCHAR *input, ULONG input_len, UCHAR *output,
794 ULONG output_len )
796 int ret;
798 if ((ret = pgnutls_cipher_encrypt2( key->handle, input, input_len, output, output_len )))
800 pgnutls_perror( ret );
801 return STATUS_INTERNAL_ERROR;
804 return STATUS_SUCCESS;
807 static NTSTATUS key_decrypt( struct key *key, const UCHAR *input, ULONG input_len, UCHAR *output,
808 ULONG output_len )
810 int ret;
812 if ((ret = pgnutls_cipher_decrypt2( key->handle, input, input_len, output, output_len )))
814 pgnutls_perror( ret );
815 return STATUS_INTERNAL_ERROR;
818 return STATUS_SUCCESS;
821 static NTSTATUS key_destroy( struct key *key )
823 if (key->handle) pgnutls_cipher_deinit( key->handle );
824 HeapFree( GetProcessHeap(), 0, key->secret );
825 HeapFree( GetProcessHeap(), 0, key );
826 return STATUS_SUCCESS;
828 #else
829 struct key
831 struct object hdr;
832 ULONG block_size;
835 static NTSTATUS key_init( struct key *key, enum alg_id id, const UCHAR *secret, ULONG secret_len )
837 ERR( "support for keys not available at build time\n" );
838 return STATUS_NOT_IMPLEMENTED;
841 static NTSTATUS key_set_params( struct key *key, UCHAR *iv, ULONG iv_len )
843 ERR( "support for keys not available at build time\n" );
844 return STATUS_NOT_IMPLEMENTED;
847 static NTSTATUS key_encrypt( struct key *key, const UCHAR *input, ULONG input_len, UCHAR *output,
848 ULONG output_len )
850 ERR( "support for keys not available at build time\n" );
851 return STATUS_NOT_IMPLEMENTED;
854 static NTSTATUS key_decrypt( struct key *key, const UCHAR *input, ULONG input_len, UCHAR *output,
855 ULONG output_len )
857 ERR( "support for keys not available at build time\n" );
858 return STATUS_NOT_IMPLEMENTED;
861 static NTSTATUS key_destroy( struct key *key )
863 ERR( "support for keys not available at build time\n" );
864 return STATUS_NOT_IMPLEMENTED;
866 #endif
868 NTSTATUS WINAPI BCryptGenerateSymmetricKey( BCRYPT_ALG_HANDLE algorithm, BCRYPT_KEY_HANDLE *handle,
869 UCHAR *object, ULONG object_len, UCHAR *secret, ULONG secret_len,
870 ULONG flags )
872 struct algorithm *alg = algorithm;
873 struct key *key;
874 NTSTATUS status;
876 TRACE( "%p, %p, %p, %u, %p, %u, %08x\n", algorithm, handle, object, object_len, secret, secret_len, flags );
878 if (!alg || alg->hdr.magic != MAGIC_ALG) return STATUS_INVALID_HANDLE;
879 if (object) FIXME( "ignoring object buffer\n" );
881 if (!(key = HeapAlloc( GetProcessHeap(), 0, sizeof(*key) ))) return STATUS_NO_MEMORY;
882 key->hdr.magic = MAGIC_KEY;
884 if ((status = key_init( key, alg->id, secret, secret_len )))
886 HeapFree( GetProcessHeap(), 0, key );
887 return status;
890 *handle = key;
891 return STATUS_SUCCESS;
894 NTSTATUS WINAPI BCryptDestroyKey( BCRYPT_KEY_HANDLE handle )
896 struct key *key = handle;
898 TRACE( "%p\n", handle );
900 if (!key || key->hdr.magic != MAGIC_KEY) return STATUS_INVALID_HANDLE;
901 return key_destroy( key );
904 NTSTATUS WINAPI BCryptEncrypt( BCRYPT_KEY_HANDLE handle, UCHAR *input, ULONG input_len,
905 void *padding, UCHAR *iv, ULONG iv_len, UCHAR *output,
906 ULONG output_len, ULONG *ret_len, ULONG flags )
908 struct key *key = handle;
909 ULONG bytes_left = input_len;
910 UCHAR *buf, *src, *dst;
911 NTSTATUS status;
913 TRACE( "%p, %p, %u, %p, %p, %u, %p, %u, %p, %08x\n", handle, input, input_len,
914 padding, iv, iv_len, output, output_len, ret_len, flags );
916 if (!key || key->hdr.magic != MAGIC_KEY) return STATUS_INVALID_HANDLE;
917 if (padding)
919 FIXME( "padding info not implemented\n" );
920 return STATUS_NOT_IMPLEMENTED;
922 if (flags & ~BCRYPT_BLOCK_PADDING)
924 FIXME( "flags %08x not implemented\n", flags );
925 return STATUS_NOT_IMPLEMENTED;
928 if ((status = key_set_params( key, iv, iv_len ))) return status;
930 *ret_len = input_len;
932 if (flags & BCRYPT_BLOCK_PADDING)
933 *ret_len = (input_len + key->block_size) & ~(key->block_size - 1);
934 else if (input_len & (key->block_size - 1))
935 return STATUS_INVALID_BUFFER_SIZE;
937 if (!output) return STATUS_SUCCESS;
938 if (output_len < *ret_len) return STATUS_BUFFER_TOO_SMALL;
940 src = input;
941 dst = output;
942 while (bytes_left >= key->block_size)
944 if ((status = key_encrypt( key, src, key->block_size, dst, key->block_size ))) return status;
945 bytes_left -= key->block_size;
946 src += key->block_size;
947 dst += key->block_size;
950 if (flags & BCRYPT_BLOCK_PADDING)
952 if (!(buf = HeapAlloc( GetProcessHeap(), 0, key->block_size ))) return STATUS_NO_MEMORY;
953 memcpy( buf, src, bytes_left );
954 memset( buf + bytes_left, key->block_size - bytes_left, key->block_size - bytes_left );
955 status = key_encrypt( key, buf, key->block_size, dst, key->block_size );
956 HeapFree( GetProcessHeap(), 0, buf );
959 return status;
962 NTSTATUS WINAPI BCryptDecrypt( BCRYPT_KEY_HANDLE handle, UCHAR *input, ULONG input_len,
963 void *padding, UCHAR *iv, ULONG iv_len, UCHAR *output,
964 ULONG output_len, ULONG *ret_len, ULONG flags )
966 struct key *key = handle;
967 ULONG bytes_left = input_len;
968 UCHAR *buf, *src, *dst;
969 NTSTATUS status;
971 TRACE( "%p, %p, %u, %p, %p, %u, %p, %u, %p, %08x\n", handle, input, input_len,
972 padding, iv, iv_len, output, output_len, ret_len, flags );
974 if (!key || key->hdr.magic != MAGIC_KEY) return STATUS_INVALID_HANDLE;
975 if (padding)
977 FIXME( "padding info not implemented\n" );
978 return STATUS_NOT_IMPLEMENTED;
980 if (flags & ~BCRYPT_BLOCK_PADDING)
982 FIXME( "flags %08x not supported\n", flags );
983 return STATUS_NOT_IMPLEMENTED;
986 if ((status = key_set_params( key, iv, iv_len ))) return status;
988 *ret_len = input_len;
990 if (input_len & (key->block_size - 1)) return STATUS_INVALID_BUFFER_SIZE;
991 if (!output) return STATUS_SUCCESS;
992 if (flags & BCRYPT_BLOCK_PADDING)
994 if (output_len + key->block_size < *ret_len) return STATUS_BUFFER_TOO_SMALL;
995 if (input_len < key->block_size) return STATUS_BUFFER_TOO_SMALL;
996 bytes_left -= key->block_size;
998 else if (output_len < *ret_len)
999 return STATUS_BUFFER_TOO_SMALL;
1001 src = input;
1002 dst = output;
1003 while (bytes_left >= key->block_size)
1005 if ((status = key_decrypt( key, src, key->block_size, dst, key->block_size ))) return status;
1006 bytes_left -= key->block_size;
1007 src += key->block_size;
1008 dst += key->block_size;
1011 if (flags & BCRYPT_BLOCK_PADDING)
1013 if (!(buf = HeapAlloc( GetProcessHeap(), 0, key->block_size ))) return STATUS_NO_MEMORY;
1014 status = key_decrypt( key, src, key->block_size, buf, key->block_size );
1015 if (!status && buf[ key->block_size - 1 ] <= key->block_size)
1017 *ret_len -= buf[ key->block_size - 1 ];
1018 if (output_len < *ret_len) status = STATUS_BUFFER_TOO_SMALL;
1019 else memcpy( dst, buf, key->block_size - buf[ key->block_size - 1 ] );
1021 else
1022 status = STATUS_UNSUCCESSFUL; /* FIXME: invalid padding */
1023 HeapFree( GetProcessHeap(), 0, buf );
1026 return status;
1029 BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
1031 switch (reason)
1033 case DLL_PROCESS_ATTACH:
1034 instance = hinst;
1035 DisableThreadLibraryCalls( hinst );
1036 #if defined(HAVE_GNUTLS_CIPHER_INIT) && !defined(HAVE_COMMONCRYPTO_COMMONDIGEST_H)
1037 gnutls_initialize();
1038 #endif
1039 break;
1041 case DLL_PROCESS_DETACH:
1042 if (reserved) break;
1043 #if defined(HAVE_GNUTLS_CIPHER_INIT) && !defined(HAVE_COMMONCRYPTO_COMMONDIGEST_H)
1044 gnutls_uninitialize();
1045 #endif
1046 break;
1048 return TRUE;