bcrypt: Implement support for ECB chain mode.
[wine.git] / dlls / bcrypt / bcrypt_main.c
blob1aeafd0dd8282cbef2a2867f876fe6898e92096e
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 {
237 ULONG object_length;
238 ULONG hash_length;
239 ULONG block_bits;
240 const WCHAR *alg_name;
241 } alg_props[] = {
242 /* ALG_ID_AES */ { 654, 0, 0, BCRYPT_AES_ALGORITHM },
243 /* ALG_ID_MD2 */ { 270, 16, 128, BCRYPT_MD2_ALGORITHM },
244 /* ALG_ID_MD4 */ { 270, 16, 512, BCRYPT_MD4_ALGORITHM },
245 /* ALG_ID_MD5 */ { 274, 16, 512, BCRYPT_MD5_ALGORITHM },
246 /* ALG_ID_RNG */ { 0, 0, 0, BCRYPT_RNG_ALGORITHM },
247 /* ALG_ID_SHA1 */ { 278, 20, 512, BCRYPT_SHA1_ALGORITHM },
248 /* ALG_ID_SHA256 */ { 286, 32, 512, BCRYPT_SHA256_ALGORITHM },
249 /* ALG_ID_SHA384 */ { 382, 48, 1024, BCRYPT_SHA384_ALGORITHM },
250 /* ALG_ID_SHA512 */ { 382, 64, 1024, BCRYPT_SHA512_ALGORITHM }
253 struct algorithm
255 struct object hdr;
256 enum alg_id id;
257 enum mode_id mode;
258 BOOL hmac;
261 NTSTATUS WINAPI BCryptGenRandom(BCRYPT_ALG_HANDLE handle, UCHAR *buffer, ULONG count, ULONG flags)
263 const DWORD supported_flags = BCRYPT_USE_SYSTEM_PREFERRED_RNG;
264 struct algorithm *algorithm = handle;
266 TRACE("%p, %p, %u, %08x - semi-stub\n", handle, buffer, count, flags);
268 if (!algorithm)
270 /* It's valid to call without an algorithm if BCRYPT_USE_SYSTEM_PREFERRED_RNG
271 * is set. In this case the preferred system RNG is used.
273 if (!(flags & BCRYPT_USE_SYSTEM_PREFERRED_RNG))
274 return STATUS_INVALID_HANDLE;
276 else if (algorithm->hdr.magic != MAGIC_ALG || algorithm->id != ALG_ID_RNG)
277 return STATUS_INVALID_HANDLE;
279 if (!buffer)
280 return STATUS_INVALID_PARAMETER;
282 if (flags & ~supported_flags)
283 FIXME("unsupported flags %08x\n", flags & ~supported_flags);
285 if (algorithm)
286 FIXME("ignoring selected algorithm\n");
288 /* When zero bytes are requested the function returns success too. */
289 if (!count)
290 return STATUS_SUCCESS;
292 if (algorithm || (flags & BCRYPT_USE_SYSTEM_PREFERRED_RNG))
294 if (RtlGenRandom(buffer, count))
295 return STATUS_SUCCESS;
298 FIXME("called with unsupported parameters, returning error\n");
299 return STATUS_NOT_IMPLEMENTED;
302 NTSTATUS WINAPI BCryptOpenAlgorithmProvider( BCRYPT_ALG_HANDLE *handle, LPCWSTR id, LPCWSTR implementation, DWORD flags )
304 const DWORD supported_flags = BCRYPT_ALG_HANDLE_HMAC_FLAG;
305 struct algorithm *alg;
306 enum alg_id alg_id;
308 TRACE( "%p, %s, %s, %08x\n", handle, wine_dbgstr_w(id), wine_dbgstr_w(implementation), flags );
310 if (!handle || !id) return STATUS_INVALID_PARAMETER;
311 if (flags & ~supported_flags)
313 FIXME( "unsupported flags %08x\n", flags & ~supported_flags);
314 return STATUS_NOT_IMPLEMENTED;
317 if (!strcmpW( id, BCRYPT_AES_ALGORITHM )) alg_id = ALG_ID_AES;
318 else if (!strcmpW( id, BCRYPT_MD2_ALGORITHM )) alg_id = ALG_ID_MD2;
319 else if (!strcmpW( id, BCRYPT_MD4_ALGORITHM )) alg_id = ALG_ID_MD4;
320 else if (!strcmpW( id, BCRYPT_MD5_ALGORITHM )) alg_id = ALG_ID_MD5;
321 else if (!strcmpW( id, BCRYPT_RNG_ALGORITHM )) alg_id = ALG_ID_RNG;
322 else if (!strcmpW( id, BCRYPT_SHA1_ALGORITHM )) alg_id = ALG_ID_SHA1;
323 else if (!strcmpW( id, BCRYPT_SHA256_ALGORITHM )) alg_id = ALG_ID_SHA256;
324 else if (!strcmpW( id, BCRYPT_SHA384_ALGORITHM )) alg_id = ALG_ID_SHA384;
325 else if (!strcmpW( id, BCRYPT_SHA512_ALGORITHM )) alg_id = ALG_ID_SHA512;
326 else
328 FIXME( "algorithm %s not supported\n", debugstr_w(id) );
329 return STATUS_NOT_IMPLEMENTED;
331 if (implementation && strcmpW( implementation, MS_PRIMITIVE_PROVIDER ))
333 FIXME( "implementation %s not supported\n", debugstr_w(implementation) );
334 return STATUS_NOT_IMPLEMENTED;
337 if (!(alg = heap_alloc( sizeof(*alg) ))) return STATUS_NO_MEMORY;
338 alg->hdr.magic = MAGIC_ALG;
339 alg->id = alg_id;
340 alg->mode = MODE_ID_CBC;
341 alg->hmac = flags & BCRYPT_ALG_HANDLE_HMAC_FLAG;
343 *handle = alg;
344 return STATUS_SUCCESS;
347 NTSTATUS WINAPI BCryptCloseAlgorithmProvider( BCRYPT_ALG_HANDLE handle, DWORD flags )
349 struct algorithm *alg = handle;
351 TRACE( "%p, %08x\n", handle, flags );
353 if (!alg || alg->hdr.magic != MAGIC_ALG) return STATUS_INVALID_HANDLE;
354 heap_free( alg );
355 return STATUS_SUCCESS;
358 NTSTATUS WINAPI BCryptGetFipsAlgorithmMode(BOOLEAN *enabled)
360 FIXME("%p - semi-stub\n", enabled);
362 if (!enabled)
363 return STATUS_INVALID_PARAMETER;
365 *enabled = FALSE;
366 return STATUS_SUCCESS;
369 struct hash_impl
371 union
373 MD2_CTX md2;
374 MD4_CTX md4;
375 MD5_CTX md5;
376 SHA_CTX sha1;
377 SHA256_CTX sha256;
378 SHA512_CTX sha512;
379 } u;
382 static NTSTATUS hash_init( struct hash_impl *hash, enum alg_id alg_id )
384 switch (alg_id)
386 case ALG_ID_MD2:
387 md2_init( &hash->u.md2 );
388 break;
390 case ALG_ID_MD4:
391 MD4Init( &hash->u.md4 );
392 break;
394 case ALG_ID_MD5:
395 MD5Init( &hash->u.md5 );
396 break;
398 case ALG_ID_SHA1:
399 A_SHAInit( &hash->u.sha1 );
400 break;
402 case ALG_ID_SHA256:
403 sha256_init( &hash->u.sha256 );
404 break;
406 case ALG_ID_SHA384:
407 sha384_init( &hash->u.sha512 );
408 break;
410 case ALG_ID_SHA512:
411 sha512_init( &hash->u.sha512 );
412 break;
414 default:
415 ERR( "unhandled id %u\n", alg_id );
416 return STATUS_NOT_IMPLEMENTED;
418 return STATUS_SUCCESS;
421 static NTSTATUS hash_update( struct hash_impl *hash, enum alg_id alg_id,
422 UCHAR *input, ULONG size )
424 switch (alg_id)
426 case ALG_ID_MD2:
427 md2_update( &hash->u.md2, input, size );
428 break;
430 case ALG_ID_MD4:
431 MD4Update( &hash->u.md4, input, size );
432 break;
434 case ALG_ID_MD5:
435 MD5Update( &hash->u.md5, input, size );
436 break;
438 case ALG_ID_SHA1:
439 A_SHAUpdate( &hash->u.sha1, input, size );
440 break;
442 case ALG_ID_SHA256:
443 sha256_update( &hash->u.sha256, input, size );
444 break;
446 case ALG_ID_SHA384:
447 sha384_update( &hash->u.sha512, input, size );
448 break;
450 case ALG_ID_SHA512:
451 sha512_update( &hash->u.sha512, input, size );
452 break;
454 default:
455 ERR( "unhandled id %u\n", alg_id );
456 return STATUS_NOT_IMPLEMENTED;
458 return STATUS_SUCCESS;
461 static NTSTATUS hash_finish( struct hash_impl *hash, enum alg_id alg_id,
462 UCHAR *output, ULONG size )
464 switch (alg_id)
466 case ALG_ID_MD2:
467 md2_finalize( &hash->u.md2, output );
468 break;
470 case ALG_ID_MD4:
471 MD4Final( &hash->u.md4 );
472 memcpy( output, hash->u.md4.digest, 16 );
473 break;
475 case ALG_ID_MD5:
476 MD5Final( &hash->u.md5 );
477 memcpy( output, hash->u.md5.digest, 16 );
478 break;
480 case ALG_ID_SHA1:
481 A_SHAFinal( &hash->u.sha1, (ULONG *)output );
482 break;
484 case ALG_ID_SHA256:
485 sha256_finalize( &hash->u.sha256, output );
486 break;
488 case ALG_ID_SHA384:
489 sha384_finalize( &hash->u.sha512, output );
490 break;
492 case ALG_ID_SHA512:
493 sha512_finalize( &hash->u.sha512, output );
494 break;
496 default:
497 ERR( "unhandled id %u\n", alg_id );
498 return STATUS_NOT_IMPLEMENTED;
500 return STATUS_SUCCESS;
503 struct hash
505 struct object hdr;
506 enum alg_id alg_id;
507 BOOL hmac;
508 struct hash_impl outer;
509 struct hash_impl inner;
512 #define BLOCK_LENGTH_AES 16
514 static NTSTATUS generic_alg_property( enum alg_id id, const WCHAR *prop, UCHAR *buf, ULONG size, ULONG *ret_size )
516 if (!strcmpW( prop, BCRYPT_OBJECT_LENGTH ))
518 if (!alg_props[id].object_length)
519 return STATUS_NOT_SUPPORTED;
520 *ret_size = sizeof(ULONG);
521 if (size < sizeof(ULONG))
522 return STATUS_BUFFER_TOO_SMALL;
523 if (buf)
524 *(ULONG *)buf = alg_props[id].object_length;
525 return STATUS_SUCCESS;
528 if (!strcmpW( prop, BCRYPT_HASH_LENGTH ))
530 if (!alg_props[id].hash_length)
531 return STATUS_NOT_SUPPORTED;
532 *ret_size = sizeof(ULONG);
533 if (size < sizeof(ULONG))
534 return STATUS_BUFFER_TOO_SMALL;
535 if(buf)
536 *(ULONG*)buf = alg_props[id].hash_length;
537 return STATUS_SUCCESS;
540 if (!strcmpW( prop, BCRYPT_ALGORITHM_NAME ))
542 *ret_size = (strlenW(alg_props[id].alg_name)+1)*sizeof(WCHAR);
543 if (size < *ret_size)
544 return STATUS_BUFFER_TOO_SMALL;
545 if(buf)
546 memcpy(buf, alg_props[id].alg_name, *ret_size);
547 return STATUS_SUCCESS;
550 return STATUS_NOT_IMPLEMENTED;
553 static NTSTATUS get_alg_property( const struct algorithm *alg, const WCHAR *prop, UCHAR *buf, ULONG size, ULONG *ret_size )
555 NTSTATUS status;
557 status = generic_alg_property( alg->id, prop, buf, size, ret_size );
558 if (status != STATUS_NOT_IMPLEMENTED)
559 return status;
561 switch (alg->id)
563 case ALG_ID_AES:
564 if (!strcmpW( prop, BCRYPT_BLOCK_LENGTH ))
566 *ret_size = sizeof(ULONG);
567 if (size < sizeof(ULONG))
568 return STATUS_BUFFER_TOO_SMALL;
569 if (buf)
570 *(ULONG *)buf = BLOCK_LENGTH_AES;
571 return STATUS_SUCCESS;
573 if (!strcmpW( prop, BCRYPT_CHAINING_MODE ))
575 const WCHAR *mode;
576 switch (alg->mode)
578 case MODE_ID_ECB: mode = BCRYPT_CHAIN_MODE_ECB; break;
579 case MODE_ID_CBC: mode = BCRYPT_CHAIN_MODE_CBC; break;
580 case MODE_ID_GCM: mode = BCRYPT_CHAIN_MODE_GCM; break;
581 default: return STATUS_NOT_IMPLEMENTED;
584 *ret_size = 64;
585 if (size < *ret_size) return STATUS_BUFFER_TOO_SMALL;
586 memcpy( buf, mode, (strlenW(mode) + 1) * sizeof(WCHAR) );
587 return STATUS_SUCCESS;
589 if (!strcmpW( prop, BCRYPT_KEY_LENGTHS ))
591 BCRYPT_KEY_LENGTHS_STRUCT *key_lengths = (void *)buf;
592 *ret_size = sizeof(*key_lengths);
593 if (key_lengths && size < *ret_size) return STATUS_BUFFER_TOO_SMALL;
594 if (key_lengths)
596 key_lengths->dwMinLength = 128;
597 key_lengths->dwMaxLength = 256;
598 key_lengths->dwIncrement = 64;
600 return STATUS_SUCCESS;
602 if (!strcmpW( prop, BCRYPT_AUTH_TAG_LENGTH ))
604 BCRYPT_AUTH_TAG_LENGTHS_STRUCT *tag_length = (void *)buf;
605 if (alg->mode != MODE_ID_GCM) return STATUS_NOT_SUPPORTED;
606 *ret_size = sizeof(*tag_length);
607 if (tag_length && size < *ret_size) return STATUS_BUFFER_TOO_SMALL;
608 if (tag_length)
610 tag_length->dwMinLength = 12;
611 tag_length->dwMaxLength = 16;
612 tag_length->dwIncrement = 1;
614 return STATUS_SUCCESS;
616 break;
618 default:
619 break;
622 FIXME( "unsupported property %s\n", debugstr_w(prop) );
623 return STATUS_NOT_IMPLEMENTED;
626 static NTSTATUS set_alg_property( struct algorithm *alg, const WCHAR *prop, UCHAR *value, ULONG size, ULONG flags )
628 switch (alg->id)
630 case ALG_ID_AES:
631 if (!strcmpW( prop, BCRYPT_CHAINING_MODE ))
633 if (!strncmpW( (WCHAR *)value, BCRYPT_CHAIN_MODE_ECB, size ))
635 alg->mode = MODE_ID_ECB;
636 return STATUS_SUCCESS;
638 else if (!strncmpW( (WCHAR *)value, BCRYPT_CHAIN_MODE_CBC, size ))
640 alg->mode = MODE_ID_CBC;
641 return STATUS_SUCCESS;
643 else if (!strncmpW( (WCHAR *)value, BCRYPT_CHAIN_MODE_GCM, size ))
645 alg->mode = MODE_ID_GCM;
646 return STATUS_SUCCESS;
648 else
650 FIXME( "unsupported mode %s\n", debugstr_wn( (WCHAR *)value, size ) );
651 return STATUS_NOT_IMPLEMENTED;
654 FIXME( "unsupported aes algorithm property %s\n", debugstr_w(prop) );
655 return STATUS_NOT_IMPLEMENTED;
657 default:
658 FIXME( "unsupported algorithm %u\n", alg->id );
659 return STATUS_NOT_IMPLEMENTED;
663 static NTSTATUS get_hash_property( const struct hash *hash, const WCHAR *prop, UCHAR *buf, ULONG size, ULONG *ret_size )
665 NTSTATUS status;
667 status = generic_alg_property( hash->alg_id, prop, buf, size, ret_size );
668 if (status == STATUS_NOT_IMPLEMENTED)
669 FIXME( "unsupported property %s\n", debugstr_w(prop) );
670 return status;
673 NTSTATUS WINAPI BCryptGetProperty( BCRYPT_HANDLE handle, LPCWSTR prop, UCHAR *buffer, ULONG count, ULONG *res, ULONG flags )
675 struct object *object = handle;
677 TRACE( "%p, %s, %p, %u, %p, %08x\n", handle, wine_dbgstr_w(prop), buffer, count, res, flags );
679 if (!object) return STATUS_INVALID_HANDLE;
680 if (!prop || !res) return STATUS_INVALID_PARAMETER;
682 switch (object->magic)
684 case MAGIC_ALG:
686 const struct algorithm *alg = (const struct algorithm *)object;
687 return get_alg_property( alg, prop, buffer, count, res );
689 case MAGIC_HASH:
691 const struct hash *hash = (const struct hash *)object;
692 return get_hash_property( hash, prop, buffer, count, res );
694 default:
695 WARN( "unknown magic %08x\n", object->magic );
696 return STATUS_INVALID_HANDLE;
700 NTSTATUS WINAPI BCryptCreateHash( BCRYPT_ALG_HANDLE algorithm, BCRYPT_HASH_HANDLE *handle, UCHAR *object, ULONG objectlen,
701 UCHAR *secret, ULONG secretlen, ULONG flags )
703 struct algorithm *alg = algorithm;
704 UCHAR buffer[MAX_HASH_BLOCK_BITS / 8] = {0};
705 struct hash *hash;
706 int block_bytes;
707 NTSTATUS status;
708 int i;
710 TRACE( "%p, %p, %p, %u, %p, %u, %08x - stub\n", algorithm, handle, object, objectlen,
711 secret, secretlen, flags );
712 if (flags)
714 FIXME( "unimplemented flags %08x\n", flags );
715 return STATUS_NOT_IMPLEMENTED;
718 if (!alg || alg->hdr.magic != MAGIC_ALG) return STATUS_INVALID_HANDLE;
719 if (object) FIXME( "ignoring object buffer\n" );
721 if (!(hash = heap_alloc( sizeof(*hash) ))) return STATUS_NO_MEMORY;
722 hash->hdr.magic = MAGIC_HASH;
723 hash->alg_id = alg->id;
724 hash->hmac = alg->hmac;
726 /* initialize hash */
727 if ((status = hash_init( &hash->inner, hash->alg_id ))) goto end;
728 if (!hash->hmac) goto end;
730 /* initialize hmac */
731 if ((status = hash_init( &hash->outer, hash->alg_id ))) goto end;
732 block_bytes = alg_props[hash->alg_id].block_bits / 8;
733 if (secretlen > block_bytes)
735 struct hash_impl temp;
736 if ((status = hash_init( &temp, hash->alg_id ))) goto end;
737 if ((status = hash_update( &temp, hash->alg_id, secret, secretlen ))) goto end;
738 if ((status = hash_finish( &temp, hash->alg_id, buffer,
739 alg_props[hash->alg_id].hash_length ))) goto end;
741 else
743 memcpy( buffer, secret, secretlen );
745 for (i = 0; i < block_bytes; i++) buffer[i] ^= 0x5c;
746 if ((status = hash_update( &hash->outer, hash->alg_id, buffer, block_bytes ))) goto end;
747 for (i = 0; i < block_bytes; i++) buffer[i] ^= (0x5c ^ 0x36);
748 status = hash_update( &hash->inner, hash->alg_id, buffer, block_bytes );
750 end:
751 if (status != STATUS_SUCCESS)
753 heap_free( hash );
754 return status;
757 *handle = hash;
758 return STATUS_SUCCESS;
761 NTSTATUS WINAPI BCryptDuplicateHash( BCRYPT_HASH_HANDLE handle, BCRYPT_HASH_HANDLE *handle_copy,
762 UCHAR *object, ULONG objectlen, ULONG flags )
764 struct hash *hash_orig = handle;
765 struct hash *hash_copy;
767 TRACE( "%p, %p, %p, %u, %u\n", handle, handle_copy, object, objectlen, flags );
769 if (!hash_orig || hash_orig->hdr.magic != MAGIC_HASH) return STATUS_INVALID_HANDLE;
770 if (!handle_copy) return STATUS_INVALID_PARAMETER;
771 if (object) FIXME( "ignoring object buffer\n" );
773 if (!(hash_copy = heap_alloc( sizeof(*hash_copy) )))
774 return STATUS_NO_MEMORY;
776 memcpy( hash_copy, hash_orig, sizeof(*hash_orig) );
778 *handle_copy = hash_copy;
779 return STATUS_SUCCESS;
782 NTSTATUS WINAPI BCryptDestroyHash( BCRYPT_HASH_HANDLE handle )
784 struct hash *hash = handle;
786 TRACE( "%p\n", handle );
788 if (!hash || hash->hdr.magic != MAGIC_HASH) return STATUS_INVALID_HANDLE;
789 heap_free( hash );
790 return STATUS_SUCCESS;
793 NTSTATUS WINAPI BCryptHashData( BCRYPT_HASH_HANDLE handle, UCHAR *input, ULONG size, ULONG flags )
795 struct hash *hash = handle;
797 TRACE( "%p, %p, %u, %08x\n", handle, input, size, flags );
799 if (!hash || hash->hdr.magic != MAGIC_HASH) return STATUS_INVALID_HANDLE;
800 if (!input) return STATUS_SUCCESS;
802 return hash_update( &hash->inner, hash->alg_id, input, size );
805 NTSTATUS WINAPI BCryptFinishHash( BCRYPT_HASH_HANDLE handle, UCHAR *output, ULONG size, ULONG flags )
807 UCHAR buffer[MAX_HASH_OUTPUT_BYTES];
808 struct hash *hash = handle;
809 NTSTATUS status;
810 int hash_length;
812 TRACE( "%p, %p, %u, %08x\n", handle, output, size, flags );
814 if (!hash || hash->hdr.magic != MAGIC_HASH) return STATUS_INVALID_HANDLE;
815 if (!output) return STATUS_INVALID_PARAMETER;
817 if (!hash->hmac)
818 return hash_finish( &hash->inner, hash->alg_id, output, size );
820 hash_length = alg_props[hash->alg_id].hash_length;
821 if ((status = hash_finish( &hash->inner, hash->alg_id, buffer, hash_length ))) return status;
822 if ((status = hash_update( &hash->outer, hash->alg_id, buffer, hash_length ))) return status;
823 return hash_finish( &hash->outer, hash->alg_id, output, size );
826 NTSTATUS WINAPI BCryptHash( BCRYPT_ALG_HANDLE algorithm, UCHAR *secret, ULONG secretlen,
827 UCHAR *input, ULONG inputlen, UCHAR *output, ULONG outputlen )
829 NTSTATUS status;
830 BCRYPT_HASH_HANDLE handle;
832 TRACE( "%p, %p, %u, %p, %u, %p, %u\n", algorithm, secret, secretlen,
833 input, inputlen, output, outputlen );
835 status = BCryptCreateHash( algorithm, &handle, NULL, 0, secret, secretlen, 0);
836 if (status != STATUS_SUCCESS)
838 return status;
841 status = BCryptHashData( handle, input, inputlen, 0 );
842 if (status != STATUS_SUCCESS)
844 BCryptDestroyHash( handle );
845 return status;
848 status = BCryptFinishHash( handle, output, outputlen, 0 );
849 if (status != STATUS_SUCCESS)
851 BCryptDestroyHash( handle );
852 return status;
855 return BCryptDestroyHash( handle );
858 #if defined(HAVE_GNUTLS_CIPHER_INIT) && !defined(HAVE_COMMONCRYPTO_COMMONCRYPTOR_H)
859 struct key
861 struct object hdr;
862 enum alg_id alg_id;
863 enum mode_id mode;
864 ULONG block_size;
865 gnutls_cipher_hd_t handle;
866 UCHAR *secret;
867 ULONG secret_len;
869 #elif defined(HAVE_COMMONCRYPTO_COMMONCRYPTOR_H) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
870 struct key
872 struct object hdr;
873 enum alg_id alg_id;
874 enum mode_id mode;
875 ULONG block_size;
876 CCCryptorRef ref_encrypt;
877 CCCryptorRef ref_decrypt;
878 UCHAR *secret;
879 ULONG secret_len;
881 #else
882 struct key
884 struct object hdr;
885 enum mode_id mode;
886 ULONG block_size;
888 #endif
890 #if defined(HAVE_GNUTLS_CIPHER_INIT) || defined(HAVE_COMMONCRYPTO_COMMONCRYPTOR_H) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
891 static ULONG get_block_size( struct algorithm *alg )
893 ULONG ret = 0, size = sizeof(ret);
894 get_alg_property( alg, BCRYPT_BLOCK_LENGTH, (UCHAR *)&ret, sizeof(ret), &size );
895 return ret;
898 static NTSTATUS key_export( struct key *key, const WCHAR *type, UCHAR *output, ULONG output_len, ULONG *size )
900 if (!strcmpW( type, BCRYPT_KEY_DATA_BLOB ))
902 BCRYPT_KEY_DATA_BLOB_HEADER *header = (BCRYPT_KEY_DATA_BLOB_HEADER *)output;
903 ULONG req_size = sizeof(BCRYPT_KEY_DATA_BLOB_HEADER) + key->secret_len;
905 *size = req_size;
906 if (output_len < req_size) return STATUS_BUFFER_TOO_SMALL;
908 header->dwMagic = BCRYPT_KEY_DATA_BLOB_MAGIC;
909 header->dwVersion = BCRYPT_KEY_DATA_BLOB_VERSION1;
910 header->cbKeyData = key->secret_len;
911 memcpy( &header[1], key->secret, key->secret_len );
912 return STATUS_SUCCESS;
915 FIXME( "unsupported key type %s\n", debugstr_w(type) );
916 return STATUS_NOT_IMPLEMENTED;
919 static NTSTATUS key_duplicate( struct key *key_orig, struct key *key_copy )
921 UCHAR *buffer;
923 if (!(buffer = heap_alloc( key_orig->secret_len ))) return STATUS_NO_MEMORY;
924 memcpy( buffer, key_orig->secret, key_orig->secret_len );
926 memset( key_copy, 0, sizeof(*key_copy) );
927 key_copy->hdr = key_orig->hdr;
928 key_copy->alg_id = key_orig->alg_id;
929 key_copy->mode = key_orig->mode;
930 key_copy->block_size = key_orig->block_size;
931 key_copy->secret = buffer;
932 key_copy->secret_len = key_orig->secret_len;
934 return STATUS_SUCCESS;
936 #endif
938 #if defined(HAVE_GNUTLS_CIPHER_INIT) && !defined(HAVE_COMMONCRYPTO_COMMONCRYPTOR_H)
939 static NTSTATUS key_init( struct key *key, struct algorithm *alg, const UCHAR *secret, ULONG secret_len )
941 UCHAR *buffer;
943 if (!libgnutls_handle) return STATUS_INTERNAL_ERROR;
945 switch (alg->id)
947 case ALG_ID_AES:
948 break;
950 default:
951 FIXME( "algorithm %u not supported\n", alg->id );
952 return STATUS_NOT_SUPPORTED;
955 if (!(key->block_size = get_block_size( alg ))) return STATUS_INVALID_PARAMETER;
956 if (!(buffer = heap_alloc( secret_len ))) return STATUS_NO_MEMORY;
957 memcpy( buffer, secret, secret_len );
959 key->alg_id = alg->id;
960 key->mode = alg->mode;
961 key->handle = 0; /* initialized on first use */
962 key->secret = buffer;
963 key->secret_len = secret_len;
965 return STATUS_SUCCESS;
968 static NTSTATUS set_key_property( struct key *key, const WCHAR *prop, UCHAR *value, ULONG size, ULONG flags )
970 if (!strcmpW( prop, BCRYPT_CHAINING_MODE ))
972 if (!strncmpW( (WCHAR *)value, BCRYPT_CHAIN_MODE_ECB, size ))
974 key->mode = MODE_ID_ECB;
975 return STATUS_SUCCESS;
977 else if (!strncmpW( (WCHAR *)value, BCRYPT_CHAIN_MODE_CBC, size ))
979 key->mode = MODE_ID_CBC;
980 return STATUS_SUCCESS;
982 else if (!strncmpW( (WCHAR *)value, BCRYPT_CHAIN_MODE_GCM, size ))
984 key->mode = MODE_ID_GCM;
985 return STATUS_SUCCESS;
987 else
989 FIXME( "unsupported mode %s\n", debugstr_wn( (WCHAR *)value, size ) );
990 return STATUS_NOT_IMPLEMENTED;
994 FIXME( "unsupported key property %s\n", debugstr_w(prop) );
995 return STATUS_NOT_IMPLEMENTED;
998 static gnutls_cipher_algorithm_t get_gnutls_cipher( const struct key *key )
1000 switch (key->alg_id)
1002 case ALG_ID_AES:
1003 WARN( "handle block size\n" );
1004 switch (key->mode)
1006 case MODE_ID_GCM: return GNUTLS_CIPHER_AES_128_GCM;
1007 case MODE_ID_ECB: /* can be emulated with CBC + empty IV */
1008 case MODE_ID_CBC:
1009 default: return GNUTLS_CIPHER_AES_128_CBC;
1011 default:
1012 FIXME( "algorithm %u not supported\n", key->alg_id );
1013 return GNUTLS_CIPHER_UNKNOWN;
1017 static NTSTATUS key_set_params( struct key *key, UCHAR *iv, ULONG iv_len )
1019 gnutls_cipher_algorithm_t cipher;
1020 gnutls_datum_t secret, vector;
1021 int ret;
1023 if (key->handle)
1025 pgnutls_cipher_deinit( key->handle );
1026 key->handle = NULL;
1029 if ((cipher = get_gnutls_cipher( key )) == GNUTLS_CIPHER_UNKNOWN)
1030 return STATUS_NOT_SUPPORTED;
1032 secret.data = key->secret;
1033 secret.size = key->secret_len;
1034 if (iv)
1036 vector.data = iv;
1037 vector.size = iv_len;
1040 if ((ret = pgnutls_cipher_init( &key->handle, cipher, &secret, iv ? &vector : NULL )))
1042 pgnutls_perror( ret );
1043 return STATUS_INTERNAL_ERROR;
1046 return STATUS_SUCCESS;
1049 static NTSTATUS key_set_auth_data( struct key *key, UCHAR *auth_data, ULONG len )
1051 int ret;
1053 if ((ret = pgnutls_cipher_add_auth( key->handle, auth_data, len )))
1055 pgnutls_perror( ret );
1056 return STATUS_INTERNAL_ERROR;
1059 return STATUS_SUCCESS;
1062 static NTSTATUS key_encrypt( struct key *key, const UCHAR *input, ULONG input_len, UCHAR *output,
1063 ULONG output_len )
1065 int ret;
1067 if ((ret = pgnutls_cipher_encrypt2( key->handle, input, input_len, output, output_len )))
1069 pgnutls_perror( ret );
1070 return STATUS_INTERNAL_ERROR;
1073 return STATUS_SUCCESS;
1076 static NTSTATUS key_decrypt( struct key *key, const UCHAR *input, ULONG input_len, UCHAR *output,
1077 ULONG output_len )
1079 int ret;
1081 if ((ret = pgnutls_cipher_decrypt2( key->handle, input, input_len, output, output_len )))
1083 pgnutls_perror( ret );
1084 return STATUS_INTERNAL_ERROR;
1087 return STATUS_SUCCESS;
1090 static NTSTATUS key_get_tag( struct key *key, UCHAR *tag, ULONG len )
1092 int ret;
1094 if ((ret = pgnutls_cipher_tag( key->handle, tag, len )))
1096 pgnutls_perror( ret );
1097 return STATUS_INTERNAL_ERROR;
1100 return STATUS_SUCCESS;
1103 static NTSTATUS key_destroy( struct key *key )
1105 if (key->handle) pgnutls_cipher_deinit( key->handle );
1106 heap_free( key->secret );
1107 heap_free( key );
1108 return STATUS_SUCCESS;
1110 #elif defined(HAVE_COMMONCRYPTO_COMMONCRYPTOR_H) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
1111 static NTSTATUS key_init( struct key *key, struct algorithm *alg, const UCHAR *secret, ULONG secret_len )
1113 UCHAR *buffer;
1115 switch (alg->id)
1117 case ALG_ID_AES:
1118 switch (alg->mode)
1120 case MODE_ID_ECB:
1121 case MODE_ID_CBC:
1122 break;
1123 default:
1124 FIXME( "mode %u not supported\n", alg->mode );
1125 return STATUS_NOT_SUPPORTED;
1127 break;
1129 default:
1130 FIXME( "algorithm %u not supported\n", alg->id );
1131 return STATUS_NOT_SUPPORTED;
1134 if (!(key->block_size = get_block_size( alg ))) return STATUS_INVALID_PARAMETER;
1135 if (!(buffer = heap_alloc( secret_len ))) return STATUS_NO_MEMORY;
1136 memcpy( buffer, secret, secret_len );
1138 key->alg_id = alg->id;
1139 key->mode = alg->mode;
1140 key->ref_encrypt = NULL; /* initialized on first use */
1141 key->ref_decrypt = NULL;
1142 key->secret = buffer;
1143 key->secret_len = secret_len;
1145 return STATUS_SUCCESS;
1148 static NTSTATUS set_key_property( struct key *key, const WCHAR *prop, UCHAR *value, ULONG size, ULONG flags )
1150 if (!strcmpW( prop, BCRYPT_CHAINING_MODE ))
1152 if (!strncmpW( (WCHAR *)value, BCRYPT_CHAIN_MODE_ECB, size ))
1154 key->mode = MODE_ID_ECB;
1155 return STATUS_SUCCESS;
1157 else if (!strncmpW( (WCHAR *)value, BCRYPT_CHAIN_MODE_CBC, size ))
1159 key->mode = MODE_ID_CBC;
1160 return STATUS_SUCCESS;
1162 else
1164 FIXME( "unsupported mode %s\n", debugstr_wn( (WCHAR *)value, size ) );
1165 return STATUS_NOT_IMPLEMENTED;
1169 FIXME( "unsupported key property %s\n", debugstr_w(prop) );
1170 return STATUS_NOT_IMPLEMENTED;
1173 static CCMode get_cryptor_mode( struct key *key )
1175 switch (key->mode)
1177 case MODE_ID_ECB: return kCCModeECB;
1178 case MODE_ID_CBC: return kCCModeCBC;
1179 default:
1180 FIXME( "unsupported mode %u\n", key->mode );
1181 return 0;
1185 static NTSTATUS key_set_params( struct key *key, UCHAR *iv, ULONG iv_len )
1187 CCCryptorStatus status;
1188 CCMode mode;
1190 if (!(mode = get_cryptor_mode( key ))) return STATUS_NOT_SUPPORTED;
1192 if (key->ref_encrypt)
1194 CCCryptorRelease( key->ref_encrypt );
1195 key->ref_encrypt = NULL;
1197 if (key->ref_decrypt)
1199 CCCryptorRelease( key->ref_decrypt );
1200 key->ref_decrypt = NULL;
1203 if ((status = CCCryptorCreateWithMode( kCCEncrypt, mode, kCCAlgorithmAES128, ccNoPadding, iv, key->secret,
1204 key->secret_len, NULL, 0, 0, 0, &key->ref_encrypt )) != kCCSuccess)
1206 WARN( "CCCryptorCreateWithMode failed %d\n", status );
1207 return STATUS_INTERNAL_ERROR;
1209 if ((status = CCCryptorCreateWithMode( kCCDecrypt, mode, kCCAlgorithmAES128, ccNoPadding, iv, key->secret,
1210 key->secret_len, NULL, 0, 0, 0, &key->ref_decrypt )) != kCCSuccess)
1212 WARN( "CCCryptorCreateWithMode failed %d\n", status );
1213 CCCryptorRelease( key->ref_encrypt );
1214 key->ref_encrypt = NULL;
1215 return STATUS_INTERNAL_ERROR;
1218 return STATUS_SUCCESS;
1221 static NTSTATUS key_set_auth_data( struct key *key, UCHAR *auth_data, ULONG len )
1223 FIXME( "not implemented on Mac\n" );
1224 return STATUS_NOT_IMPLEMENTED;
1227 static NTSTATUS key_encrypt( struct key *key, const UCHAR *input, ULONG input_len, UCHAR *output,
1228 ULONG output_len )
1230 CCCryptorStatus status;
1232 if ((status = CCCryptorUpdate( key->ref_encrypt, input, input_len, output, output_len, NULL )) != kCCSuccess)
1234 WARN( "CCCryptorUpdate failed %d\n", status );
1235 return STATUS_INTERNAL_ERROR;
1238 return STATUS_SUCCESS;
1241 static NTSTATUS key_decrypt( struct key *key, const UCHAR *input, ULONG input_len, UCHAR *output,
1242 ULONG output_len )
1244 CCCryptorStatus status;
1246 if ((status = CCCryptorUpdate( key->ref_decrypt, input, input_len, output, output_len, NULL )) != kCCSuccess)
1248 WARN( "CCCryptorUpdate failed %d\n", status );
1249 return STATUS_INTERNAL_ERROR;
1252 return STATUS_SUCCESS;
1255 static NTSTATUS key_get_tag( struct key *key, UCHAR *tag, ULONG len )
1257 FIXME( "not implemented on Mac\n" );
1258 return STATUS_NOT_IMPLEMENTED;
1261 static NTSTATUS key_destroy( struct key *key )
1263 if (key->ref_encrypt) CCCryptorRelease( key->ref_encrypt );
1264 if (key->ref_decrypt) CCCryptorRelease( key->ref_decrypt );
1265 heap_free( key->secret );
1266 heap_free( key );
1267 return STATUS_SUCCESS;
1269 #else
1270 static NTSTATUS key_init( struct key *key, struct algorithm *alg, const UCHAR *secret, ULONG secret_len )
1272 ERR( "support for keys not available at build time\n" );
1273 return STATUS_NOT_IMPLEMENTED;
1276 static NTSTATUS set_key_property( struct key *key, const WCHAR *prop, UCHAR *value, ULONG size, ULONG flags )
1278 ERR( "support for keys not available at build time\n" );
1279 return STATUS_NOT_IMPLEMENTED;
1282 static NTSTATUS key_duplicate( struct key *key_orig, struct key *key_copy )
1284 ERR( "support for keys not available at build time\n" );
1285 return STATUS_NOT_IMPLEMENTED;
1288 static NTSTATUS key_set_params( struct key *key, UCHAR *iv, ULONG iv_len )
1290 ERR( "support for keys not available at build time\n" );
1291 return STATUS_NOT_IMPLEMENTED;
1294 static NTSTATUS key_set_auth_data( struct key *key, UCHAR *auth_data, ULONG len )
1296 ERR( "support for keys not available at build time\n" );
1297 return STATUS_NOT_IMPLEMENTED;
1300 static NTSTATUS key_encrypt( struct key *key, const UCHAR *input, ULONG input_len, UCHAR *output,
1301 ULONG output_len )
1303 ERR( "support for keys not available at build time\n" );
1304 return STATUS_NOT_IMPLEMENTED;
1307 static NTSTATUS key_decrypt( struct key *key, const UCHAR *input, ULONG input_len, UCHAR *output,
1308 ULONG output_len )
1310 ERR( "support for keys not available at build time\n" );
1311 return STATUS_NOT_IMPLEMENTED;
1314 static NTSTATUS key_get_tag( struct key *key, UCHAR *tag, ULONG len )
1316 ERR( "support for keys not available at build time\n" );
1317 return STATUS_NOT_IMPLEMENTED;
1320 static NTSTATUS key_destroy( struct key *key )
1322 ERR( "support for keys not available at build time\n" );
1323 return STATUS_NOT_IMPLEMENTED;
1326 static NTSTATUS key_export( struct key *key, const WCHAR *type, UCHAR *output, ULONG output_len, ULONG *size )
1328 ERR( "support for keys not available at build time\n" );
1329 return STATUS_NOT_IMPLEMENTED;
1331 #endif
1333 NTSTATUS WINAPI BCryptGenerateSymmetricKey( BCRYPT_ALG_HANDLE algorithm, BCRYPT_KEY_HANDLE *handle,
1334 UCHAR *object, ULONG object_len, UCHAR *secret, ULONG secret_len,
1335 ULONG flags )
1337 struct algorithm *alg = algorithm;
1338 struct key *key;
1339 NTSTATUS status;
1341 TRACE( "%p, %p, %p, %u, %p, %u, %08x\n", algorithm, handle, object, object_len, secret, secret_len, flags );
1343 if (!alg || alg->hdr.magic != MAGIC_ALG) return STATUS_INVALID_HANDLE;
1344 if (object) FIXME( "ignoring object buffer\n" );
1346 if (!(key = heap_alloc( sizeof(*key) ))) return STATUS_NO_MEMORY;
1347 key->hdr.magic = MAGIC_KEY;
1349 if ((status = key_init( key, alg, secret, secret_len )))
1351 heap_free( key );
1352 return status;
1355 *handle = key;
1356 return STATUS_SUCCESS;
1359 NTSTATUS WINAPI BCryptImportKey(BCRYPT_ALG_HANDLE algorithm, BCRYPT_KEY_HANDLE decrypt_key, LPCWSTR type,
1360 BCRYPT_KEY_HANDLE *key, PUCHAR object, ULONG object_len, PUCHAR input,
1361 ULONG input_len, ULONG flags)
1363 struct algorithm *alg = algorithm;
1365 TRACE("%p, %p, %s, %p, %p, %u, %p, %u, %u\n", algorithm, decrypt_key, debugstr_w(type), key, object,
1366 object_len, input, input_len, flags);
1368 if (!alg || alg->hdr.magic != MAGIC_ALG) return STATUS_INVALID_HANDLE;
1369 if (!key || !type || !input) return STATUS_INVALID_PARAMETER;
1371 if (decrypt_key)
1373 FIXME("Decrypting of key not yet supported\n");
1374 return STATUS_NO_MEMORY;
1377 if (!strcmpW(type, BCRYPT_KEY_DATA_BLOB))
1379 BCRYPT_KEY_DATA_BLOB_HEADER *key_header = (BCRYPT_KEY_DATA_BLOB_HEADER*)input;
1381 if (input_len < sizeof(BCRYPT_KEY_DATA_BLOB_HEADER))
1382 return STATUS_BUFFER_TOO_SMALL;
1384 if (key_header->dwMagic != BCRYPT_KEY_DATA_BLOB_MAGIC)
1385 return STATUS_INVALID_PARAMETER;
1387 if (key_header->dwVersion != BCRYPT_KEY_DATA_BLOB_VERSION1)
1389 FIXME("Unknown key data blob version: %d\n", key_header->dwVersion);
1390 return STATUS_INVALID_PARAMETER;
1393 if (key_header->cbKeyData + sizeof(BCRYPT_KEY_DATA_BLOB_HEADER) > input_len)
1394 return STATUS_INVALID_PARAMETER;
1396 return BCryptGenerateSymmetricKey(algorithm, key, object, object_len, (UCHAR*)&key_header[1], key_header->cbKeyData, 0);
1399 FIXME("Unsupported key type: %s\n", debugstr_w(type));
1400 return STATUS_INVALID_PARAMETER;
1403 NTSTATUS WINAPI BCryptExportKey(BCRYPT_KEY_HANDLE export_key, BCRYPT_KEY_HANDLE encrypt_key, LPCWSTR type,
1404 PUCHAR output, ULONG output_len, ULONG *size, ULONG flags)
1406 struct key *key = export_key;
1408 TRACE("%p, %p, %s, %p, %u, %p, %u\n", key, encrypt_key, debugstr_w(type), output, output_len, size, flags);
1410 if (!key || key->hdr.magic != MAGIC_KEY) return STATUS_INVALID_HANDLE;
1411 if (!output || !output_len || !size) return STATUS_INVALID_PARAMETER;
1413 if (encrypt_key)
1415 FIXME("Encryption of key not yet supported\n");
1416 return STATUS_NO_MEMORY;
1419 return key_export( key, type, output, output_len, size );
1422 NTSTATUS WINAPI BCryptDuplicateKey( BCRYPT_KEY_HANDLE handle, BCRYPT_KEY_HANDLE *handle_copy,
1423 UCHAR *object, ULONG object_len, ULONG flags )
1425 struct key *key_orig = handle;
1426 struct key *key_copy;
1427 NTSTATUS status;
1429 TRACE( "%p, %p, %p, %u, %08x\n", handle, handle_copy, object, object_len, flags );
1430 if (object) FIXME( "ignoring object buffer\n" );
1432 if (!key_orig || key_orig->hdr.magic != MAGIC_KEY) return STATUS_INVALID_HANDLE;
1433 if (!handle_copy) return STATUS_INVALID_PARAMETER;
1434 if (!(key_copy = heap_alloc( sizeof(*key_copy) ))) return STATUS_NO_MEMORY;
1436 if ((status = key_duplicate( key_orig, key_copy )))
1438 heap_free( key_copy );
1439 return status;
1442 *handle_copy = key_copy;
1443 return STATUS_SUCCESS;
1446 NTSTATUS WINAPI BCryptDestroyKey( BCRYPT_KEY_HANDLE handle )
1448 struct key *key = handle;
1450 TRACE( "%p\n", handle );
1452 if (!key || key->hdr.magic != MAGIC_KEY) return STATUS_INVALID_HANDLE;
1453 return key_destroy( key );
1456 NTSTATUS WINAPI BCryptEncrypt( BCRYPT_KEY_HANDLE handle, UCHAR *input, ULONG input_len,
1457 void *padding, UCHAR *iv, ULONG iv_len, UCHAR *output,
1458 ULONG output_len, ULONG *ret_len, ULONG flags )
1460 struct key *key = handle;
1461 ULONG bytes_left = input_len;
1462 UCHAR *buf, *src, *dst;
1463 NTSTATUS status;
1465 TRACE( "%p, %p, %u, %p, %p, %u, %p, %u, %p, %08x\n", handle, input, input_len,
1466 padding, iv, iv_len, output, output_len, ret_len, flags );
1468 if (!key || key->hdr.magic != MAGIC_KEY) return STATUS_INVALID_HANDLE;
1469 if (flags & ~BCRYPT_BLOCK_PADDING)
1471 FIXME( "flags %08x not implemented\n", flags );
1472 return STATUS_NOT_IMPLEMENTED;
1475 if (key->mode == MODE_ID_GCM)
1477 BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO *auth_info = padding;
1479 if (!auth_info) return STATUS_INVALID_PARAMETER;
1480 if (!auth_info->pbNonce) return STATUS_INVALID_PARAMETER;
1481 if (!auth_info->pbTag) return STATUS_INVALID_PARAMETER;
1482 if (auth_info->cbTag < 12 || auth_info->cbTag > 16) return STATUS_INVALID_PARAMETER;
1483 if (auth_info->dwFlags & BCRYPT_AUTH_MODE_CHAIN_CALLS_FLAG)
1484 FIXME( "call chaining not implemented\n" );
1486 if ((status = key_set_params( key, auth_info->pbNonce, auth_info->cbNonce )))
1487 return status;
1489 *ret_len = input_len;
1490 if (flags & BCRYPT_BLOCK_PADDING) return STATUS_INVALID_PARAMETER;
1491 if (input && !output) return STATUS_SUCCESS;
1492 if (output_len < *ret_len) return STATUS_BUFFER_TOO_SMALL;
1494 if (auth_info->pbAuthData && (status = key_set_auth_data( key, auth_info->pbAuthData, auth_info->cbAuthData )))
1495 return status;
1496 if ((status = key_encrypt( key, input, input_len, output, output_len )))
1497 return status;
1499 return key_get_tag( key, auth_info->pbTag, auth_info->cbTag );
1502 if ((status = key_set_params( key, iv, iv_len ))) return status;
1504 *ret_len = input_len;
1506 if (flags & BCRYPT_BLOCK_PADDING)
1507 *ret_len = (input_len + key->block_size) & ~(key->block_size - 1);
1508 else if (input_len & (key->block_size - 1))
1509 return STATUS_INVALID_BUFFER_SIZE;
1511 if (!output) return STATUS_SUCCESS;
1512 if (output_len < *ret_len) return STATUS_BUFFER_TOO_SMALL;
1513 if (key->mode == MODE_ID_ECB && iv) return STATUS_INVALID_PARAMETER;
1515 src = input;
1516 dst = output;
1517 while (bytes_left >= key->block_size)
1519 if ((status = key_encrypt( key, src, key->block_size, dst, key->block_size ))) return status;
1520 if (key->mode == MODE_ID_ECB && (status = key_set_params( key, NULL, 0 ))) return status;
1521 bytes_left -= key->block_size;
1522 src += key->block_size;
1523 dst += key->block_size;
1526 if (flags & BCRYPT_BLOCK_PADDING)
1528 if (!(buf = heap_alloc( key->block_size ))) return STATUS_NO_MEMORY;
1529 memcpy( buf, src, bytes_left );
1530 memset( buf + bytes_left, key->block_size - bytes_left, key->block_size - bytes_left );
1531 status = key_encrypt( key, buf, key->block_size, dst, key->block_size );
1532 heap_free( buf );
1535 return status;
1538 NTSTATUS WINAPI BCryptDecrypt( BCRYPT_KEY_HANDLE handle, UCHAR *input, ULONG input_len,
1539 void *padding, UCHAR *iv, ULONG iv_len, UCHAR *output,
1540 ULONG output_len, ULONG *ret_len, ULONG flags )
1542 struct key *key = handle;
1543 ULONG bytes_left = input_len;
1544 UCHAR *buf, *src, *dst;
1545 NTSTATUS status;
1547 TRACE( "%p, %p, %u, %p, %p, %u, %p, %u, %p, %08x\n", handle, input, input_len,
1548 padding, iv, iv_len, output, output_len, ret_len, flags );
1550 if (!key || key->hdr.magic != MAGIC_KEY) return STATUS_INVALID_HANDLE;
1551 if (flags & ~BCRYPT_BLOCK_PADDING)
1553 FIXME( "flags %08x not supported\n", flags );
1554 return STATUS_NOT_IMPLEMENTED;
1557 if (key->mode == MODE_ID_GCM)
1559 BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO *auth_info = padding;
1560 UCHAR tag[16];
1562 if (!auth_info) return STATUS_INVALID_PARAMETER;
1563 if (!auth_info->pbNonce) return STATUS_INVALID_PARAMETER;
1564 if (!auth_info->pbTag) return STATUS_INVALID_PARAMETER;
1565 if (auth_info->cbTag < 12 || auth_info->cbTag > 16) return STATUS_INVALID_PARAMETER;
1567 if ((status = key_set_params( key, auth_info->pbNonce, auth_info->cbNonce )))
1568 return status;
1570 *ret_len = input_len;
1571 if (flags & BCRYPT_BLOCK_PADDING) return STATUS_INVALID_PARAMETER;
1572 if (!output) return STATUS_SUCCESS;
1573 if (output_len < *ret_len) return STATUS_BUFFER_TOO_SMALL;
1575 if (auth_info->pbAuthData && (status = key_set_auth_data( key, auth_info->pbAuthData, auth_info->cbAuthData )))
1576 return status;
1577 if ((status = key_decrypt( key, input, input_len, output, output_len )))
1578 return status;
1580 if ((status = key_get_tag( key, tag, sizeof(tag) )))
1581 return status;
1582 if (memcmp( tag, auth_info->pbTag, auth_info->cbTag ))
1583 return STATUS_AUTH_TAG_MISMATCH;
1585 return STATUS_SUCCESS;
1588 if ((status = key_set_params( key, iv, iv_len ))) return status;
1590 *ret_len = input_len;
1592 if (input_len & (key->block_size - 1)) return STATUS_INVALID_BUFFER_SIZE;
1593 if (!output) return STATUS_SUCCESS;
1594 if (flags & BCRYPT_BLOCK_PADDING)
1596 if (output_len + key->block_size < *ret_len) return STATUS_BUFFER_TOO_SMALL;
1597 if (input_len < key->block_size) return STATUS_BUFFER_TOO_SMALL;
1598 bytes_left -= key->block_size;
1600 else if (output_len < *ret_len) return STATUS_BUFFER_TOO_SMALL;
1602 if (key->mode == MODE_ID_ECB && iv) return STATUS_INVALID_PARAMETER;
1604 src = input;
1605 dst = output;
1606 while (bytes_left >= key->block_size)
1608 if ((status = key_decrypt( key, src, key->block_size, dst, key->block_size ))) return status;
1609 if (key->mode == MODE_ID_ECB && (status = key_set_params( key, NULL, 0 ))) return status;
1610 bytes_left -= key->block_size;
1611 src += key->block_size;
1612 dst += key->block_size;
1615 if (flags & BCRYPT_BLOCK_PADDING)
1617 if (!(buf = heap_alloc( key->block_size ))) return STATUS_NO_MEMORY;
1618 status = key_decrypt( key, src, key->block_size, buf, key->block_size );
1619 if (!status && buf[ key->block_size - 1 ] <= key->block_size)
1621 *ret_len -= buf[ key->block_size - 1 ];
1622 if (output_len < *ret_len) status = STATUS_BUFFER_TOO_SMALL;
1623 else memcpy( dst, buf, key->block_size - buf[ key->block_size - 1 ] );
1625 else
1626 status = STATUS_UNSUCCESSFUL; /* FIXME: invalid padding */
1627 heap_free( buf );
1630 return status;
1633 NTSTATUS WINAPI BCryptSetProperty( BCRYPT_HANDLE handle, const WCHAR *prop, UCHAR *value, ULONG size, ULONG flags )
1635 struct object *object = handle;
1637 TRACE( "%p, %s, %p, %u, %08x\n", handle, debugstr_w(prop), value, size, flags );
1639 if (!object) return STATUS_INVALID_HANDLE;
1641 switch (object->magic)
1643 case MAGIC_ALG:
1645 struct algorithm *alg = (struct algorithm *)object;
1646 return set_alg_property( alg, prop, value, size, flags );
1648 case MAGIC_KEY:
1650 struct key *key = (struct key *)object;
1651 return set_key_property( key, prop, value, size, flags );
1653 default:
1654 WARN( "unknown magic %08x\n", object->magic );
1655 return STATUS_INVALID_HANDLE;
1659 BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
1661 switch (reason)
1663 case DLL_PROCESS_ATTACH:
1664 instance = hinst;
1665 DisableThreadLibraryCalls( hinst );
1666 #if defined(HAVE_GNUTLS_CIPHER_INIT) && !defined(HAVE_COMMONCRYPTO_COMMONCRYPTOR_H)
1667 gnutls_initialize();
1668 #endif
1669 break;
1671 case DLL_PROCESS_DETACH:
1672 if (reserved) break;
1673 #if defined(HAVE_GNUTLS_CIPHER_INIT) && !defined(HAVE_COMMONCRYPTO_COMMONCRYPTOR_H)
1674 gnutls_uninitialize();
1675 #endif
1676 break;
1678 return TRUE;