bcrypt: Add support for auth data in AES GCM mode.
[wine.git] / dlls / bcrypt / bcrypt_main.c
blobb21dc1fd18c72b1e7481127dc0d07cad5619d300
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_COMMONCRYPTOR_H
25 #include <AvailabilityMacros.h>
26 #include <CommonCrypto/CommonCryptor.h>
27 #elif defined(HAVE_GNUTLS_CIPHER_INIT)
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/heap.h"
43 #include "wine/library.h"
44 #include "wine/unicode.h"
46 WINE_DEFAULT_DEBUG_CHANNEL(bcrypt);
48 static HINSTANCE instance;
50 #if defined(HAVE_GNUTLS_CIPHER_INIT) && !defined(HAVE_COMMONCRYPTO_COMMONCRYPTOR_H)
51 WINE_DECLARE_DEBUG_CHANNEL(winediag);
53 /* Not present in gnutls version < 3.0 */
54 static int (*pgnutls_cipher_tag)(gnutls_cipher_hd_t handle, void * tag, size_t tag_size);
55 static int (*pgnutls_cipher_add_auth)(gnutls_cipher_hd_t handle, const void *ptext, size_t ptext_size);
57 static void *libgnutls_handle;
58 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
59 MAKE_FUNCPTR(gnutls_cipher_decrypt2);
60 MAKE_FUNCPTR(gnutls_cipher_deinit);
61 MAKE_FUNCPTR(gnutls_cipher_encrypt2);
62 MAKE_FUNCPTR(gnutls_cipher_init);
63 MAKE_FUNCPTR(gnutls_global_deinit);
64 MAKE_FUNCPTR(gnutls_global_init);
65 MAKE_FUNCPTR(gnutls_global_set_log_function);
66 MAKE_FUNCPTR(gnutls_global_set_log_level);
67 MAKE_FUNCPTR(gnutls_perror);
68 #undef MAKE_FUNCPTR
70 #if GNUTLS_VERSION_MAJOR < 3
71 #define GNUTLS_CIPHER_AES_192_CBC 92
72 #define GNUTLS_CIPHER_AES_128_GCM 93
73 #define GNUTLS_CIPHER_AES_256_GCM 94
74 #endif
76 static int compat_gnutls_cipher_tag(gnutls_cipher_hd_t handle, void *tag, size_t tag_size)
78 return GNUTLS_E_UNKNOWN_CIPHER_TYPE;
81 static int compat_gnutls_cipher_add_auth(gnutls_cipher_hd_t handle, const void *ptext, size_t ptext_size)
83 return GNUTLS_E_UNKNOWN_CIPHER_TYPE;
86 static void gnutls_log( int level, const char *msg )
88 TRACE( "<%d> %s", level, msg );
91 static BOOL gnutls_initialize(void)
93 int ret;
95 if (!(libgnutls_handle = wine_dlopen( SONAME_LIBGNUTLS, RTLD_NOW, NULL, 0 )))
97 ERR_(winediag)( "failed to load libgnutls, no support for encryption\n" );
98 return FALSE;
101 #define LOAD_FUNCPTR(f) \
102 if (!(p##f = wine_dlsym( libgnutls_handle, #f, NULL, 0 ))) \
104 ERR( "failed to load %s\n", #f ); \
105 goto fail; \
108 LOAD_FUNCPTR(gnutls_cipher_decrypt2)
109 LOAD_FUNCPTR(gnutls_cipher_deinit)
110 LOAD_FUNCPTR(gnutls_cipher_encrypt2)
111 LOAD_FUNCPTR(gnutls_cipher_init)
112 LOAD_FUNCPTR(gnutls_global_deinit)
113 LOAD_FUNCPTR(gnutls_global_init)
114 LOAD_FUNCPTR(gnutls_global_set_log_function)
115 LOAD_FUNCPTR(gnutls_global_set_log_level)
116 LOAD_FUNCPTR(gnutls_perror)
117 #undef LOAD_FUNCPTR
119 if (!(pgnutls_cipher_tag = wine_dlsym( libgnutls_handle, "gnutls_cipher_tag", NULL, 0 )))
121 WARN("gnutls_cipher_tag not found\n");
122 pgnutls_cipher_tag = compat_gnutls_cipher_tag;
124 if (!(pgnutls_cipher_add_auth = wine_dlsym( libgnutls_handle, "gnutls_cipher_add_auth", NULL, 0 )))
126 WARN("gnutls_cipher_add_auth not found\n");
127 pgnutls_cipher_add_auth = compat_gnutls_cipher_add_auth;
130 if ((ret = pgnutls_global_init()) != GNUTLS_E_SUCCESS)
132 pgnutls_perror( ret );
133 goto fail;
136 if (TRACE_ON( bcrypt ))
138 pgnutls_global_set_log_level( 4 );
139 pgnutls_global_set_log_function( gnutls_log );
142 return TRUE;
144 fail:
145 wine_dlclose( libgnutls_handle, NULL, 0 );
146 libgnutls_handle = NULL;
147 return FALSE;
150 static void gnutls_uninitialize(void)
152 pgnutls_global_deinit();
153 wine_dlclose( libgnutls_handle, NULL, 0 );
154 libgnutls_handle = NULL;
156 #endif /* HAVE_GNUTLS_CIPHER_INIT && !HAVE_COMMONCRYPTO_COMMONCRYPTOR_H */
158 NTSTATUS WINAPI BCryptAddContextFunction(ULONG table, LPCWSTR context, ULONG iface, LPCWSTR function, ULONG pos)
160 FIXME("%08x, %s, %08x, %s, %u: stub\n", table, debugstr_w(context), iface, debugstr_w(function), pos);
161 return STATUS_SUCCESS;
164 NTSTATUS WINAPI BCryptAddContextFunctionProvider(ULONG table, LPCWSTR context, ULONG iface, LPCWSTR function, LPCWSTR provider, ULONG pos)
166 FIXME("%08x, %s, %08x, %s, %s, %u: stub\n", table, debugstr_w(context), iface, debugstr_w(function), debugstr_w(provider), pos);
167 return STATUS_SUCCESS;
170 NTSTATUS WINAPI BCryptRemoveContextFunction(ULONG table, LPCWSTR context, ULONG iface, LPCWSTR function)
172 FIXME("%08x, %s, %08x, %s: stub\n", table, debugstr_w(context), iface, debugstr_w(function));
173 return STATUS_NOT_IMPLEMENTED;
176 NTSTATUS WINAPI BCryptRemoveContextFunctionProvider(ULONG table, LPCWSTR context, ULONG iface, LPCWSTR function, LPCWSTR provider)
178 FIXME("%08x, %s, %08x, %s, %s: stub\n", table, debugstr_w(context), iface, debugstr_w(function), debugstr_w(provider));
179 return STATUS_NOT_IMPLEMENTED;
182 NTSTATUS WINAPI BCryptRegisterProvider(LPCWSTR provider, ULONG flags, PCRYPT_PROVIDER_REG reg)
184 FIXME("%s, %08x, %p: stub\n", debugstr_w(provider), flags, reg);
185 return STATUS_SUCCESS;
188 NTSTATUS WINAPI BCryptUnregisterProvider(LPCWSTR provider)
190 FIXME("%s: stub\n", debugstr_w(provider));
191 return STATUS_NOT_IMPLEMENTED;
194 NTSTATUS WINAPI BCryptEnumAlgorithms(ULONG dwAlgOperations, ULONG *pAlgCount,
195 BCRYPT_ALGORITHM_IDENTIFIER **ppAlgList, ULONG dwFlags)
197 FIXME("%08x, %p, %p, %08x - stub\n", dwAlgOperations, pAlgCount, ppAlgList, dwFlags);
199 *ppAlgList=NULL;
200 *pAlgCount=0;
202 return STATUS_NOT_IMPLEMENTED;
205 #define MAGIC_ALG (('A' << 24) | ('L' << 16) | ('G' << 8) | '0')
206 #define MAGIC_HASH (('H' << 24) | ('A' << 16) | ('S' << 8) | 'H')
207 #define MAGIC_KEY (('K' << 24) | ('E' << 16) | ('Y' << 8) | '0')
208 struct object
210 ULONG magic;
213 enum alg_id
215 ALG_ID_AES,
216 ALG_ID_MD2,
217 ALG_ID_MD4,
218 ALG_ID_MD5,
219 ALG_ID_RNG,
220 ALG_ID_SHA1,
221 ALG_ID_SHA256,
222 ALG_ID_SHA384,
223 ALG_ID_SHA512
226 enum mode_id
228 MODE_ID_CBC,
229 MODE_ID_GCM
232 #define MAX_HASH_OUTPUT_BYTES 64
233 #define MAX_HASH_BLOCK_BITS 1024
235 static const struct {
236 ULONG object_length;
237 ULONG hash_length;
238 ULONG block_bits;
239 const WCHAR *alg_name;
240 } alg_props[] = {
241 /* ALG_ID_AES */ { 654, 0, 0, BCRYPT_AES_ALGORITHM },
242 /* ALG_ID_MD2 */ { 270, 16, 128, BCRYPT_MD2_ALGORITHM },
243 /* ALG_ID_MD4 */ { 270, 16, 512, BCRYPT_MD4_ALGORITHM },
244 /* ALG_ID_MD5 */ { 274, 16, 512, BCRYPT_MD5_ALGORITHM },
245 /* ALG_ID_RNG */ { 0, 0, 0, BCRYPT_RNG_ALGORITHM },
246 /* ALG_ID_SHA1 */ { 278, 20, 512, BCRYPT_SHA1_ALGORITHM },
247 /* ALG_ID_SHA256 */ { 286, 32, 512, BCRYPT_SHA256_ALGORITHM },
248 /* ALG_ID_SHA384 */ { 382, 48, 1024, BCRYPT_SHA384_ALGORITHM },
249 /* ALG_ID_SHA512 */ { 382, 64, 1024, BCRYPT_SHA512_ALGORITHM }
252 struct algorithm
254 struct object hdr;
255 enum alg_id id;
256 enum mode_id mode;
257 BOOL hmac;
260 NTSTATUS WINAPI BCryptGenRandom(BCRYPT_ALG_HANDLE handle, UCHAR *buffer, ULONG count, ULONG flags)
262 const DWORD supported_flags = BCRYPT_USE_SYSTEM_PREFERRED_RNG;
263 struct algorithm *algorithm = handle;
265 TRACE("%p, %p, %u, %08x - semi-stub\n", handle, buffer, count, flags);
267 if (!algorithm)
269 /* It's valid to call without an algorithm if BCRYPT_USE_SYSTEM_PREFERRED_RNG
270 * is set. In this case the preferred system RNG is used.
272 if (!(flags & BCRYPT_USE_SYSTEM_PREFERRED_RNG))
273 return STATUS_INVALID_HANDLE;
275 else if (algorithm->hdr.magic != MAGIC_ALG || algorithm->id != ALG_ID_RNG)
276 return STATUS_INVALID_HANDLE;
278 if (!buffer)
279 return STATUS_INVALID_PARAMETER;
281 if (flags & ~supported_flags)
282 FIXME("unsupported flags %08x\n", flags & ~supported_flags);
284 if (algorithm)
285 FIXME("ignoring selected algorithm\n");
287 /* When zero bytes are requested the function returns success too. */
288 if (!count)
289 return STATUS_SUCCESS;
291 if (algorithm || (flags & BCRYPT_USE_SYSTEM_PREFERRED_RNG))
293 if (RtlGenRandom(buffer, count))
294 return STATUS_SUCCESS;
297 FIXME("called with unsupported parameters, returning error\n");
298 return STATUS_NOT_IMPLEMENTED;
301 NTSTATUS WINAPI BCryptOpenAlgorithmProvider( BCRYPT_ALG_HANDLE *handle, LPCWSTR id, LPCWSTR implementation, DWORD flags )
303 const DWORD supported_flags = BCRYPT_ALG_HANDLE_HMAC_FLAG;
304 struct algorithm *alg;
305 enum alg_id alg_id;
307 TRACE( "%p, %s, %s, %08x\n", handle, wine_dbgstr_w(id), wine_dbgstr_w(implementation), flags );
309 if (!handle || !id) return STATUS_INVALID_PARAMETER;
310 if (flags & ~supported_flags)
312 FIXME( "unsupported flags %08x\n", flags & ~supported_flags);
313 return STATUS_NOT_IMPLEMENTED;
316 if (!strcmpW( id, BCRYPT_AES_ALGORITHM )) alg_id = ALG_ID_AES;
317 else if (!strcmpW( id, BCRYPT_MD2_ALGORITHM )) alg_id = ALG_ID_MD2;
318 else if (!strcmpW( id, BCRYPT_MD4_ALGORITHM )) alg_id = ALG_ID_MD4;
319 else if (!strcmpW( id, BCRYPT_MD5_ALGORITHM )) alg_id = ALG_ID_MD5;
320 else if (!strcmpW( id, BCRYPT_RNG_ALGORITHM )) alg_id = ALG_ID_RNG;
321 else if (!strcmpW( id, BCRYPT_SHA1_ALGORITHM )) alg_id = ALG_ID_SHA1;
322 else if (!strcmpW( id, BCRYPT_SHA256_ALGORITHM )) alg_id = ALG_ID_SHA256;
323 else if (!strcmpW( id, BCRYPT_SHA384_ALGORITHM )) alg_id = ALG_ID_SHA384;
324 else if (!strcmpW( id, BCRYPT_SHA512_ALGORITHM )) alg_id = ALG_ID_SHA512;
325 else
327 FIXME( "algorithm %s not supported\n", debugstr_w(id) );
328 return STATUS_NOT_IMPLEMENTED;
330 if (implementation && strcmpW( implementation, MS_PRIMITIVE_PROVIDER ))
332 FIXME( "implementation %s not supported\n", debugstr_w(implementation) );
333 return STATUS_NOT_IMPLEMENTED;
336 if (!(alg = heap_alloc( sizeof(*alg) ))) return STATUS_NO_MEMORY;
337 alg->hdr.magic = MAGIC_ALG;
338 alg->id = alg_id;
339 alg->mode = MODE_ID_CBC;
340 alg->hmac = flags & BCRYPT_ALG_HANDLE_HMAC_FLAG;
342 *handle = alg;
343 return STATUS_SUCCESS;
346 NTSTATUS WINAPI BCryptCloseAlgorithmProvider( BCRYPT_ALG_HANDLE handle, DWORD flags )
348 struct algorithm *alg = handle;
350 TRACE( "%p, %08x\n", handle, flags );
352 if (!alg || alg->hdr.magic != MAGIC_ALG) return STATUS_INVALID_HANDLE;
353 heap_free( alg );
354 return STATUS_SUCCESS;
357 NTSTATUS WINAPI BCryptGetFipsAlgorithmMode(BOOLEAN *enabled)
359 FIXME("%p - semi-stub\n", enabled);
361 if (!enabled)
362 return STATUS_INVALID_PARAMETER;
364 *enabled = FALSE;
365 return STATUS_SUCCESS;
368 struct hash_impl
370 union
372 MD2_CTX md2;
373 MD4_CTX md4;
374 MD5_CTX md5;
375 SHA_CTX sha1;
376 SHA256_CTX sha256;
377 SHA512_CTX sha512;
378 } u;
381 static NTSTATUS hash_init( struct hash_impl *hash, enum alg_id alg_id )
383 switch (alg_id)
385 case ALG_ID_MD2:
386 md2_init( &hash->u.md2 );
387 break;
389 case ALG_ID_MD4:
390 MD4Init( &hash->u.md4 );
391 break;
393 case ALG_ID_MD5:
394 MD5Init( &hash->u.md5 );
395 break;
397 case ALG_ID_SHA1:
398 A_SHAInit( &hash->u.sha1 );
399 break;
401 case ALG_ID_SHA256:
402 sha256_init( &hash->u.sha256 );
403 break;
405 case ALG_ID_SHA384:
406 sha384_init( &hash->u.sha512 );
407 break;
409 case ALG_ID_SHA512:
410 sha512_init( &hash->u.sha512 );
411 break;
413 default:
414 ERR( "unhandled id %u\n", alg_id );
415 return STATUS_NOT_IMPLEMENTED;
417 return STATUS_SUCCESS;
420 static NTSTATUS hash_update( struct hash_impl *hash, enum alg_id alg_id,
421 UCHAR *input, ULONG size )
423 switch (alg_id)
425 case ALG_ID_MD2:
426 md2_update( &hash->u.md2, input, size );
427 break;
429 case ALG_ID_MD4:
430 MD4Update( &hash->u.md4, input, size );
431 break;
433 case ALG_ID_MD5:
434 MD5Update( &hash->u.md5, input, size );
435 break;
437 case ALG_ID_SHA1:
438 A_SHAUpdate( &hash->u.sha1, input, size );
439 break;
441 case ALG_ID_SHA256:
442 sha256_update( &hash->u.sha256, input, size );
443 break;
445 case ALG_ID_SHA384:
446 sha384_update( &hash->u.sha512, input, size );
447 break;
449 case ALG_ID_SHA512:
450 sha512_update( &hash->u.sha512, input, size );
451 break;
453 default:
454 ERR( "unhandled id %u\n", alg_id );
455 return STATUS_NOT_IMPLEMENTED;
457 return STATUS_SUCCESS;
460 static NTSTATUS hash_finish( struct hash_impl *hash, enum alg_id alg_id,
461 UCHAR *output, ULONG size )
463 switch (alg_id)
465 case ALG_ID_MD2:
466 md2_finalize( &hash->u.md2, output );
467 break;
469 case ALG_ID_MD4:
470 MD4Final( &hash->u.md4 );
471 memcpy( output, hash->u.md4.digest, 16 );
472 break;
474 case ALG_ID_MD5:
475 MD5Final( &hash->u.md5 );
476 memcpy( output, hash->u.md5.digest, 16 );
477 break;
479 case ALG_ID_SHA1:
480 A_SHAFinal( &hash->u.sha1, (ULONG *)output );
481 break;
483 case ALG_ID_SHA256:
484 sha256_finalize( &hash->u.sha256, output );
485 break;
487 case ALG_ID_SHA384:
488 sha384_finalize( &hash->u.sha512, output );
489 break;
491 case ALG_ID_SHA512:
492 sha512_finalize( &hash->u.sha512, output );
493 break;
495 default:
496 ERR( "unhandled id %u\n", alg_id );
497 return STATUS_NOT_IMPLEMENTED;
499 return STATUS_SUCCESS;
502 struct hash
504 struct object hdr;
505 enum alg_id alg_id;
506 BOOL hmac;
507 struct hash_impl outer;
508 struct hash_impl inner;
511 #define BLOCK_LENGTH_AES 16
513 static NTSTATUS generic_alg_property( enum alg_id id, const WCHAR *prop, UCHAR *buf, ULONG size, ULONG *ret_size )
515 if (!strcmpW( prop, BCRYPT_OBJECT_LENGTH ))
517 if (!alg_props[id].object_length)
518 return STATUS_NOT_SUPPORTED;
519 *ret_size = sizeof(ULONG);
520 if (size < sizeof(ULONG))
521 return STATUS_BUFFER_TOO_SMALL;
522 if (buf)
523 *(ULONG *)buf = alg_props[id].object_length;
524 return STATUS_SUCCESS;
527 if (!strcmpW( prop, BCRYPT_HASH_LENGTH ))
529 if (!alg_props[id].hash_length)
530 return STATUS_NOT_SUPPORTED;
531 *ret_size = sizeof(ULONG);
532 if (size < sizeof(ULONG))
533 return STATUS_BUFFER_TOO_SMALL;
534 if(buf)
535 *(ULONG*)buf = alg_props[id].hash_length;
536 return STATUS_SUCCESS;
539 if (!strcmpW( prop, BCRYPT_ALGORITHM_NAME ))
541 *ret_size = (strlenW(alg_props[id].alg_name)+1)*sizeof(WCHAR);
542 if (size < *ret_size)
543 return STATUS_BUFFER_TOO_SMALL;
544 if(buf)
545 memcpy(buf, alg_props[id].alg_name, *ret_size);
546 return STATUS_SUCCESS;
549 return STATUS_NOT_IMPLEMENTED;
552 static NTSTATUS get_alg_property( const struct algorithm *alg, const WCHAR *prop, UCHAR *buf, ULONG size, ULONG *ret_size )
554 NTSTATUS status;
556 status = generic_alg_property( alg->id, prop, buf, size, ret_size );
557 if (status != STATUS_NOT_IMPLEMENTED)
558 return status;
560 switch (alg->id)
562 case ALG_ID_AES:
563 if (!strcmpW( prop, BCRYPT_BLOCK_LENGTH ))
565 *ret_size = sizeof(ULONG);
566 if (size < sizeof(ULONG))
567 return STATUS_BUFFER_TOO_SMALL;
568 if (buf)
569 *(ULONG *)buf = BLOCK_LENGTH_AES;
570 return STATUS_SUCCESS;
572 if (!strcmpW( prop, BCRYPT_CHAINING_MODE ))
574 const WCHAR *mode;
575 switch (alg->mode)
577 case MODE_ID_GCM: mode = BCRYPT_CHAIN_MODE_GCM; break;
578 case MODE_ID_CBC: mode = BCRYPT_CHAIN_MODE_CBC; break;
579 default: return STATUS_NOT_IMPLEMENTED;
582 *ret_size = 64;
583 if (size < *ret_size) return STATUS_BUFFER_TOO_SMALL;
584 memcpy( buf, mode, (strlenW(mode) + 1) * sizeof(WCHAR) );
585 return STATUS_SUCCESS;
587 if (!strcmpW( prop, BCRYPT_KEY_LENGTHS ))
589 BCRYPT_KEY_LENGTHS_STRUCT *key_lengths = (void *)buf;
590 *ret_size = sizeof(*key_lengths);
591 if (key_lengths && size < *ret_size) return STATUS_BUFFER_TOO_SMALL;
592 if (key_lengths)
594 key_lengths->dwMinLength = 128;
595 key_lengths->dwMaxLength = 256;
596 key_lengths->dwIncrement = 64;
598 return STATUS_SUCCESS;
600 if (!strcmpW( prop, BCRYPT_AUTH_TAG_LENGTH ))
602 BCRYPT_AUTH_TAG_LENGTHS_STRUCT *tag_length = (void *)buf;
603 if (alg->mode != MODE_ID_GCM) return STATUS_NOT_SUPPORTED;
604 *ret_size = sizeof(*tag_length);
605 if (tag_length && size < *ret_size) return STATUS_BUFFER_TOO_SMALL;
606 if (tag_length)
608 tag_length->dwMinLength = 12;
609 tag_length->dwMaxLength = 16;
610 tag_length->dwIncrement = 1;
612 return STATUS_SUCCESS;
614 break;
616 default:
617 break;
620 FIXME( "unsupported property %s\n", debugstr_w(prop) );
621 return STATUS_NOT_IMPLEMENTED;
624 static NTSTATUS set_alg_property( struct algorithm *alg, const WCHAR *prop, UCHAR *value, ULONG size, ULONG flags )
626 switch (alg->id)
628 case ALG_ID_AES:
629 if (!strcmpW( prop, BCRYPT_CHAINING_MODE ))
631 if (!strncmpW( (WCHAR *)value, BCRYPT_CHAIN_MODE_CBC, size ))
633 alg->mode = MODE_ID_CBC;
634 return STATUS_SUCCESS;
636 else if (!strncmpW( (WCHAR *)value, BCRYPT_CHAIN_MODE_GCM, size ))
638 alg->mode = MODE_ID_GCM;
639 return STATUS_SUCCESS;
641 else
643 FIXME( "unsupported mode %s\n", debugstr_wn( (WCHAR *)value, size ) );
644 return STATUS_NOT_IMPLEMENTED;
647 FIXME( "unsupported aes algorithm property %s\n", debugstr_w(prop) );
648 return STATUS_NOT_IMPLEMENTED;
650 default:
651 FIXME( "unsupported algorithm %u\n", alg->id );
652 return STATUS_NOT_IMPLEMENTED;
656 static NTSTATUS get_hash_property( const struct hash *hash, const WCHAR *prop, UCHAR *buf, ULONG size, ULONG *ret_size )
658 NTSTATUS status;
660 status = generic_alg_property( hash->alg_id, prop, buf, size, ret_size );
661 if (status == STATUS_NOT_IMPLEMENTED)
662 FIXME( "unsupported property %s\n", debugstr_w(prop) );
663 return status;
666 NTSTATUS WINAPI BCryptGetProperty( BCRYPT_HANDLE handle, LPCWSTR prop, UCHAR *buffer, ULONG count, ULONG *res, ULONG flags )
668 struct object *object = handle;
670 TRACE( "%p, %s, %p, %u, %p, %08x\n", handle, wine_dbgstr_w(prop), buffer, count, res, flags );
672 if (!object) return STATUS_INVALID_HANDLE;
673 if (!prop || !res) return STATUS_INVALID_PARAMETER;
675 switch (object->magic)
677 case MAGIC_ALG:
679 const struct algorithm *alg = (const struct algorithm *)object;
680 return get_alg_property( alg, prop, buffer, count, res );
682 case MAGIC_HASH:
684 const struct hash *hash = (const struct hash *)object;
685 return get_hash_property( hash, prop, buffer, count, res );
687 default:
688 WARN( "unknown magic %08x\n", object->magic );
689 return STATUS_INVALID_HANDLE;
693 NTSTATUS WINAPI BCryptCreateHash( BCRYPT_ALG_HANDLE algorithm, BCRYPT_HASH_HANDLE *handle, UCHAR *object, ULONG objectlen,
694 UCHAR *secret, ULONG secretlen, ULONG flags )
696 struct algorithm *alg = algorithm;
697 UCHAR buffer[MAX_HASH_BLOCK_BITS / 8] = {0};
698 struct hash *hash;
699 int block_bytes;
700 NTSTATUS status;
701 int i;
703 TRACE( "%p, %p, %p, %u, %p, %u, %08x - stub\n", algorithm, handle, object, objectlen,
704 secret, secretlen, flags );
705 if (flags)
707 FIXME( "unimplemented flags %08x\n", flags );
708 return STATUS_NOT_IMPLEMENTED;
711 if (!alg || alg->hdr.magic != MAGIC_ALG) return STATUS_INVALID_HANDLE;
712 if (object) FIXME( "ignoring object buffer\n" );
714 if (!(hash = heap_alloc( sizeof(*hash) ))) return STATUS_NO_MEMORY;
715 hash->hdr.magic = MAGIC_HASH;
716 hash->alg_id = alg->id;
717 hash->hmac = alg->hmac;
719 /* initialize hash */
720 if ((status = hash_init( &hash->inner, hash->alg_id ))) goto end;
721 if (!hash->hmac) goto end;
723 /* initialize hmac */
724 if ((status = hash_init( &hash->outer, hash->alg_id ))) goto end;
725 block_bytes = alg_props[hash->alg_id].block_bits / 8;
726 if (secretlen > block_bytes)
728 struct hash_impl temp;
729 if ((status = hash_init( &temp, hash->alg_id ))) goto end;
730 if ((status = hash_update( &temp, hash->alg_id, secret, secretlen ))) goto end;
731 if ((status = hash_finish( &temp, hash->alg_id, buffer,
732 alg_props[hash->alg_id].hash_length ))) goto end;
734 else
736 memcpy( buffer, secret, secretlen );
738 for (i = 0; i < block_bytes; i++) buffer[i] ^= 0x5c;
739 if ((status = hash_update( &hash->outer, hash->alg_id, buffer, block_bytes ))) goto end;
740 for (i = 0; i < block_bytes; i++) buffer[i] ^= (0x5c ^ 0x36);
741 status = hash_update( &hash->inner, hash->alg_id, buffer, block_bytes );
743 end:
744 if (status != STATUS_SUCCESS)
746 heap_free( hash );
747 return status;
750 *handle = hash;
751 return STATUS_SUCCESS;
754 NTSTATUS WINAPI BCryptDuplicateHash( BCRYPT_HASH_HANDLE handle, BCRYPT_HASH_HANDLE *handle_copy,
755 UCHAR *object, ULONG objectlen, ULONG flags )
757 struct hash *hash_orig = handle;
758 struct hash *hash_copy;
760 TRACE( "%p, %p, %p, %u, %u\n", handle, handle_copy, object, objectlen, flags );
762 if (!hash_orig || hash_orig->hdr.magic != MAGIC_HASH) return STATUS_INVALID_HANDLE;
763 if (!handle_copy) return STATUS_INVALID_PARAMETER;
764 if (object) FIXME( "ignoring object buffer\n" );
766 if (!(hash_copy = heap_alloc( sizeof(*hash_copy) )))
767 return STATUS_NO_MEMORY;
769 memcpy( hash_copy, hash_orig, sizeof(*hash_orig) );
771 *handle_copy = hash_copy;
772 return STATUS_SUCCESS;
775 NTSTATUS WINAPI BCryptDestroyHash( BCRYPT_HASH_HANDLE handle )
777 struct hash *hash = handle;
779 TRACE( "%p\n", handle );
781 if (!hash || hash->hdr.magic != MAGIC_HASH) return STATUS_INVALID_HANDLE;
782 heap_free( hash );
783 return STATUS_SUCCESS;
786 NTSTATUS WINAPI BCryptHashData( BCRYPT_HASH_HANDLE handle, UCHAR *input, ULONG size, ULONG flags )
788 struct hash *hash = handle;
790 TRACE( "%p, %p, %u, %08x\n", handle, input, size, flags );
792 if (!hash || hash->hdr.magic != MAGIC_HASH) return STATUS_INVALID_HANDLE;
793 if (!input) return STATUS_SUCCESS;
795 return hash_update( &hash->inner, hash->alg_id, input, size );
798 NTSTATUS WINAPI BCryptFinishHash( BCRYPT_HASH_HANDLE handle, UCHAR *output, ULONG size, ULONG flags )
800 UCHAR buffer[MAX_HASH_OUTPUT_BYTES];
801 struct hash *hash = handle;
802 NTSTATUS status;
803 int hash_length;
805 TRACE( "%p, %p, %u, %08x\n", handle, output, size, flags );
807 if (!hash || hash->hdr.magic != MAGIC_HASH) return STATUS_INVALID_HANDLE;
808 if (!output) return STATUS_INVALID_PARAMETER;
810 if (!hash->hmac)
811 return hash_finish( &hash->inner, hash->alg_id, output, size );
813 hash_length = alg_props[hash->alg_id].hash_length;
814 if ((status = hash_finish( &hash->inner, hash->alg_id, buffer, hash_length ))) return status;
815 if ((status = hash_update( &hash->outer, hash->alg_id, buffer, hash_length ))) return status;
816 return hash_finish( &hash->outer, hash->alg_id, output, size );
819 NTSTATUS WINAPI BCryptHash( BCRYPT_ALG_HANDLE algorithm, UCHAR *secret, ULONG secretlen,
820 UCHAR *input, ULONG inputlen, UCHAR *output, ULONG outputlen )
822 NTSTATUS status;
823 BCRYPT_HASH_HANDLE handle;
825 TRACE( "%p, %p, %u, %p, %u, %p, %u\n", algorithm, secret, secretlen,
826 input, inputlen, output, outputlen );
828 status = BCryptCreateHash( algorithm, &handle, NULL, 0, secret, secretlen, 0);
829 if (status != STATUS_SUCCESS)
831 return status;
834 status = BCryptHashData( handle, input, inputlen, 0 );
835 if (status != STATUS_SUCCESS)
837 BCryptDestroyHash( handle );
838 return status;
841 status = BCryptFinishHash( handle, output, outputlen, 0 );
842 if (status != STATUS_SUCCESS)
844 BCryptDestroyHash( handle );
845 return status;
848 return BCryptDestroyHash( handle );
851 #if defined(HAVE_GNUTLS_CIPHER_INIT) && !defined(HAVE_COMMONCRYPTO_COMMONCRYPTOR_H)
852 struct key
854 struct object hdr;
855 enum alg_id alg_id;
856 enum mode_id mode;
857 ULONG block_size;
858 gnutls_cipher_hd_t handle;
859 UCHAR *secret;
860 ULONG secret_len;
862 #elif defined(HAVE_COMMONCRYPTO_COMMONCRYPTOR_H) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
863 struct key
865 struct object hdr;
866 enum alg_id alg_id;
867 enum mode_id mode;
868 ULONG block_size;
869 CCCryptorRef ref_encrypt;
870 CCCryptorRef ref_decrypt;
871 UCHAR *secret;
872 ULONG secret_len;
874 #else
875 struct key
877 struct object hdr;
878 enum mode_id mode;
879 ULONG block_size;
881 #endif
883 #if defined(HAVE_GNUTLS_CIPHER_INIT) || defined(HAVE_COMMONCRYPTO_COMMONCRYPTOR_H) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
884 static ULONG get_block_size( struct algorithm *alg )
886 ULONG ret = 0, size = sizeof(ret);
887 get_alg_property( alg, BCRYPT_BLOCK_LENGTH, (UCHAR *)&ret, sizeof(ret), &size );
888 return ret;
891 static NTSTATUS key_export( struct key *key, const WCHAR *type, UCHAR *output, ULONG output_len, ULONG *size )
893 if (!strcmpW( type, BCRYPT_KEY_DATA_BLOB ))
895 BCRYPT_KEY_DATA_BLOB_HEADER *header = (BCRYPT_KEY_DATA_BLOB_HEADER *)output;
896 ULONG req_size = sizeof(BCRYPT_KEY_DATA_BLOB_HEADER) + key->secret_len;
898 *size = req_size;
899 if (output_len < req_size) return STATUS_BUFFER_TOO_SMALL;
901 header->dwMagic = BCRYPT_KEY_DATA_BLOB_MAGIC;
902 header->dwVersion = BCRYPT_KEY_DATA_BLOB_VERSION1;
903 header->cbKeyData = key->secret_len;
904 memcpy( &header[1], key->secret, key->secret_len );
905 return STATUS_SUCCESS;
908 FIXME( "unsupported key type %s\n", debugstr_w(type) );
909 return STATUS_NOT_IMPLEMENTED;
912 static NTSTATUS key_duplicate( struct key *key_orig, struct key *key_copy )
914 UCHAR *buffer;
916 if (!(buffer = heap_alloc( key_orig->secret_len ))) return STATUS_NO_MEMORY;
917 memcpy( buffer, key_orig->secret, key_orig->secret_len );
919 memset( key_copy, 0, sizeof(*key_copy) );
920 key_copy->hdr = key_orig->hdr;
921 key_copy->alg_id = key_orig->alg_id;
922 key_copy->mode = key_orig->mode;
923 key_copy->block_size = key_orig->block_size;
924 key_copy->secret = buffer;
925 key_copy->secret_len = key_orig->secret_len;
927 return STATUS_SUCCESS;
929 #endif
931 #if defined(HAVE_GNUTLS_CIPHER_INIT) && !defined(HAVE_COMMONCRYPTO_COMMONCRYPTOR_H)
932 static NTSTATUS key_init( struct key *key, struct algorithm *alg, const UCHAR *secret, ULONG secret_len )
934 UCHAR *buffer;
936 if (!libgnutls_handle) return STATUS_INTERNAL_ERROR;
938 switch (alg->id)
940 case ALG_ID_AES:
941 break;
943 default:
944 FIXME( "algorithm %u not supported\n", alg->id );
945 return STATUS_NOT_SUPPORTED;
948 if (!(key->block_size = get_block_size( alg ))) return STATUS_INVALID_PARAMETER;
949 if (!(buffer = heap_alloc( secret_len ))) return STATUS_NO_MEMORY;
950 memcpy( buffer, secret, secret_len );
952 key->alg_id = alg->id;
953 key->mode = alg->mode;
954 key->handle = 0; /* initialized on first use */
955 key->secret = buffer;
956 key->secret_len = secret_len;
958 return STATUS_SUCCESS;
961 static NTSTATUS set_key_property( struct key *key, const WCHAR *prop, UCHAR *value, ULONG size, ULONG flags )
963 if (!strcmpW( prop, BCRYPT_CHAINING_MODE ))
965 if (!strncmpW( (WCHAR *)value, BCRYPT_CHAIN_MODE_CBC, size ))
967 key->mode = MODE_ID_CBC;
968 return STATUS_SUCCESS;
970 else if (!strncmpW( (WCHAR *)value, BCRYPT_CHAIN_MODE_GCM, size ))
972 key->mode = MODE_ID_GCM;
973 return STATUS_SUCCESS;
975 else
977 FIXME( "unsupported mode %s\n", debugstr_wn( (WCHAR *)value, size ) );
978 return STATUS_NOT_IMPLEMENTED;
982 FIXME( "unsupported key property %s\n", debugstr_w(prop) );
983 return STATUS_NOT_IMPLEMENTED;
986 static gnutls_cipher_algorithm_t get_gnutls_cipher( const struct key *key )
988 switch (key->alg_id)
990 case ALG_ID_AES:
991 WARN( "handle block size\n" );
992 switch (key->mode)
994 case MODE_ID_GCM: return GNUTLS_CIPHER_AES_128_GCM;
995 case MODE_ID_CBC:
996 default: return GNUTLS_CIPHER_AES_128_CBC;
998 default:
999 FIXME( "algorithm %u not supported\n", key->alg_id );
1000 return GNUTLS_CIPHER_UNKNOWN;
1004 static NTSTATUS key_set_params( struct key *key, UCHAR *iv, ULONG iv_len )
1006 gnutls_cipher_algorithm_t cipher;
1007 gnutls_datum_t secret, vector;
1008 int ret;
1010 if (key->handle)
1012 pgnutls_cipher_deinit( key->handle );
1013 key->handle = NULL;
1016 if ((cipher = get_gnutls_cipher( key )) == GNUTLS_CIPHER_UNKNOWN)
1017 return STATUS_NOT_SUPPORTED;
1019 secret.data = key->secret;
1020 secret.size = key->secret_len;
1021 if (iv)
1023 vector.data = iv;
1024 vector.size = iv_len;
1027 if ((ret = pgnutls_cipher_init( &key->handle, cipher, &secret, iv ? &vector : NULL )))
1029 pgnutls_perror( ret );
1030 return STATUS_INTERNAL_ERROR;
1033 return STATUS_SUCCESS;
1036 static NTSTATUS key_set_auth_data( struct key *key, UCHAR *auth_data, ULONG len )
1038 int ret;
1040 if ((ret = pgnutls_cipher_add_auth( key->handle, auth_data, len )))
1042 pgnutls_perror( ret );
1043 return STATUS_INTERNAL_ERROR;
1046 return STATUS_SUCCESS;
1049 static NTSTATUS key_encrypt( struct key *key, const UCHAR *input, ULONG input_len, UCHAR *output,
1050 ULONG output_len )
1052 int ret;
1054 if ((ret = pgnutls_cipher_encrypt2( key->handle, input, input_len, output, output_len )))
1056 pgnutls_perror( ret );
1057 return STATUS_INTERNAL_ERROR;
1060 return STATUS_SUCCESS;
1063 static NTSTATUS key_decrypt( struct key *key, const UCHAR *input, ULONG input_len, UCHAR *output,
1064 ULONG output_len )
1066 int ret;
1068 if ((ret = pgnutls_cipher_decrypt2( key->handle, input, input_len, output, output_len )))
1070 pgnutls_perror( ret );
1071 return STATUS_INTERNAL_ERROR;
1074 return STATUS_SUCCESS;
1077 static NTSTATUS key_get_tag( struct key *key, UCHAR *tag, ULONG len )
1079 int ret;
1081 if ((ret = pgnutls_cipher_tag( key->handle, tag, len )))
1083 pgnutls_perror( ret );
1084 return STATUS_INTERNAL_ERROR;
1087 return STATUS_SUCCESS;
1090 static NTSTATUS key_destroy( struct key *key )
1092 if (key->handle) pgnutls_cipher_deinit( key->handle );
1093 heap_free( key->secret );
1094 heap_free( key );
1095 return STATUS_SUCCESS;
1097 #elif defined(HAVE_COMMONCRYPTO_COMMONCRYPTOR_H) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
1098 static NTSTATUS key_init( struct key *key, struct algorithm *alg, const UCHAR *secret, ULONG secret_len )
1100 UCHAR *buffer;
1102 switch (alg->id)
1104 case ALG_ID_AES:
1105 switch (alg->mode)
1107 case MODE_ID_CBC:
1108 break;
1109 default:
1110 FIXME( "mode %u not supported\n", alg->mode );
1111 return STATUS_NOT_SUPPORTED;
1113 break;
1115 default:
1116 FIXME( "algorithm %u not supported\n", alg->id );
1117 return STATUS_NOT_SUPPORTED;
1120 if (!(key->block_size = get_block_size( alg ))) return STATUS_INVALID_PARAMETER;
1121 if (!(buffer = heap_alloc( secret_len ))) return STATUS_NO_MEMORY;
1122 memcpy( buffer, secret, secret_len );
1124 key->alg_id = alg->id;
1125 key->mode = alg->mode;
1126 key->ref_encrypt = NULL; /* initialized on first use */
1127 key->ref_decrypt = NULL;
1128 key->secret = buffer;
1129 key->secret_len = secret_len;
1131 return STATUS_SUCCESS;
1134 static NTSTATUS set_key_property( struct key *key, const WCHAR *prop, UCHAR *value, ULONG size, ULONG flags )
1136 FIXME( "not implemented on Mac\n" );
1137 return STATUS_NOT_IMPLEMENTED;
1140 static NTSTATUS key_set_params( struct key *key, UCHAR *iv, ULONG iv_len )
1142 CCCryptorStatus status;
1144 if (key->ref_encrypt)
1146 CCCryptorRelease( key->ref_encrypt );
1147 key->ref_encrypt = NULL;
1149 if (key->ref_decrypt)
1151 CCCryptorRelease( key->ref_decrypt );
1152 key->ref_decrypt = NULL;
1155 if ((status = CCCryptorCreateWithMode( kCCEncrypt, kCCModeCBC, kCCAlgorithmAES128, ccNoPadding, iv,
1156 key->secret, key->secret_len, NULL, 0, 0, 0, &key->ref_encrypt )) != kCCSuccess)
1158 WARN( "CCCryptorCreateWithMode failed %d\n", status );
1159 return STATUS_INTERNAL_ERROR;
1161 if ((status = CCCryptorCreateWithMode( kCCDecrypt, kCCModeCBC, kCCAlgorithmAES128, ccNoPadding, iv,
1162 key->secret, key->secret_len, NULL, 0, 0, 0, &key->ref_decrypt )) != kCCSuccess)
1164 WARN( "CCCryptorCreateWithMode failed %d\n", status );
1165 CCCryptorRelease( key->ref_encrypt );
1166 key->ref_encrypt = NULL;
1167 return STATUS_INTERNAL_ERROR;
1170 return STATUS_SUCCESS;
1173 static NTSTATUS key_set_auth_data( struct key *key, UCHAR *auth_data, ULONG len )
1175 FIXME( "not implemented on Mac\n" );
1176 return STATUS_NOT_IMPLEMENTED;
1179 static NTSTATUS key_encrypt( struct key *key, const UCHAR *input, ULONG input_len, UCHAR *output,
1180 ULONG output_len )
1182 CCCryptorStatus status;
1184 if ((status = CCCryptorUpdate( key->ref_encrypt, input, input_len, output, output_len, NULL )) != kCCSuccess)
1186 WARN( "CCCryptorUpdate failed %d\n", status );
1187 return STATUS_INTERNAL_ERROR;
1190 return STATUS_SUCCESS;
1193 static NTSTATUS key_decrypt( struct key *key, const UCHAR *input, ULONG input_len, UCHAR *output,
1194 ULONG output_len )
1196 CCCryptorStatus status;
1198 if ((status = CCCryptorUpdate( key->ref_decrypt, input, input_len, output, output_len, NULL )) != kCCSuccess)
1200 WARN( "CCCryptorUpdate failed %d\n", status );
1201 return STATUS_INTERNAL_ERROR;
1204 return STATUS_SUCCESS;
1207 static NTSTATUS key_get_tag( struct key *key, UCHAR *tag, ULONG len )
1209 FIXME( "not implemented on Mac\n" );
1210 return STATUS_NOT_IMPLEMENTED;
1213 static NTSTATUS key_destroy( struct key *key )
1215 if (key->ref_encrypt) CCCryptorRelease( key->ref_encrypt );
1216 if (key->ref_decrypt) CCCryptorRelease( key->ref_decrypt );
1217 heap_free( key->secret );
1218 heap_free( key );
1219 return STATUS_SUCCESS;
1221 #else
1222 static NTSTATUS key_init( struct key *key, struct algorithm *alg, const UCHAR *secret, ULONG secret_len )
1224 ERR( "support for keys not available at build time\n" );
1225 return STATUS_NOT_IMPLEMENTED;
1228 static NTSTATUS set_key_property( struct key *key, const WCHAR *prop, UCHAR *value, ULONG size, ULONG flags )
1230 ERR( "support for keys not available at build time\n" );
1231 return STATUS_NOT_IMPLEMENTED;
1234 static NTSTATUS key_duplicate( struct key *key_orig, struct key *key_copy )
1236 ERR( "support for keys not available at build time\n" );
1237 return STATUS_NOT_IMPLEMENTED;
1240 static NTSTATUS key_set_params( struct key *key, UCHAR *iv, ULONG iv_len )
1242 ERR( "support for keys not available at build time\n" );
1243 return STATUS_NOT_IMPLEMENTED;
1246 static NTSTATUS key_set_auth_data( struct key *key, UCHAR *auth_data, ULONG len )
1248 ERR( "support for keys not available at build time\n" );
1249 return STATUS_NOT_IMPLEMENTED;
1252 static NTSTATUS key_encrypt( struct key *key, const UCHAR *input, ULONG input_len, UCHAR *output,
1253 ULONG output_len )
1255 ERR( "support for keys not available at build time\n" );
1256 return STATUS_NOT_IMPLEMENTED;
1259 static NTSTATUS key_decrypt( struct key *key, const UCHAR *input, ULONG input_len, UCHAR *output,
1260 ULONG output_len )
1262 ERR( "support for keys not available at build time\n" );
1263 return STATUS_NOT_IMPLEMENTED;
1266 static NTSTATUS key_get_tag( struct key *key, UCHAR *tag, ULONG len )
1268 ERR( "support for keys not available at build time\n" );
1269 return STATUS_NOT_IMPLEMENTED;
1272 static NTSTATUS key_destroy( struct key *key )
1274 ERR( "support for keys not available at build time\n" );
1275 return STATUS_NOT_IMPLEMENTED;
1278 static NTSTATUS key_export( struct key *key, const WCHAR *type, UCHAR *output, ULONG output_len, ULONG *size )
1280 ERR( "support for keys not available at build time\n" );
1281 return STATUS_NOT_IMPLEMENTED;
1283 #endif
1285 NTSTATUS WINAPI BCryptGenerateSymmetricKey( BCRYPT_ALG_HANDLE algorithm, BCRYPT_KEY_HANDLE *handle,
1286 UCHAR *object, ULONG object_len, UCHAR *secret, ULONG secret_len,
1287 ULONG flags )
1289 struct algorithm *alg = algorithm;
1290 struct key *key;
1291 NTSTATUS status;
1293 TRACE( "%p, %p, %p, %u, %p, %u, %08x\n", algorithm, handle, object, object_len, secret, secret_len, flags );
1295 if (!alg || alg->hdr.magic != MAGIC_ALG) return STATUS_INVALID_HANDLE;
1296 if (object) FIXME( "ignoring object buffer\n" );
1298 if (!(key = heap_alloc( sizeof(*key) ))) return STATUS_NO_MEMORY;
1299 key->hdr.magic = MAGIC_KEY;
1301 if ((status = key_init( key, alg, secret, secret_len )))
1303 heap_free( key );
1304 return status;
1307 *handle = key;
1308 return STATUS_SUCCESS;
1311 NTSTATUS WINAPI BCryptImportKey(BCRYPT_ALG_HANDLE algorithm, BCRYPT_KEY_HANDLE decrypt_key, LPCWSTR type,
1312 BCRYPT_KEY_HANDLE *key, PUCHAR object, ULONG object_len, PUCHAR input,
1313 ULONG input_len, ULONG flags)
1315 struct algorithm *alg = algorithm;
1317 TRACE("%p, %p, %s, %p, %p, %u, %p, %u, %u\n", algorithm, decrypt_key, debugstr_w(type), key, object,
1318 object_len, input, input_len, flags);
1320 if (!alg || alg->hdr.magic != MAGIC_ALG) return STATUS_INVALID_HANDLE;
1321 if (!key || !type || !input) return STATUS_INVALID_PARAMETER;
1323 if (decrypt_key)
1325 FIXME("Decrypting of key not yet supported\n");
1326 return STATUS_NO_MEMORY;
1329 if (!strcmpW(type, BCRYPT_KEY_DATA_BLOB))
1331 BCRYPT_KEY_DATA_BLOB_HEADER *key_header = (BCRYPT_KEY_DATA_BLOB_HEADER*)input;
1333 if (input_len < sizeof(BCRYPT_KEY_DATA_BLOB_HEADER))
1334 return STATUS_BUFFER_TOO_SMALL;
1336 if (key_header->dwMagic != BCRYPT_KEY_DATA_BLOB_MAGIC)
1337 return STATUS_INVALID_PARAMETER;
1339 if (key_header->dwVersion != BCRYPT_KEY_DATA_BLOB_VERSION1)
1341 FIXME("Unknown key data blob version: %d\n", key_header->dwVersion);
1342 return STATUS_INVALID_PARAMETER;
1345 if (key_header->cbKeyData + sizeof(BCRYPT_KEY_DATA_BLOB_HEADER) > input_len)
1346 return STATUS_INVALID_PARAMETER;
1348 return BCryptGenerateSymmetricKey(algorithm, key, object, object_len, (UCHAR*)&key_header[1], key_header->cbKeyData, 0);
1351 FIXME("Unsupported key type: %s\n", debugstr_w(type));
1352 return STATUS_INVALID_PARAMETER;
1355 NTSTATUS WINAPI BCryptExportKey(BCRYPT_KEY_HANDLE export_key, BCRYPT_KEY_HANDLE encrypt_key, LPCWSTR type,
1356 PUCHAR output, ULONG output_len, ULONG *size, ULONG flags)
1358 struct key *key = export_key;
1360 TRACE("%p, %p, %s, %p, %u, %p, %u\n", key, encrypt_key, debugstr_w(type), output, output_len, size, flags);
1362 if (!key || key->hdr.magic != MAGIC_KEY) return STATUS_INVALID_HANDLE;
1363 if (!output || !output_len || !size) return STATUS_INVALID_PARAMETER;
1365 if (encrypt_key)
1367 FIXME("Encryption of key not yet supported\n");
1368 return STATUS_NO_MEMORY;
1371 return key_export( key, type, output, output_len, size );
1374 NTSTATUS WINAPI BCryptDuplicateKey( BCRYPT_KEY_HANDLE handle, BCRYPT_KEY_HANDLE *handle_copy,
1375 UCHAR *object, ULONG object_len, ULONG flags )
1377 struct key *key_orig = handle;
1378 struct key *key_copy;
1379 NTSTATUS status;
1381 TRACE( "%p, %p, %p, %u, %08x\n", handle, handle_copy, object, object_len, flags );
1382 if (object) FIXME( "ignoring object buffer\n" );
1384 if (!key_orig || key_orig->hdr.magic != MAGIC_KEY) return STATUS_INVALID_HANDLE;
1385 if (!handle_copy) return STATUS_INVALID_PARAMETER;
1386 if (!(key_copy = heap_alloc( sizeof(*key_copy) ))) return STATUS_NO_MEMORY;
1388 if ((status = key_duplicate( key_orig, key_copy )))
1390 heap_free( key_copy );
1391 return status;
1394 *handle_copy = key_copy;
1395 return STATUS_SUCCESS;
1398 NTSTATUS WINAPI BCryptDestroyKey( BCRYPT_KEY_HANDLE handle )
1400 struct key *key = handle;
1402 TRACE( "%p\n", handle );
1404 if (!key || key->hdr.magic != MAGIC_KEY) return STATUS_INVALID_HANDLE;
1405 return key_destroy( key );
1408 NTSTATUS WINAPI BCryptEncrypt( BCRYPT_KEY_HANDLE handle, UCHAR *input, ULONG input_len,
1409 void *padding, UCHAR *iv, ULONG iv_len, UCHAR *output,
1410 ULONG output_len, ULONG *ret_len, ULONG flags )
1412 struct key *key = handle;
1413 ULONG bytes_left = input_len;
1414 UCHAR *buf, *src, *dst;
1415 NTSTATUS status;
1417 TRACE( "%p, %p, %u, %p, %p, %u, %p, %u, %p, %08x\n", handle, input, input_len,
1418 padding, iv, iv_len, output, output_len, ret_len, flags );
1420 if (!key || key->hdr.magic != MAGIC_KEY) return STATUS_INVALID_HANDLE;
1421 if (flags & ~BCRYPT_BLOCK_PADDING)
1423 FIXME( "flags %08x not implemented\n", flags );
1424 return STATUS_NOT_IMPLEMENTED;
1427 if (key->mode == MODE_ID_GCM)
1429 BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO *auth_info = padding;
1431 if (!auth_info) return STATUS_INVALID_PARAMETER;
1432 if (!auth_info->pbNonce) return STATUS_INVALID_PARAMETER;
1433 if (!auth_info->pbTag) return STATUS_INVALID_PARAMETER;
1434 if (auth_info->cbTag < 12 || auth_info->cbTag > 16) return STATUS_INVALID_PARAMETER;
1435 if (auth_info->dwFlags & BCRYPT_AUTH_MODE_CHAIN_CALLS_FLAG)
1436 FIXME( "call chaining not implemented\n" );
1438 if ((status = key_set_params( key, auth_info->pbNonce, auth_info->cbNonce )))
1439 return status;
1441 *ret_len = input_len;
1442 if (flags & BCRYPT_BLOCK_PADDING) return STATUS_INVALID_PARAMETER;
1443 if (!output) return STATUS_SUCCESS;
1444 if (output_len < *ret_len) return STATUS_BUFFER_TOO_SMALL;
1446 if (auth_info->pbAuthData && (status = key_set_auth_data( key, auth_info->pbAuthData, auth_info->cbAuthData )))
1447 return status;
1448 if ((status = key_encrypt( key, input, input_len, output, output_len )))
1449 return status;
1451 return key_get_tag( key, auth_info->pbTag, auth_info->cbTag );
1454 if ((status = key_set_params( key, iv, iv_len ))) return status;
1456 *ret_len = input_len;
1458 if (flags & BCRYPT_BLOCK_PADDING)
1459 *ret_len = (input_len + key->block_size) & ~(key->block_size - 1);
1460 else if (input_len & (key->block_size - 1))
1461 return STATUS_INVALID_BUFFER_SIZE;
1463 if (!output) return STATUS_SUCCESS;
1464 if (output_len < *ret_len) return STATUS_BUFFER_TOO_SMALL;
1466 src = input;
1467 dst = output;
1468 while (bytes_left >= key->block_size)
1470 if ((status = key_encrypt( key, src, key->block_size, dst, key->block_size ))) return status;
1471 bytes_left -= key->block_size;
1472 src += key->block_size;
1473 dst += key->block_size;
1476 if (flags & BCRYPT_BLOCK_PADDING)
1478 if (!(buf = heap_alloc( key->block_size ))) return STATUS_NO_MEMORY;
1479 memcpy( buf, src, bytes_left );
1480 memset( buf + bytes_left, key->block_size - bytes_left, key->block_size - bytes_left );
1481 status = key_encrypt( key, buf, key->block_size, dst, key->block_size );
1482 heap_free( buf );
1485 return status;
1488 NTSTATUS WINAPI BCryptDecrypt( BCRYPT_KEY_HANDLE handle, UCHAR *input, ULONG input_len,
1489 void *padding, UCHAR *iv, ULONG iv_len, UCHAR *output,
1490 ULONG output_len, ULONG *ret_len, ULONG flags )
1492 struct key *key = handle;
1493 ULONG bytes_left = input_len;
1494 UCHAR *buf, *src, *dst;
1495 NTSTATUS status;
1497 TRACE( "%p, %p, %u, %p, %p, %u, %p, %u, %p, %08x\n", handle, input, input_len,
1498 padding, iv, iv_len, output, output_len, ret_len, flags );
1500 if (!key || key->hdr.magic != MAGIC_KEY) return STATUS_INVALID_HANDLE;
1501 if (flags & ~BCRYPT_BLOCK_PADDING)
1503 FIXME( "flags %08x not supported\n", flags );
1504 return STATUS_NOT_IMPLEMENTED;
1507 if (key->mode == MODE_ID_GCM)
1509 BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO *auth_info = padding;
1510 UCHAR tag[16];
1512 if (!auth_info) return STATUS_INVALID_PARAMETER;
1513 if (!auth_info->pbNonce) return STATUS_INVALID_PARAMETER;
1514 if (!auth_info->pbTag) return STATUS_INVALID_PARAMETER;
1515 if (auth_info->cbTag < 12 || auth_info->cbTag > 16) return STATUS_INVALID_PARAMETER;
1517 if ((status = key_set_params( key, auth_info->pbNonce, auth_info->cbNonce )))
1518 return status;
1520 *ret_len = input_len;
1521 if (flags & BCRYPT_BLOCK_PADDING) return STATUS_INVALID_PARAMETER;
1522 if (!output) return STATUS_SUCCESS;
1523 if (output_len < *ret_len) return STATUS_BUFFER_TOO_SMALL;
1525 if (auth_info->pbAuthData && (status = key_set_auth_data( key, auth_info->pbAuthData, auth_info->cbAuthData )))
1526 return status;
1527 if ((status = key_decrypt( key, input, input_len, output, output_len )))
1528 return status;
1530 if ((status = key_get_tag( key, tag, sizeof(tag) )))
1531 return status;
1532 if (memcmp( tag, auth_info->pbTag, auth_info->cbTag ))
1533 return STATUS_AUTH_TAG_MISMATCH;
1535 return STATUS_SUCCESS;
1538 if ((status = key_set_params( key, iv, iv_len ))) return status;
1540 *ret_len = input_len;
1542 if (input_len & (key->block_size - 1)) return STATUS_INVALID_BUFFER_SIZE;
1543 if (!output) return STATUS_SUCCESS;
1544 if (flags & BCRYPT_BLOCK_PADDING)
1546 if (output_len + key->block_size < *ret_len) return STATUS_BUFFER_TOO_SMALL;
1547 if (input_len < key->block_size) return STATUS_BUFFER_TOO_SMALL;
1548 bytes_left -= key->block_size;
1550 else if (output_len < *ret_len)
1551 return STATUS_BUFFER_TOO_SMALL;
1553 src = input;
1554 dst = output;
1555 while (bytes_left >= key->block_size)
1557 if ((status = key_decrypt( key, src, key->block_size, dst, key->block_size ))) return status;
1558 bytes_left -= key->block_size;
1559 src += key->block_size;
1560 dst += key->block_size;
1563 if (flags & BCRYPT_BLOCK_PADDING)
1565 if (!(buf = heap_alloc( key->block_size ))) return STATUS_NO_MEMORY;
1566 status = key_decrypt( key, src, key->block_size, buf, key->block_size );
1567 if (!status && buf[ key->block_size - 1 ] <= key->block_size)
1569 *ret_len -= buf[ key->block_size - 1 ];
1570 if (output_len < *ret_len) status = STATUS_BUFFER_TOO_SMALL;
1571 else memcpy( dst, buf, key->block_size - buf[ key->block_size - 1 ] );
1573 else
1574 status = STATUS_UNSUCCESSFUL; /* FIXME: invalid padding */
1575 heap_free( buf );
1578 return status;
1581 NTSTATUS WINAPI BCryptSetProperty( BCRYPT_HANDLE handle, const WCHAR *prop, UCHAR *value, ULONG size, ULONG flags )
1583 struct object *object = handle;
1585 TRACE( "%p, %s, %p, %u, %08x\n", handle, debugstr_w(prop), value, size, flags );
1587 if (!object) return STATUS_INVALID_HANDLE;
1589 switch (object->magic)
1591 case MAGIC_ALG:
1593 struct algorithm *alg = (struct algorithm *)object;
1594 return set_alg_property( alg, prop, value, size, flags );
1596 case MAGIC_KEY:
1598 struct key *key = (struct key *)object;
1599 return set_key_property( key, prop, value, size, flags );
1601 default:
1602 WARN( "unknown magic %08x\n", object->magic );
1603 return STATUS_INVALID_HANDLE;
1607 BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
1609 switch (reason)
1611 case DLL_PROCESS_ATTACH:
1612 instance = hinst;
1613 DisableThreadLibraryCalls( hinst );
1614 #if defined(HAVE_GNUTLS_CIPHER_INIT) && !defined(HAVE_COMMONCRYPTO_COMMONCRYPTOR_H)
1615 gnutls_initialize();
1616 #endif
1617 break;
1619 case DLL_PROCESS_DETACH:
1620 if (reserved) break;
1621 #if defined(HAVE_GNUTLS_CIPHER_INIT) && !defined(HAVE_COMMONCRYPTO_COMMONCRYPTOR_H)
1622 gnutls_uninitialize();
1623 #endif
1624 break;
1626 return TRUE;