bcrypt: Preparation for asymmetric keys.
[wine.git] / dlls / bcrypt / bcrypt_main.c
blob57cb3632d55b8970dd83cf5169434479cfc7e7df
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_ECB,
229 MODE_ID_CBC,
230 MODE_ID_GCM
233 #define MAX_HASH_OUTPUT_BYTES 64
234 #define MAX_HASH_BLOCK_BITS 1024
236 static const struct
238 ULONG object_length;
239 ULONG hash_length;
240 ULONG block_bits;
241 const WCHAR *alg_name;
242 BOOL symmetric;
244 alg_props[] =
246 /* ALG_ID_AES */ { 654, 0, 0, BCRYPT_AES_ALGORITHM, TRUE },
247 /* ALG_ID_MD2 */ { 270, 16, 128, BCRYPT_MD2_ALGORITHM, FALSE },
248 /* ALG_ID_MD4 */ { 270, 16, 512, BCRYPT_MD4_ALGORITHM, FALSE },
249 /* ALG_ID_MD5 */ { 274, 16, 512, BCRYPT_MD5_ALGORITHM, FALSE },
250 /* ALG_ID_RNG */ { 0, 0, 0, BCRYPT_RNG_ALGORITHM, FALSE },
251 /* ALG_ID_SHA1 */ { 278, 20, 512, BCRYPT_SHA1_ALGORITHM, FALSE },
252 /* ALG_ID_SHA256 */ { 286, 32, 512, BCRYPT_SHA256_ALGORITHM, FALSE },
253 /* ALG_ID_SHA384 */ { 382, 48, 1024, BCRYPT_SHA384_ALGORITHM, FALSE },
254 /* ALG_ID_SHA512 */ { 382, 64, 1024, BCRYPT_SHA512_ALGORITHM, FALSE }
257 struct algorithm
259 struct object hdr;
260 enum alg_id id;
261 enum mode_id mode;
262 BOOL hmac;
265 NTSTATUS WINAPI BCryptGenRandom(BCRYPT_ALG_HANDLE handle, UCHAR *buffer, ULONG count, ULONG flags)
267 const DWORD supported_flags = BCRYPT_USE_SYSTEM_PREFERRED_RNG;
268 struct algorithm *algorithm = handle;
270 TRACE("%p, %p, %u, %08x - semi-stub\n", handle, buffer, count, flags);
272 if (!algorithm)
274 /* It's valid to call without an algorithm if BCRYPT_USE_SYSTEM_PREFERRED_RNG
275 * is set. In this case the preferred system RNG is used.
277 if (!(flags & BCRYPT_USE_SYSTEM_PREFERRED_RNG))
278 return STATUS_INVALID_HANDLE;
280 else if (algorithm->hdr.magic != MAGIC_ALG || algorithm->id != ALG_ID_RNG)
281 return STATUS_INVALID_HANDLE;
283 if (!buffer)
284 return STATUS_INVALID_PARAMETER;
286 if (flags & ~supported_flags)
287 FIXME("unsupported flags %08x\n", flags & ~supported_flags);
289 if (algorithm)
290 FIXME("ignoring selected algorithm\n");
292 /* When zero bytes are requested the function returns success too. */
293 if (!count)
294 return STATUS_SUCCESS;
296 if (algorithm || (flags & BCRYPT_USE_SYSTEM_PREFERRED_RNG))
298 if (RtlGenRandom(buffer, count))
299 return STATUS_SUCCESS;
302 FIXME("called with unsupported parameters, returning error\n");
303 return STATUS_NOT_IMPLEMENTED;
306 NTSTATUS WINAPI BCryptOpenAlgorithmProvider( BCRYPT_ALG_HANDLE *handle, LPCWSTR id, LPCWSTR implementation, DWORD flags )
308 const DWORD supported_flags = BCRYPT_ALG_HANDLE_HMAC_FLAG;
309 struct algorithm *alg;
310 enum alg_id alg_id;
312 TRACE( "%p, %s, %s, %08x\n", handle, wine_dbgstr_w(id), wine_dbgstr_w(implementation), flags );
314 if (!handle || !id) return STATUS_INVALID_PARAMETER;
315 if (flags & ~supported_flags)
317 FIXME( "unsupported flags %08x\n", flags & ~supported_flags);
318 return STATUS_NOT_IMPLEMENTED;
321 if (!strcmpW( id, BCRYPT_AES_ALGORITHM )) alg_id = ALG_ID_AES;
322 else if (!strcmpW( id, BCRYPT_MD2_ALGORITHM )) alg_id = ALG_ID_MD2;
323 else if (!strcmpW( id, BCRYPT_MD4_ALGORITHM )) alg_id = ALG_ID_MD4;
324 else if (!strcmpW( id, BCRYPT_MD5_ALGORITHM )) alg_id = ALG_ID_MD5;
325 else if (!strcmpW( id, BCRYPT_RNG_ALGORITHM )) alg_id = ALG_ID_RNG;
326 else if (!strcmpW( id, BCRYPT_SHA1_ALGORITHM )) alg_id = ALG_ID_SHA1;
327 else if (!strcmpW( id, BCRYPT_SHA256_ALGORITHM )) alg_id = ALG_ID_SHA256;
328 else if (!strcmpW( id, BCRYPT_SHA384_ALGORITHM )) alg_id = ALG_ID_SHA384;
329 else if (!strcmpW( id, BCRYPT_SHA512_ALGORITHM )) alg_id = ALG_ID_SHA512;
330 else
332 FIXME( "algorithm %s not supported\n", debugstr_w(id) );
333 return STATUS_NOT_IMPLEMENTED;
335 if (implementation && strcmpW( implementation, MS_PRIMITIVE_PROVIDER ))
337 FIXME( "implementation %s not supported\n", debugstr_w(implementation) );
338 return STATUS_NOT_IMPLEMENTED;
341 if (!(alg = heap_alloc( sizeof(*alg) ))) return STATUS_NO_MEMORY;
342 alg->hdr.magic = MAGIC_ALG;
343 alg->id = alg_id;
344 alg->mode = MODE_ID_CBC;
345 alg->hmac = flags & BCRYPT_ALG_HANDLE_HMAC_FLAG;
347 *handle = alg;
348 return STATUS_SUCCESS;
351 NTSTATUS WINAPI BCryptCloseAlgorithmProvider( BCRYPT_ALG_HANDLE handle, DWORD flags )
353 struct algorithm *alg = handle;
355 TRACE( "%p, %08x\n", handle, flags );
357 if (!alg || alg->hdr.magic != MAGIC_ALG) return STATUS_INVALID_HANDLE;
358 heap_free( alg );
359 return STATUS_SUCCESS;
362 NTSTATUS WINAPI BCryptGetFipsAlgorithmMode(BOOLEAN *enabled)
364 FIXME("%p - semi-stub\n", enabled);
366 if (!enabled)
367 return STATUS_INVALID_PARAMETER;
369 *enabled = FALSE;
370 return STATUS_SUCCESS;
373 struct hash_impl
375 union
377 MD2_CTX md2;
378 MD4_CTX md4;
379 MD5_CTX md5;
380 SHA_CTX sha1;
381 SHA256_CTX sha256;
382 SHA512_CTX sha512;
383 } u;
386 static NTSTATUS hash_init( struct hash_impl *hash, enum alg_id alg_id )
388 switch (alg_id)
390 case ALG_ID_MD2:
391 md2_init( &hash->u.md2 );
392 break;
394 case ALG_ID_MD4:
395 MD4Init( &hash->u.md4 );
396 break;
398 case ALG_ID_MD5:
399 MD5Init( &hash->u.md5 );
400 break;
402 case ALG_ID_SHA1:
403 A_SHAInit( &hash->u.sha1 );
404 break;
406 case ALG_ID_SHA256:
407 sha256_init( &hash->u.sha256 );
408 break;
410 case ALG_ID_SHA384:
411 sha384_init( &hash->u.sha512 );
412 break;
414 case ALG_ID_SHA512:
415 sha512_init( &hash->u.sha512 );
416 break;
418 default:
419 ERR( "unhandled id %u\n", alg_id );
420 return STATUS_NOT_IMPLEMENTED;
422 return STATUS_SUCCESS;
425 static NTSTATUS hash_update( struct hash_impl *hash, enum alg_id alg_id,
426 UCHAR *input, ULONG size )
428 switch (alg_id)
430 case ALG_ID_MD2:
431 md2_update( &hash->u.md2, input, size );
432 break;
434 case ALG_ID_MD4:
435 MD4Update( &hash->u.md4, input, size );
436 break;
438 case ALG_ID_MD5:
439 MD5Update( &hash->u.md5, input, size );
440 break;
442 case ALG_ID_SHA1:
443 A_SHAUpdate( &hash->u.sha1, input, size );
444 break;
446 case ALG_ID_SHA256:
447 sha256_update( &hash->u.sha256, input, size );
448 break;
450 case ALG_ID_SHA384:
451 sha384_update( &hash->u.sha512, input, size );
452 break;
454 case ALG_ID_SHA512:
455 sha512_update( &hash->u.sha512, input, size );
456 break;
458 default:
459 ERR( "unhandled id %u\n", alg_id );
460 return STATUS_NOT_IMPLEMENTED;
462 return STATUS_SUCCESS;
465 static NTSTATUS hash_finish( struct hash_impl *hash, enum alg_id alg_id,
466 UCHAR *output, ULONG size )
468 switch (alg_id)
470 case ALG_ID_MD2:
471 md2_finalize( &hash->u.md2, output );
472 break;
474 case ALG_ID_MD4:
475 MD4Final( &hash->u.md4 );
476 memcpy( output, hash->u.md4.digest, 16 );
477 break;
479 case ALG_ID_MD5:
480 MD5Final( &hash->u.md5 );
481 memcpy( output, hash->u.md5.digest, 16 );
482 break;
484 case ALG_ID_SHA1:
485 A_SHAFinal( &hash->u.sha1, (ULONG *)output );
486 break;
488 case ALG_ID_SHA256:
489 sha256_finalize( &hash->u.sha256, output );
490 break;
492 case ALG_ID_SHA384:
493 sha384_finalize( &hash->u.sha512, output );
494 break;
496 case ALG_ID_SHA512:
497 sha512_finalize( &hash->u.sha512, output );
498 break;
500 default:
501 ERR( "unhandled id %u\n", alg_id );
502 return STATUS_NOT_IMPLEMENTED;
504 return STATUS_SUCCESS;
507 struct hash
509 struct object hdr;
510 enum alg_id alg_id;
511 BOOL hmac;
512 struct hash_impl outer;
513 struct hash_impl inner;
516 #define BLOCK_LENGTH_AES 16
518 static NTSTATUS generic_alg_property( enum alg_id id, const WCHAR *prop, UCHAR *buf, ULONG size, ULONG *ret_size )
520 if (!strcmpW( prop, BCRYPT_OBJECT_LENGTH ))
522 if (!alg_props[id].object_length)
523 return STATUS_NOT_SUPPORTED;
524 *ret_size = sizeof(ULONG);
525 if (size < sizeof(ULONG))
526 return STATUS_BUFFER_TOO_SMALL;
527 if (buf)
528 *(ULONG *)buf = alg_props[id].object_length;
529 return STATUS_SUCCESS;
532 if (!strcmpW( prop, BCRYPT_HASH_LENGTH ))
534 if (!alg_props[id].hash_length)
535 return STATUS_NOT_SUPPORTED;
536 *ret_size = sizeof(ULONG);
537 if (size < sizeof(ULONG))
538 return STATUS_BUFFER_TOO_SMALL;
539 if(buf)
540 *(ULONG*)buf = alg_props[id].hash_length;
541 return STATUS_SUCCESS;
544 if (!strcmpW( prop, BCRYPT_ALGORITHM_NAME ))
546 *ret_size = (strlenW(alg_props[id].alg_name)+1)*sizeof(WCHAR);
547 if (size < *ret_size)
548 return STATUS_BUFFER_TOO_SMALL;
549 if(buf)
550 memcpy(buf, alg_props[id].alg_name, *ret_size);
551 return STATUS_SUCCESS;
554 return STATUS_NOT_IMPLEMENTED;
557 static NTSTATUS get_alg_property( const struct algorithm *alg, const WCHAR *prop, UCHAR *buf, ULONG size, ULONG *ret_size )
559 NTSTATUS status;
561 status = generic_alg_property( alg->id, prop, buf, size, ret_size );
562 if (status != STATUS_NOT_IMPLEMENTED)
563 return status;
565 switch (alg->id)
567 case ALG_ID_AES:
568 if (!strcmpW( prop, BCRYPT_BLOCK_LENGTH ))
570 *ret_size = sizeof(ULONG);
571 if (size < sizeof(ULONG))
572 return STATUS_BUFFER_TOO_SMALL;
573 if (buf)
574 *(ULONG *)buf = BLOCK_LENGTH_AES;
575 return STATUS_SUCCESS;
577 if (!strcmpW( prop, BCRYPT_CHAINING_MODE ))
579 const WCHAR *mode;
580 switch (alg->mode)
582 case MODE_ID_ECB: mode = BCRYPT_CHAIN_MODE_ECB; break;
583 case MODE_ID_CBC: mode = BCRYPT_CHAIN_MODE_CBC; break;
584 case MODE_ID_GCM: mode = BCRYPT_CHAIN_MODE_GCM; break;
585 default: return STATUS_NOT_IMPLEMENTED;
588 *ret_size = 64;
589 if (size < *ret_size) return STATUS_BUFFER_TOO_SMALL;
590 memcpy( buf, mode, (strlenW(mode) + 1) * sizeof(WCHAR) );
591 return STATUS_SUCCESS;
593 if (!strcmpW( prop, BCRYPT_KEY_LENGTHS ))
595 BCRYPT_KEY_LENGTHS_STRUCT *key_lengths = (void *)buf;
596 *ret_size = sizeof(*key_lengths);
597 if (key_lengths && size < *ret_size) return STATUS_BUFFER_TOO_SMALL;
598 if (key_lengths)
600 key_lengths->dwMinLength = 128;
601 key_lengths->dwMaxLength = 256;
602 key_lengths->dwIncrement = 64;
604 return STATUS_SUCCESS;
606 if (!strcmpW( prop, BCRYPT_AUTH_TAG_LENGTH ))
608 BCRYPT_AUTH_TAG_LENGTHS_STRUCT *tag_length = (void *)buf;
609 if (alg->mode != MODE_ID_GCM) return STATUS_NOT_SUPPORTED;
610 *ret_size = sizeof(*tag_length);
611 if (tag_length && size < *ret_size) return STATUS_BUFFER_TOO_SMALL;
612 if (tag_length)
614 tag_length->dwMinLength = 12;
615 tag_length->dwMaxLength = 16;
616 tag_length->dwIncrement = 1;
618 return STATUS_SUCCESS;
620 break;
622 default:
623 break;
626 FIXME( "unsupported property %s\n", debugstr_w(prop) );
627 return STATUS_NOT_IMPLEMENTED;
630 static NTSTATUS set_alg_property( struct algorithm *alg, const WCHAR *prop, UCHAR *value, ULONG size, ULONG flags )
632 switch (alg->id)
634 case ALG_ID_AES:
635 if (!strcmpW( prop, BCRYPT_CHAINING_MODE ))
637 if (!strncmpW( (WCHAR *)value, BCRYPT_CHAIN_MODE_ECB, size ))
639 alg->mode = MODE_ID_ECB;
640 return STATUS_SUCCESS;
642 else if (!strncmpW( (WCHAR *)value, BCRYPT_CHAIN_MODE_CBC, size ))
644 alg->mode = MODE_ID_CBC;
645 return STATUS_SUCCESS;
647 else if (!strncmpW( (WCHAR *)value, BCRYPT_CHAIN_MODE_GCM, size ))
649 alg->mode = MODE_ID_GCM;
650 return STATUS_SUCCESS;
652 else
654 FIXME( "unsupported mode %s\n", debugstr_wn( (WCHAR *)value, size ) );
655 return STATUS_NOT_IMPLEMENTED;
658 FIXME( "unsupported aes algorithm property %s\n", debugstr_w(prop) );
659 return STATUS_NOT_IMPLEMENTED;
661 default:
662 FIXME( "unsupported algorithm %u\n", alg->id );
663 return STATUS_NOT_IMPLEMENTED;
667 static NTSTATUS get_hash_property( const struct hash *hash, const WCHAR *prop, UCHAR *buf, ULONG size, ULONG *ret_size )
669 NTSTATUS status;
671 status = generic_alg_property( hash->alg_id, prop, buf, size, ret_size );
672 if (status == STATUS_NOT_IMPLEMENTED)
673 FIXME( "unsupported property %s\n", debugstr_w(prop) );
674 return status;
677 NTSTATUS WINAPI BCryptGetProperty( BCRYPT_HANDLE handle, LPCWSTR prop, UCHAR *buffer, ULONG count, ULONG *res, ULONG flags )
679 struct object *object = handle;
681 TRACE( "%p, %s, %p, %u, %p, %08x\n", handle, wine_dbgstr_w(prop), buffer, count, res, flags );
683 if (!object) return STATUS_INVALID_HANDLE;
684 if (!prop || !res) return STATUS_INVALID_PARAMETER;
686 switch (object->magic)
688 case MAGIC_ALG:
690 const struct algorithm *alg = (const struct algorithm *)object;
691 return get_alg_property( alg, prop, buffer, count, res );
693 case MAGIC_HASH:
695 const struct hash *hash = (const struct hash *)object;
696 return get_hash_property( hash, prop, buffer, count, res );
698 default:
699 WARN( "unknown magic %08x\n", object->magic );
700 return STATUS_INVALID_HANDLE;
704 NTSTATUS WINAPI BCryptCreateHash( BCRYPT_ALG_HANDLE algorithm, BCRYPT_HASH_HANDLE *handle, UCHAR *object, ULONG objectlen,
705 UCHAR *secret, ULONG secretlen, ULONG flags )
707 struct algorithm *alg = algorithm;
708 UCHAR buffer[MAX_HASH_BLOCK_BITS / 8] = {0};
709 struct hash *hash;
710 int block_bytes;
711 NTSTATUS status;
712 int i;
714 TRACE( "%p, %p, %p, %u, %p, %u, %08x - stub\n", algorithm, handle, object, objectlen,
715 secret, secretlen, flags );
716 if (flags)
718 FIXME( "unimplemented flags %08x\n", flags );
719 return STATUS_NOT_IMPLEMENTED;
722 if (!alg || alg->hdr.magic != MAGIC_ALG) return STATUS_INVALID_HANDLE;
723 if (object) FIXME( "ignoring object buffer\n" );
725 if (!(hash = heap_alloc( sizeof(*hash) ))) return STATUS_NO_MEMORY;
726 hash->hdr.magic = MAGIC_HASH;
727 hash->alg_id = alg->id;
728 hash->hmac = alg->hmac;
730 /* initialize hash */
731 if ((status = hash_init( &hash->inner, hash->alg_id ))) goto end;
732 if (!hash->hmac) goto end;
734 /* initialize hmac */
735 if ((status = hash_init( &hash->outer, hash->alg_id ))) goto end;
736 block_bytes = alg_props[hash->alg_id].block_bits / 8;
737 if (secretlen > block_bytes)
739 struct hash_impl temp;
740 if ((status = hash_init( &temp, hash->alg_id ))) goto end;
741 if ((status = hash_update( &temp, hash->alg_id, secret, secretlen ))) goto end;
742 if ((status = hash_finish( &temp, hash->alg_id, buffer,
743 alg_props[hash->alg_id].hash_length ))) goto end;
745 else
747 memcpy( buffer, secret, secretlen );
749 for (i = 0; i < block_bytes; i++) buffer[i] ^= 0x5c;
750 if ((status = hash_update( &hash->outer, hash->alg_id, buffer, block_bytes ))) goto end;
751 for (i = 0; i < block_bytes; i++) buffer[i] ^= (0x5c ^ 0x36);
752 status = hash_update( &hash->inner, hash->alg_id, buffer, block_bytes );
754 end:
755 if (status != STATUS_SUCCESS)
757 heap_free( hash );
758 return status;
761 *handle = hash;
762 return STATUS_SUCCESS;
765 NTSTATUS WINAPI BCryptDuplicateHash( BCRYPT_HASH_HANDLE handle, BCRYPT_HASH_HANDLE *handle_copy,
766 UCHAR *object, ULONG objectlen, ULONG flags )
768 struct hash *hash_orig = handle;
769 struct hash *hash_copy;
771 TRACE( "%p, %p, %p, %u, %u\n", handle, handle_copy, object, objectlen, flags );
773 if (!hash_orig || hash_orig->hdr.magic != MAGIC_HASH) return STATUS_INVALID_HANDLE;
774 if (!handle_copy) return STATUS_INVALID_PARAMETER;
775 if (object) FIXME( "ignoring object buffer\n" );
777 if (!(hash_copy = heap_alloc( sizeof(*hash_copy) )))
778 return STATUS_NO_MEMORY;
780 memcpy( hash_copy, hash_orig, sizeof(*hash_orig) );
782 *handle_copy = hash_copy;
783 return STATUS_SUCCESS;
786 NTSTATUS WINAPI BCryptDestroyHash( BCRYPT_HASH_HANDLE handle )
788 struct hash *hash = handle;
790 TRACE( "%p\n", handle );
792 if (!hash || hash->hdr.magic != MAGIC_HASH) return STATUS_INVALID_HANDLE;
793 heap_free( hash );
794 return STATUS_SUCCESS;
797 NTSTATUS WINAPI BCryptHashData( BCRYPT_HASH_HANDLE handle, UCHAR *input, ULONG size, ULONG flags )
799 struct hash *hash = handle;
801 TRACE( "%p, %p, %u, %08x\n", handle, input, size, flags );
803 if (!hash || hash->hdr.magic != MAGIC_HASH) return STATUS_INVALID_HANDLE;
804 if (!input) return STATUS_SUCCESS;
806 return hash_update( &hash->inner, hash->alg_id, input, size );
809 NTSTATUS WINAPI BCryptFinishHash( BCRYPT_HASH_HANDLE handle, UCHAR *output, ULONG size, ULONG flags )
811 UCHAR buffer[MAX_HASH_OUTPUT_BYTES];
812 struct hash *hash = handle;
813 NTSTATUS status;
814 int hash_length;
816 TRACE( "%p, %p, %u, %08x\n", handle, output, size, flags );
818 if (!hash || hash->hdr.magic != MAGIC_HASH) return STATUS_INVALID_HANDLE;
819 if (!output) return STATUS_INVALID_PARAMETER;
821 if (!hash->hmac)
822 return hash_finish( &hash->inner, hash->alg_id, output, size );
824 hash_length = alg_props[hash->alg_id].hash_length;
825 if ((status = hash_finish( &hash->inner, hash->alg_id, buffer, hash_length ))) return status;
826 if ((status = hash_update( &hash->outer, hash->alg_id, buffer, hash_length ))) return status;
827 return hash_finish( &hash->outer, hash->alg_id, output, size );
830 NTSTATUS WINAPI BCryptHash( BCRYPT_ALG_HANDLE algorithm, UCHAR *secret, ULONG secretlen,
831 UCHAR *input, ULONG inputlen, UCHAR *output, ULONG outputlen )
833 NTSTATUS status;
834 BCRYPT_HASH_HANDLE handle;
836 TRACE( "%p, %p, %u, %p, %u, %p, %u\n", algorithm, secret, secretlen,
837 input, inputlen, output, outputlen );
839 status = BCryptCreateHash( algorithm, &handle, NULL, 0, secret, secretlen, 0);
840 if (status != STATUS_SUCCESS)
842 return status;
845 status = BCryptHashData( handle, input, inputlen, 0 );
846 if (status != STATUS_SUCCESS)
848 BCryptDestroyHash( handle );
849 return status;
852 status = BCryptFinishHash( handle, output, outputlen, 0 );
853 if (status != STATUS_SUCCESS)
855 BCryptDestroyHash( handle );
856 return status;
859 return BCryptDestroyHash( handle );
862 #if defined(HAVE_GNUTLS_CIPHER_INIT) && !defined(HAVE_COMMONCRYPTO_COMMONCRYPTOR_H)
863 struct key_symmetric
865 enum mode_id mode;
866 ULONG block_size;
867 gnutls_cipher_hd_t handle;
868 UCHAR *secret;
869 ULONG secret_len;
872 struct key
874 struct object hdr;
875 enum alg_id alg_id;
876 union
878 struct key_symmetric s;
879 } u;
882 #elif defined(HAVE_COMMONCRYPTO_COMMONCRYPTOR_H) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
883 struct key_symmetric
885 enum mode_id mode;
886 ULONG block_size;
887 CCCryptorRef ref_encrypt;
888 CCCryptorRef ref_decrypt;
889 UCHAR *secret;
890 ULONG secret_len;
893 struct key
895 struct object hdr;
896 enum alg_id alg_id;
897 union
899 struct key_symmetric s;
900 } u;
902 #else
903 struct key_symmetric
905 enum mode_id mode;
906 ULONG block_size;
909 struct key
911 struct object hdr;
912 union
914 struct key_symmetric s;
915 } u;
917 #endif
919 #if defined(HAVE_GNUTLS_CIPHER_INIT) || defined(HAVE_COMMONCRYPTO_COMMONCRYPTOR_H) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
920 static inline BOOL key_is_symmetric( struct key *key )
922 return alg_props[key->alg_id].symmetric;
925 static ULONG get_block_size( struct algorithm *alg )
927 ULONG ret = 0, size = sizeof(ret);
928 get_alg_property( alg, BCRYPT_BLOCK_LENGTH, (UCHAR *)&ret, sizeof(ret), &size );
929 return ret;
932 static NTSTATUS key_export( struct key *key, const WCHAR *type, UCHAR *output, ULONG output_len, ULONG *size )
934 if (!strcmpW( type, BCRYPT_KEY_DATA_BLOB ))
936 BCRYPT_KEY_DATA_BLOB_HEADER *header = (BCRYPT_KEY_DATA_BLOB_HEADER *)output;
937 ULONG req_size = sizeof(BCRYPT_KEY_DATA_BLOB_HEADER) + key->u.s.secret_len;
939 *size = req_size;
940 if (output_len < req_size) return STATUS_BUFFER_TOO_SMALL;
942 header->dwMagic = BCRYPT_KEY_DATA_BLOB_MAGIC;
943 header->dwVersion = BCRYPT_KEY_DATA_BLOB_VERSION1;
944 header->cbKeyData = key->u.s.secret_len;
945 memcpy( &header[1], key->u.s.secret, key->u.s.secret_len );
946 return STATUS_SUCCESS;
949 FIXME( "unsupported key type %s\n", debugstr_w(type) );
950 return STATUS_NOT_IMPLEMENTED;
953 static NTSTATUS key_duplicate( struct key *key_orig, struct key *key_copy )
955 UCHAR *buffer;
957 if (!key_is_symmetric( key_orig )) return STATUS_NOT_IMPLEMENTED;
959 if (!(buffer = heap_alloc( key_orig->u.s.secret_len ))) return STATUS_NO_MEMORY;
960 memcpy( buffer, key_orig->u.s.secret, key_orig->u.s.secret_len );
962 memset( key_copy, 0, sizeof(*key_copy) );
963 key_copy->hdr = key_orig->hdr;
964 key_copy->alg_id = key_orig->alg_id;
965 key_copy->u.s.mode = key_orig->u.s.mode;
966 key_copy->u.s.block_size = key_orig->u.s.block_size;
967 key_copy->u.s.secret = buffer;
968 key_copy->u.s.secret_len = key_orig->u.s.secret_len;
970 return STATUS_SUCCESS;
972 #endif
974 #if defined(HAVE_GNUTLS_CIPHER_INIT) && !defined(HAVE_COMMONCRYPTO_COMMONCRYPTOR_H)
975 static NTSTATUS key_symmetric_init( struct key *key, struct algorithm *alg, const UCHAR *secret, ULONG secret_len )
977 UCHAR *buffer;
979 if (!libgnutls_handle) return STATUS_INTERNAL_ERROR;
981 switch (alg->id)
983 case ALG_ID_AES:
984 break;
986 default:
987 FIXME( "algorithm %u not supported\n", alg->id );
988 return STATUS_NOT_SUPPORTED;
991 if (!(key->u.s.block_size = get_block_size( alg ))) return STATUS_INVALID_PARAMETER;
992 if (!(buffer = heap_alloc( secret_len ))) return STATUS_NO_MEMORY;
993 memcpy( buffer, secret, secret_len );
995 key->alg_id = alg->id;
996 key->u.s.mode = alg->mode;
997 key->u.s.handle = 0; /* initialized on first use */
998 key->u.s.secret = buffer;
999 key->u.s.secret_len = secret_len;
1001 return STATUS_SUCCESS;
1004 static NTSTATUS set_key_property( struct key *key, const WCHAR *prop, UCHAR *value, ULONG size, ULONG flags )
1006 if (!strcmpW( prop, BCRYPT_CHAINING_MODE ))
1008 if (!strncmpW( (WCHAR *)value, BCRYPT_CHAIN_MODE_ECB, size ))
1010 key->u.s.mode = MODE_ID_ECB;
1011 return STATUS_SUCCESS;
1013 else if (!strncmpW( (WCHAR *)value, BCRYPT_CHAIN_MODE_CBC, size ))
1015 key->u.s.mode = MODE_ID_CBC;
1016 return STATUS_SUCCESS;
1018 else if (!strncmpW( (WCHAR *)value, BCRYPT_CHAIN_MODE_GCM, size ))
1020 key->u.s.mode = MODE_ID_GCM;
1021 return STATUS_SUCCESS;
1023 else
1025 FIXME( "unsupported mode %s\n", debugstr_wn( (WCHAR *)value, size ) );
1026 return STATUS_NOT_IMPLEMENTED;
1030 FIXME( "unsupported key property %s\n", debugstr_w(prop) );
1031 return STATUS_NOT_IMPLEMENTED;
1034 static gnutls_cipher_algorithm_t get_gnutls_cipher( const struct key *key )
1036 switch (key->alg_id)
1038 case ALG_ID_AES:
1039 WARN( "handle block size\n" );
1040 switch (key->u.s.mode)
1042 case MODE_ID_GCM:
1043 if (key->u.s.secret_len == 16) return GNUTLS_CIPHER_AES_128_GCM;
1044 if (key->u.s.secret_len == 32) return GNUTLS_CIPHER_AES_256_GCM;
1045 break;
1046 case MODE_ID_ECB: /* can be emulated with CBC + empty IV */
1047 case MODE_ID_CBC:
1048 if (key->u.s.secret_len == 16) return GNUTLS_CIPHER_AES_128_CBC;
1049 if (key->u.s.secret_len == 24) return GNUTLS_CIPHER_AES_192_CBC;
1050 if (key->u.s.secret_len == 32) return GNUTLS_CIPHER_AES_256_CBC;
1051 break;
1052 default:
1053 break;
1055 FIXME( "AES mode %u with key length %u not supported\n", key->u.s.mode, key->u.s.secret_len );
1056 return GNUTLS_CIPHER_UNKNOWN;
1058 default:
1059 FIXME( "algorithm %u not supported\n", key->alg_id );
1060 return GNUTLS_CIPHER_UNKNOWN;
1064 static NTSTATUS key_symmetric_set_params( struct key *key, UCHAR *iv, ULONG iv_len )
1066 gnutls_cipher_algorithm_t cipher;
1067 gnutls_datum_t secret, vector;
1068 int ret;
1070 if (key->u.s.handle)
1072 pgnutls_cipher_deinit( key->u.s.handle );
1073 key->u.s.handle = NULL;
1076 if ((cipher = get_gnutls_cipher( key )) == GNUTLS_CIPHER_UNKNOWN)
1077 return STATUS_NOT_SUPPORTED;
1079 secret.data = key->u.s.secret;
1080 secret.size = key->u.s.secret_len;
1081 if (iv)
1083 vector.data = iv;
1084 vector.size = iv_len;
1087 if ((ret = pgnutls_cipher_init( &key->u.s.handle, cipher, &secret, iv ? &vector : NULL )))
1089 pgnutls_perror( ret );
1090 return STATUS_INTERNAL_ERROR;
1093 return STATUS_SUCCESS;
1096 static NTSTATUS key_symmetric_set_auth_data( struct key *key, UCHAR *auth_data, ULONG len )
1098 int ret;
1100 if (!auth_data) return STATUS_SUCCESS;
1102 if ((ret = pgnutls_cipher_add_auth( key->u.s.handle, auth_data, len )))
1104 pgnutls_perror( ret );
1105 return STATUS_INTERNAL_ERROR;
1108 return STATUS_SUCCESS;
1111 static NTSTATUS key_symmetric_encrypt( struct key *key, const UCHAR *input, ULONG input_len, UCHAR *output,
1112 ULONG output_len )
1114 int ret;
1116 if ((ret = pgnutls_cipher_encrypt2( key->u.s.handle, input, input_len, output, output_len )))
1118 pgnutls_perror( ret );
1119 return STATUS_INTERNAL_ERROR;
1122 return STATUS_SUCCESS;
1125 static NTSTATUS key_symmetric_decrypt( struct key *key, const UCHAR *input, ULONG input_len, UCHAR *output,
1126 ULONG output_len )
1128 int ret;
1130 if ((ret = pgnutls_cipher_decrypt2( key->u.s.handle, input, input_len, output, output_len )))
1132 pgnutls_perror( ret );
1133 return STATUS_INTERNAL_ERROR;
1136 return STATUS_SUCCESS;
1139 static NTSTATUS key_symmetric_get_tag( struct key *key, UCHAR *tag, ULONG len )
1141 int ret;
1143 if ((ret = pgnutls_cipher_tag( key->u.s.handle, tag, len )))
1145 pgnutls_perror( ret );
1146 return STATUS_INTERNAL_ERROR;
1149 return STATUS_SUCCESS;
1152 static NTSTATUS key_destroy( struct key *key )
1154 if (key->u.s.handle) pgnutls_cipher_deinit( key->u.s.handle );
1155 heap_free( key->u.s.secret );
1156 heap_free( key );
1157 return STATUS_SUCCESS;
1159 #elif defined(HAVE_COMMONCRYPTO_COMMONCRYPTOR_H) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
1160 static NTSTATUS key_symmetric_init( struct key *key, struct algorithm *alg, const UCHAR *secret, ULONG secret_len )
1162 UCHAR *buffer;
1164 switch (alg->id)
1166 case ALG_ID_AES:
1167 switch (alg->mode)
1169 case MODE_ID_ECB:
1170 case MODE_ID_CBC:
1171 break;
1172 default:
1173 FIXME( "mode %u not supported\n", alg->mode );
1174 return STATUS_NOT_SUPPORTED;
1176 break;
1178 default:
1179 FIXME( "algorithm %u not supported\n", alg->id );
1180 return STATUS_NOT_SUPPORTED;
1183 if (!(key->u.s.block_size = get_block_size( alg ))) return STATUS_INVALID_PARAMETER;
1184 if (!(buffer = heap_alloc( secret_len ))) return STATUS_NO_MEMORY;
1185 memcpy( buffer, secret, secret_len );
1187 key->alg_id = alg->id;
1188 key->u.s.mode = alg->mode;
1189 key->u.s.ref_encrypt = NULL; /* initialized on first use */
1190 key->u.s.ref_decrypt = NULL;
1191 key->u.s.secret = buffer;
1192 key->u.s.secret_len = secret_len;
1194 return STATUS_SUCCESS;
1197 static NTSTATUS set_key_property( struct key *key, const WCHAR *prop, UCHAR *value, ULONG size, ULONG flags )
1199 if (!strcmpW( prop, BCRYPT_CHAINING_MODE ))
1201 if (!strncmpW( (WCHAR *)value, BCRYPT_CHAIN_MODE_ECB, size ))
1203 key->u.s.mode = MODE_ID_ECB;
1204 return STATUS_SUCCESS;
1206 else if (!strncmpW( (WCHAR *)value, BCRYPT_CHAIN_MODE_CBC, size ))
1208 key->u.s.mode = MODE_ID_CBC;
1209 return STATUS_SUCCESS;
1211 else
1213 FIXME( "unsupported mode %s\n", debugstr_wn( (WCHAR *)value, size ) );
1214 return STATUS_NOT_IMPLEMENTED;
1218 FIXME( "unsupported key property %s\n", debugstr_w(prop) );
1219 return STATUS_NOT_IMPLEMENTED;
1222 static CCMode get_cryptor_mode( struct key *key )
1224 switch (key->u.s.mode)
1226 case MODE_ID_ECB: return kCCModeECB;
1227 case MODE_ID_CBC: return kCCModeCBC;
1228 default:
1229 FIXME( "unsupported mode %u\n", key->u.s.mode );
1230 return 0;
1234 static NTSTATUS key_symmetric_set_params( struct key *key, UCHAR *iv, ULONG iv_len )
1236 CCCryptorStatus status;
1237 CCMode mode;
1239 if (!(mode = get_cryptor_mode( key ))) return STATUS_NOT_SUPPORTED;
1241 if (key->u.s.ref_encrypt)
1243 CCCryptorRelease( key->u.s.ref_encrypt );
1244 key->u.s.ref_encrypt = NULL;
1246 if (key->u.s.ref_decrypt)
1248 CCCryptorRelease( key->u.s.ref_decrypt );
1249 key->u.s.ref_decrypt = NULL;
1252 if ((status = CCCryptorCreateWithMode( kCCEncrypt, mode, kCCAlgorithmAES128, ccNoPadding, iv, key->u.s.secret,
1253 key->u.s.secret_len, NULL, 0, 0, 0, &key->u.s.ref_encrypt )) != kCCSuccess)
1255 WARN( "CCCryptorCreateWithMode failed %d\n", status );
1256 return STATUS_INTERNAL_ERROR;
1258 if ((status = CCCryptorCreateWithMode( kCCDecrypt, mode, kCCAlgorithmAES128, ccNoPadding, iv, key->u.s.secret,
1259 key->u.s.secret_len, NULL, 0, 0, 0, &key->u.s.ref_decrypt )) != kCCSuccess)
1261 WARN( "CCCryptorCreateWithMode failed %d\n", status );
1262 CCCryptorRelease( key->u.s.ref_encrypt );
1263 key->u.s.ref_encrypt = NULL;
1264 return STATUS_INTERNAL_ERROR;
1267 return STATUS_SUCCESS;
1270 static NTSTATUS key_symmetric_set_auth_data( struct key *key, UCHAR *auth_data, ULONG len )
1272 FIXME( "not implemented on Mac\n" );
1273 return STATUS_NOT_IMPLEMENTED;
1276 static NTSTATUS key_symmetric_encrypt( struct key *key, const UCHAR *input, ULONG input_len, UCHAR *output,
1277 ULONG output_len )
1279 CCCryptorStatus status;
1281 if ((status = CCCryptorUpdate( key->u.s.ref_encrypt, input, input_len, output, output_len, NULL )) != kCCSuccess)
1283 WARN( "CCCryptorUpdate failed %d\n", status );
1284 return STATUS_INTERNAL_ERROR;
1287 return STATUS_SUCCESS;
1290 static NTSTATUS key_symmetric_decrypt( struct key *key, const UCHAR *input, ULONG input_len, UCHAR *output,
1291 ULONG output_len )
1293 CCCryptorStatus status;
1295 if ((status = CCCryptorUpdate( key->u.s.ref_decrypt, input, input_len, output, output_len, NULL )) != kCCSuccess)
1297 WARN( "CCCryptorUpdate failed %d\n", status );
1298 return STATUS_INTERNAL_ERROR;
1301 return STATUS_SUCCESS;
1304 static NTSTATUS key_symmetric_get_tag( struct key *key, UCHAR *tag, ULONG len )
1306 FIXME( "not implemented on Mac\n" );
1307 return STATUS_NOT_IMPLEMENTED;
1310 static NTSTATUS key_destroy( struct key *key )
1312 if (key->u.s.ref_encrypt) CCCryptorRelease( key->u.s.ref_encrypt );
1313 if (key->u.s.ref_decrypt) CCCryptorRelease( key->u.s.ref_decrypt );
1314 heap_free( key->u.s.secret );
1315 heap_free( key );
1316 return STATUS_SUCCESS;
1318 #else
1319 static NTSTATUS key_symmetric_init( struct key *key, struct algorithm *alg, const UCHAR *secret, ULONG secret_len )
1321 ERR( "support for keys not available at build time\n" );
1322 return STATUS_NOT_IMPLEMENTED;
1325 static NTSTATUS set_key_property( struct key *key, const WCHAR *prop, UCHAR *value, ULONG size, ULONG flags )
1327 ERR( "support for keys not available at build time\n" );
1328 return STATUS_NOT_IMPLEMENTED;
1331 static NTSTATUS key_duplicate( struct key *key_orig, struct key *key_copy )
1333 ERR( "support for keys not available at build time\n" );
1334 return STATUS_NOT_IMPLEMENTED;
1337 static NTSTATUS key_symmetric_set_params( struct key *key, UCHAR *iv, ULONG iv_len )
1339 ERR( "support for keys not available at build time\n" );
1340 return STATUS_NOT_IMPLEMENTED;
1343 static NTSTATUS key_symmetric_set_auth_data( struct key *key, UCHAR *auth_data, ULONG len )
1345 ERR( "support for keys not available at build time\n" );
1346 return STATUS_NOT_IMPLEMENTED;
1349 static NTSTATUS key_symmetric_encrypt( struct key *key, const UCHAR *input, ULONG input_len, UCHAR *output,
1350 ULONG output_len )
1352 ERR( "support for keys not available at build time\n" );
1353 return STATUS_NOT_IMPLEMENTED;
1356 static NTSTATUS key_symmetric_decrypt( struct key *key, const UCHAR *input, ULONG input_len, UCHAR *output,
1357 ULONG output_len )
1359 ERR( "support for keys not available at build time\n" );
1360 return STATUS_NOT_IMPLEMENTED;
1363 static NTSTATUS key_symmetric_get_tag( struct key *key, UCHAR *tag, ULONG len )
1365 ERR( "support for keys not available at build time\n" );
1366 return STATUS_NOT_IMPLEMENTED;
1369 static NTSTATUS key_destroy( struct key *key )
1371 ERR( "support for keys not available at build time\n" );
1372 return STATUS_NOT_IMPLEMENTED;
1375 static NTSTATUS key_export( struct key *key, const WCHAR *type, UCHAR *output, ULONG output_len, ULONG *size )
1377 ERR( "support for keys not available at build time\n" );
1378 return STATUS_NOT_IMPLEMENTED;
1381 static inline BOOL key_is_symmetric( struct key *key )
1383 ERR( "support for keys not available at build time\n" );
1384 return FALSE;
1386 #endif
1388 NTSTATUS WINAPI BCryptGenerateSymmetricKey( BCRYPT_ALG_HANDLE algorithm, BCRYPT_KEY_HANDLE *handle,
1389 UCHAR *object, ULONG object_len, UCHAR *secret, ULONG secret_len,
1390 ULONG flags )
1392 struct algorithm *alg = algorithm;
1393 struct key *key;
1394 NTSTATUS status;
1396 TRACE( "%p, %p, %p, %u, %p, %u, %08x\n", algorithm, handle, object, object_len, secret, secret_len, flags );
1398 if (!alg || alg->hdr.magic != MAGIC_ALG) return STATUS_INVALID_HANDLE;
1399 if (object) FIXME( "ignoring object buffer\n" );
1401 if (!(key = heap_alloc( sizeof(*key) ))) return STATUS_NO_MEMORY;
1402 key->hdr.magic = MAGIC_KEY;
1404 if ((status = key_symmetric_init( key, alg, secret, secret_len )))
1406 heap_free( key );
1407 return status;
1410 *handle = key;
1411 return STATUS_SUCCESS;
1414 NTSTATUS WINAPI BCryptImportKey(BCRYPT_ALG_HANDLE algorithm, BCRYPT_KEY_HANDLE decrypt_key, LPCWSTR type,
1415 BCRYPT_KEY_HANDLE *key, PUCHAR object, ULONG object_len, PUCHAR input,
1416 ULONG input_len, ULONG flags)
1418 struct algorithm *alg = algorithm;
1420 TRACE("%p, %p, %s, %p, %p, %u, %p, %u, %u\n", algorithm, decrypt_key, debugstr_w(type), key, object,
1421 object_len, input, input_len, flags);
1423 if (!alg || alg->hdr.magic != MAGIC_ALG) return STATUS_INVALID_HANDLE;
1424 if (!key || !type || !input) return STATUS_INVALID_PARAMETER;
1426 if (decrypt_key)
1428 FIXME("Decrypting of key not yet supported\n");
1429 return STATUS_NO_MEMORY;
1432 if (!strcmpW(type, BCRYPT_KEY_DATA_BLOB))
1434 BCRYPT_KEY_DATA_BLOB_HEADER *key_header = (BCRYPT_KEY_DATA_BLOB_HEADER*)input;
1436 if (input_len < sizeof(BCRYPT_KEY_DATA_BLOB_HEADER))
1437 return STATUS_BUFFER_TOO_SMALL;
1439 if (key_header->dwMagic != BCRYPT_KEY_DATA_BLOB_MAGIC)
1440 return STATUS_INVALID_PARAMETER;
1442 if (key_header->dwVersion != BCRYPT_KEY_DATA_BLOB_VERSION1)
1444 FIXME("Unknown key data blob version: %d\n", key_header->dwVersion);
1445 return STATUS_INVALID_PARAMETER;
1448 if (key_header->cbKeyData + sizeof(BCRYPT_KEY_DATA_BLOB_HEADER) > input_len)
1449 return STATUS_INVALID_PARAMETER;
1451 return BCryptGenerateSymmetricKey(algorithm, key, object, object_len, (UCHAR*)&key_header[1], key_header->cbKeyData, 0);
1454 FIXME("Unsupported key type: %s\n", debugstr_w(type));
1455 return STATUS_INVALID_PARAMETER;
1458 NTSTATUS WINAPI BCryptExportKey(BCRYPT_KEY_HANDLE export_key, BCRYPT_KEY_HANDLE encrypt_key, LPCWSTR type,
1459 PUCHAR output, ULONG output_len, ULONG *size, ULONG flags)
1461 struct key *key = export_key;
1463 TRACE("%p, %p, %s, %p, %u, %p, %u\n", key, encrypt_key, debugstr_w(type), output, output_len, size, flags);
1465 if (!key || key->hdr.magic != MAGIC_KEY) return STATUS_INVALID_HANDLE;
1466 if (!output || !output_len || !size) return STATUS_INVALID_PARAMETER;
1468 if (encrypt_key)
1470 FIXME("Encryption of key not yet supported\n");
1471 return STATUS_NO_MEMORY;
1474 return key_export( key, type, output, output_len, size );
1477 NTSTATUS WINAPI BCryptDuplicateKey( BCRYPT_KEY_HANDLE handle, BCRYPT_KEY_HANDLE *handle_copy,
1478 UCHAR *object, ULONG object_len, ULONG flags )
1480 struct key *key_orig = handle;
1481 struct key *key_copy;
1482 NTSTATUS status;
1484 TRACE( "%p, %p, %p, %u, %08x\n", handle, handle_copy, object, object_len, flags );
1485 if (object) FIXME( "ignoring object buffer\n" );
1487 if (!key_orig || key_orig->hdr.magic != MAGIC_KEY) return STATUS_INVALID_HANDLE;
1488 if (!handle_copy) return STATUS_INVALID_PARAMETER;
1489 if (!(key_copy = heap_alloc( sizeof(*key_copy) ))) return STATUS_NO_MEMORY;
1491 if ((status = key_duplicate( key_orig, key_copy )))
1493 heap_free( key_copy );
1494 return status;
1497 *handle_copy = key_copy;
1498 return STATUS_SUCCESS;
1501 NTSTATUS WINAPI BCryptDestroyKey( BCRYPT_KEY_HANDLE handle )
1503 struct key *key = handle;
1505 TRACE( "%p\n", handle );
1507 if (!key || key->hdr.magic != MAGIC_KEY) return STATUS_INVALID_HANDLE;
1508 return key_destroy( key );
1511 NTSTATUS WINAPI BCryptEncrypt( BCRYPT_KEY_HANDLE handle, UCHAR *input, ULONG input_len,
1512 void *padding, UCHAR *iv, ULONG iv_len, UCHAR *output,
1513 ULONG output_len, ULONG *ret_len, ULONG flags )
1515 struct key *key = handle;
1516 ULONG bytes_left = input_len;
1517 UCHAR *buf, *src, *dst;
1518 NTSTATUS status;
1520 TRACE( "%p, %p, %u, %p, %p, %u, %p, %u, %p, %08x\n", handle, input, input_len,
1521 padding, iv, iv_len, output, output_len, ret_len, flags );
1523 if (!key || key->hdr.magic != MAGIC_KEY) return STATUS_INVALID_HANDLE;
1524 if (!key_is_symmetric( key ))
1526 FIXME( "encryption with asymmetric keys not yet supported\n" );
1527 return STATUS_NOT_IMPLEMENTED;
1529 if (flags & ~BCRYPT_BLOCK_PADDING)
1531 FIXME( "flags %08x not implemented\n", flags );
1532 return STATUS_NOT_IMPLEMENTED;
1535 if (key->u.s.mode == MODE_ID_GCM)
1537 BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO *auth_info = padding;
1539 if (!auth_info) return STATUS_INVALID_PARAMETER;
1540 if (!auth_info->pbNonce) return STATUS_INVALID_PARAMETER;
1541 if (!auth_info->pbTag) return STATUS_INVALID_PARAMETER;
1542 if (auth_info->cbTag < 12 || auth_info->cbTag > 16) return STATUS_INVALID_PARAMETER;
1543 if (auth_info->dwFlags & BCRYPT_AUTH_MODE_CHAIN_CALLS_FLAG)
1544 FIXME( "call chaining not implemented\n" );
1546 if ((status = key_symmetric_set_params( key, auth_info->pbNonce, auth_info->cbNonce )))
1547 return status;
1549 *ret_len = input_len;
1550 if (flags & BCRYPT_BLOCK_PADDING) return STATUS_INVALID_PARAMETER;
1551 if (input && !output) return STATUS_SUCCESS;
1552 if (output_len < *ret_len) return STATUS_BUFFER_TOO_SMALL;
1554 if ((status = key_symmetric_set_auth_data( key, auth_info->pbAuthData, auth_info->cbAuthData )))
1555 return status;
1556 if ((status = key_symmetric_encrypt( key, input, input_len, output, output_len ))) return status;
1558 return key_symmetric_get_tag( key, auth_info->pbTag, auth_info->cbTag );
1561 if ((status = key_symmetric_set_params( key, iv, iv_len ))) return status;
1562 *ret_len = input_len;
1564 if (flags & BCRYPT_BLOCK_PADDING)
1565 *ret_len = (input_len + key->u.s.block_size) & ~(key->u.s.block_size - 1);
1566 else if (input_len & (key->u.s.block_size - 1))
1567 return STATUS_INVALID_BUFFER_SIZE;
1569 if (!output) return STATUS_SUCCESS;
1570 if (output_len < *ret_len) return STATUS_BUFFER_TOO_SMALL;
1571 if (key->u.s.mode == MODE_ID_ECB && iv) return STATUS_INVALID_PARAMETER;
1573 src = input;
1574 dst = output;
1575 while (bytes_left >= key->u.s.block_size)
1577 if ((status = key_symmetric_encrypt( key, src, key->u.s.block_size, dst, key->u.s.block_size )))
1578 return status;
1579 if (key->u.s.mode == MODE_ID_ECB && (status = key_symmetric_set_params( key, NULL, 0 ))) return status;
1580 bytes_left -= key->u.s.block_size;
1581 src += key->u.s.block_size;
1582 dst += key->u.s.block_size;
1585 if (flags & BCRYPT_BLOCK_PADDING)
1587 if (!(buf = heap_alloc( key->u.s.block_size ))) return STATUS_NO_MEMORY;
1588 memcpy( buf, src, bytes_left );
1589 memset( buf + bytes_left, key->u.s.block_size - bytes_left, key->u.s.block_size - bytes_left );
1590 status = key_symmetric_encrypt( key, buf, key->u.s.block_size, dst, key->u.s.block_size );
1591 heap_free( buf );
1594 return status;
1597 NTSTATUS WINAPI BCryptDecrypt( BCRYPT_KEY_HANDLE handle, UCHAR *input, ULONG input_len,
1598 void *padding, UCHAR *iv, ULONG iv_len, UCHAR *output,
1599 ULONG output_len, ULONG *ret_len, ULONG flags )
1601 struct key *key = handle;
1602 ULONG bytes_left = input_len;
1603 UCHAR *buf, *src, *dst;
1604 NTSTATUS status;
1606 TRACE( "%p, %p, %u, %p, %p, %u, %p, %u, %p, %08x\n", handle, input, input_len,
1607 padding, iv, iv_len, output, output_len, ret_len, flags );
1609 if (!key || key->hdr.magic != MAGIC_KEY) return STATUS_INVALID_HANDLE;
1610 if (!key_is_symmetric( key ))
1612 FIXME( "decryption with asymmetric keys not yet supported\n" );
1613 return STATUS_NOT_IMPLEMENTED;
1615 if (flags & ~BCRYPT_BLOCK_PADDING)
1617 FIXME( "flags %08x not supported\n", flags );
1618 return STATUS_NOT_IMPLEMENTED;
1621 if (key->u.s.mode == MODE_ID_GCM)
1623 BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO *auth_info = padding;
1624 UCHAR tag[16];
1626 if (!auth_info) return STATUS_INVALID_PARAMETER;
1627 if (!auth_info->pbNonce) return STATUS_INVALID_PARAMETER;
1628 if (!auth_info->pbTag) return STATUS_INVALID_PARAMETER;
1629 if (auth_info->cbTag < 12 || auth_info->cbTag > 16) return STATUS_INVALID_PARAMETER;
1631 if ((status = key_symmetric_set_params( key, auth_info->pbNonce, auth_info->cbNonce )))
1632 return status;
1634 *ret_len = input_len;
1635 if (flags & BCRYPT_BLOCK_PADDING) return STATUS_INVALID_PARAMETER;
1636 if (!output) return STATUS_SUCCESS;
1637 if (output_len < *ret_len) return STATUS_BUFFER_TOO_SMALL;
1639 if ((status = key_symmetric_set_auth_data( key, auth_info->pbAuthData, auth_info->cbAuthData )))
1640 return status;
1641 if ((status = key_symmetric_decrypt( key, input, input_len, output, output_len ))) return status;
1643 if ((status = key_symmetric_get_tag( key, tag, sizeof(tag) ))) return status;
1644 if (memcmp( tag, auth_info->pbTag, auth_info->cbTag )) return STATUS_AUTH_TAG_MISMATCH;
1646 return STATUS_SUCCESS;
1649 if ((status = key_symmetric_set_params( key, iv, iv_len ))) return status;
1651 *ret_len = input_len;
1653 if (input_len & (key->u.s.block_size - 1)) return STATUS_INVALID_BUFFER_SIZE;
1654 if (!output) return STATUS_SUCCESS;
1655 if (flags & BCRYPT_BLOCK_PADDING)
1657 if (output_len + key->u.s.block_size < *ret_len) return STATUS_BUFFER_TOO_SMALL;
1658 if (input_len < key->u.s.block_size) return STATUS_BUFFER_TOO_SMALL;
1659 bytes_left -= key->u.s.block_size;
1661 else if (output_len < *ret_len) return STATUS_BUFFER_TOO_SMALL;
1663 if (key->u.s.mode == MODE_ID_ECB && iv) return STATUS_INVALID_PARAMETER;
1665 src = input;
1666 dst = output;
1667 while (bytes_left >= key->u.s.block_size)
1669 if ((status = key_symmetric_decrypt( key, src, key->u.s.block_size, dst, key->u.s.block_size )))
1670 return status;
1671 if (key->u.s.mode == MODE_ID_ECB && (status = key_symmetric_set_params( key, NULL, 0 ))) return status;
1672 bytes_left -= key->u.s.block_size;
1673 src += key->u.s.block_size;
1674 dst += key->u.s.block_size;
1677 if (flags & BCRYPT_BLOCK_PADDING)
1679 if (!(buf = heap_alloc( key->u.s.block_size ))) return STATUS_NO_MEMORY;
1680 status = key_symmetric_decrypt( key, src, key->u.s.block_size, buf, key->u.s.block_size );
1681 if (!status && buf[ key->u.s.block_size - 1 ] <= key->u.s.block_size)
1683 *ret_len -= buf[ key->u.s.block_size - 1 ];
1684 if (output_len < *ret_len) status = STATUS_BUFFER_TOO_SMALL;
1685 else memcpy( dst, buf, key->u.s.block_size - buf[ key->u.s.block_size - 1 ] );
1687 else status = STATUS_UNSUCCESSFUL; /* FIXME: invalid padding */
1688 heap_free( buf );
1691 return status;
1694 NTSTATUS WINAPI BCryptSetProperty( BCRYPT_HANDLE handle, const WCHAR *prop, UCHAR *value, ULONG size, ULONG flags )
1696 struct object *object = handle;
1698 TRACE( "%p, %s, %p, %u, %08x\n", handle, debugstr_w(prop), value, size, flags );
1700 if (!object) return STATUS_INVALID_HANDLE;
1702 switch (object->magic)
1704 case MAGIC_ALG:
1706 struct algorithm *alg = (struct algorithm *)object;
1707 return set_alg_property( alg, prop, value, size, flags );
1709 case MAGIC_KEY:
1711 struct key *key = (struct key *)object;
1712 return set_key_property( key, prop, value, size, flags );
1714 default:
1715 WARN( "unknown magic %08x\n", object->magic );
1716 return STATUS_INVALID_HANDLE;
1720 BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
1722 switch (reason)
1724 case DLL_PROCESS_ATTACH:
1725 instance = hinst;
1726 DisableThreadLibraryCalls( hinst );
1727 #if defined(HAVE_GNUTLS_CIPHER_INIT) && !defined(HAVE_COMMONCRYPTO_COMMONCRYPTOR_H)
1728 gnutls_initialize();
1729 #endif
1730 break;
1732 case DLL_PROCESS_DETACH:
1733 if (reserved) break;
1734 #if defined(HAVE_GNUTLS_CIPHER_INIT) && !defined(HAVE_COMMONCRYPTO_COMMONCRYPTOR_H)
1735 gnutls_uninitialize();
1736 #endif
1737 break;
1739 return TRUE;