krnl386.exe16: Make a couple of functions static.
[wine.git] / dlls / bcrypt / bcrypt_main.c
blob72b5df225ab2ce281c1b7b7d3b1e00f3de4050db
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 static void *libgnutls_handle;
54 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
55 MAKE_FUNCPTR(gnutls_cipher_decrypt2);
56 MAKE_FUNCPTR(gnutls_cipher_deinit);
57 MAKE_FUNCPTR(gnutls_cipher_encrypt2);
58 MAKE_FUNCPTR(gnutls_cipher_init);
59 MAKE_FUNCPTR(gnutls_global_deinit);
60 MAKE_FUNCPTR(gnutls_global_init);
61 MAKE_FUNCPTR(gnutls_global_set_log_function);
62 MAKE_FUNCPTR(gnutls_global_set_log_level);
63 MAKE_FUNCPTR(gnutls_perror);
64 #undef MAKE_FUNCPTR
66 static void gnutls_log( int level, const char *msg )
68 TRACE( "<%d> %s", level, msg );
71 static BOOL gnutls_initialize(void)
73 int ret;
75 if (!(libgnutls_handle = wine_dlopen( SONAME_LIBGNUTLS, RTLD_NOW, NULL, 0 )))
77 ERR_(winediag)( "failed to load libgnutls, no support for encryption\n" );
78 return FALSE;
81 #define LOAD_FUNCPTR(f) \
82 if (!(p##f = wine_dlsym( libgnutls_handle, #f, NULL, 0 ))) \
83 { \
84 ERR( "failed to load %s\n", #f ); \
85 goto fail; \
88 LOAD_FUNCPTR(gnutls_cipher_decrypt2)
89 LOAD_FUNCPTR(gnutls_cipher_deinit)
90 LOAD_FUNCPTR(gnutls_cipher_encrypt2)
91 LOAD_FUNCPTR(gnutls_cipher_init)
92 LOAD_FUNCPTR(gnutls_global_deinit)
93 LOAD_FUNCPTR(gnutls_global_init)
94 LOAD_FUNCPTR(gnutls_global_set_log_function)
95 LOAD_FUNCPTR(gnutls_global_set_log_level)
96 LOAD_FUNCPTR(gnutls_perror)
97 #undef LOAD_FUNCPTR
99 if ((ret = pgnutls_global_init()) != GNUTLS_E_SUCCESS)
101 pgnutls_perror( ret );
102 goto fail;
105 if (TRACE_ON( bcrypt ))
107 pgnutls_global_set_log_level( 4 );
108 pgnutls_global_set_log_function( gnutls_log );
111 return TRUE;
113 fail:
114 wine_dlclose( libgnutls_handle, NULL, 0 );
115 libgnutls_handle = NULL;
116 return FALSE;
119 static void gnutls_uninitialize(void)
121 pgnutls_global_deinit();
122 wine_dlclose( libgnutls_handle, NULL, 0 );
123 libgnutls_handle = NULL;
125 #endif /* HAVE_GNUTLS_CIPHER_INIT && !HAVE_COMMONCRYPTO_COMMONCRYPTOR_H */
127 NTSTATUS WINAPI BCryptAddContextFunction(ULONG table, LPCWSTR context, ULONG iface, LPCWSTR function, ULONG pos)
129 FIXME("%08x, %s, %08x, %s, %u: stub\n", table, debugstr_w(context), iface, debugstr_w(function), pos);
130 return STATUS_SUCCESS;
133 NTSTATUS WINAPI BCryptAddContextFunctionProvider(ULONG table, LPCWSTR context, ULONG iface, LPCWSTR function, LPCWSTR provider, ULONG pos)
135 FIXME("%08x, %s, %08x, %s, %s, %u: stub\n", table, debugstr_w(context), iface, debugstr_w(function), debugstr_w(provider), pos);
136 return STATUS_SUCCESS;
139 NTSTATUS WINAPI BCryptRemoveContextFunction(ULONG table, LPCWSTR context, ULONG iface, LPCWSTR function)
141 FIXME("%08x, %s, %08x, %s: stub\n", table, debugstr_w(context), iface, debugstr_w(function));
142 return STATUS_NOT_IMPLEMENTED;
145 NTSTATUS WINAPI BCryptRemoveContextFunctionProvider(ULONG table, LPCWSTR context, ULONG iface, LPCWSTR function, LPCWSTR provider)
147 FIXME("%08x, %s, %08x, %s, %s: stub\n", table, debugstr_w(context), iface, debugstr_w(function), debugstr_w(provider));
148 return STATUS_NOT_IMPLEMENTED;
151 NTSTATUS WINAPI BCryptRegisterProvider(LPCWSTR provider, ULONG flags, PCRYPT_PROVIDER_REG reg)
153 FIXME("%s, %08x, %p: stub\n", debugstr_w(provider), flags, reg);
154 return STATUS_SUCCESS;
157 NTSTATUS WINAPI BCryptUnregisterProvider(LPCWSTR provider)
159 FIXME("%s: stub\n", debugstr_w(provider));
160 return STATUS_NOT_IMPLEMENTED;
163 NTSTATUS WINAPI BCryptEnumAlgorithms(ULONG dwAlgOperations, ULONG *pAlgCount,
164 BCRYPT_ALGORITHM_IDENTIFIER **ppAlgList, ULONG dwFlags)
166 FIXME("%08x, %p, %p, %08x - stub\n", dwAlgOperations, pAlgCount, ppAlgList, dwFlags);
168 *ppAlgList=NULL;
169 *pAlgCount=0;
171 return STATUS_NOT_IMPLEMENTED;
174 #define MAGIC_ALG (('A' << 24) | ('L' << 16) | ('G' << 8) | '0')
175 #define MAGIC_HASH (('H' << 24) | ('A' << 16) | ('S' << 8) | 'H')
176 #define MAGIC_KEY (('K' << 24) | ('E' << 16) | ('Y' << 8) | '0')
177 struct object
179 ULONG magic;
182 enum alg_id
184 ALG_ID_AES,
185 ALG_ID_MD2,
186 ALG_ID_MD4,
187 ALG_ID_MD5,
188 ALG_ID_RNG,
189 ALG_ID_SHA1,
190 ALG_ID_SHA256,
191 ALG_ID_SHA384,
192 ALG_ID_SHA512
195 #define MAX_HASH_OUTPUT_BYTES 64
196 #define MAX_HASH_BLOCK_BITS 1024
198 static const struct {
199 ULONG object_length;
200 ULONG hash_length;
201 ULONG block_bits;
202 const WCHAR *alg_name;
203 } alg_props[] = {
204 /* ALG_ID_AES */ { 654, 0, 0, BCRYPT_AES_ALGORITHM },
205 /* ALG_ID_MD2 */ { 270, 16, 128, BCRYPT_MD2_ALGORITHM },
206 /* ALG_ID_MD4 */ { 270, 16, 512, BCRYPT_MD4_ALGORITHM },
207 /* ALG_ID_MD5 */ { 274, 16, 512, BCRYPT_MD5_ALGORITHM },
208 /* ALG_ID_RNG */ { 0, 0, 0, BCRYPT_RNG_ALGORITHM },
209 /* ALG_ID_SHA1 */ { 278, 20, 512, BCRYPT_SHA1_ALGORITHM },
210 /* ALG_ID_SHA256 */ { 286, 32, 512, BCRYPT_SHA256_ALGORITHM },
211 /* ALG_ID_SHA384 */ { 382, 48, 1024, BCRYPT_SHA384_ALGORITHM },
212 /* ALG_ID_SHA512 */ { 382, 64, 1024, BCRYPT_SHA512_ALGORITHM }
215 struct algorithm
217 struct object hdr;
218 enum alg_id id;
219 BOOL hmac;
222 NTSTATUS WINAPI BCryptGenRandom(BCRYPT_ALG_HANDLE handle, UCHAR *buffer, ULONG count, ULONG flags)
224 const DWORD supported_flags = BCRYPT_USE_SYSTEM_PREFERRED_RNG;
225 struct algorithm *algorithm = handle;
227 TRACE("%p, %p, %u, %08x - semi-stub\n", handle, buffer, count, flags);
229 if (!algorithm)
231 /* It's valid to call without an algorithm if BCRYPT_USE_SYSTEM_PREFERRED_RNG
232 * is set. In this case the preferred system RNG is used.
234 if (!(flags & BCRYPT_USE_SYSTEM_PREFERRED_RNG))
235 return STATUS_INVALID_HANDLE;
237 else if (algorithm->hdr.magic != MAGIC_ALG || algorithm->id != ALG_ID_RNG)
238 return STATUS_INVALID_HANDLE;
240 if (!buffer)
241 return STATUS_INVALID_PARAMETER;
243 if (flags & ~supported_flags)
244 FIXME("unsupported flags %08x\n", flags & ~supported_flags);
246 if (algorithm)
247 FIXME("ignoring selected algorithm\n");
249 /* When zero bytes are requested the function returns success too. */
250 if (!count)
251 return STATUS_SUCCESS;
253 if (algorithm || (flags & BCRYPT_USE_SYSTEM_PREFERRED_RNG))
255 if (RtlGenRandom(buffer, count))
256 return STATUS_SUCCESS;
259 FIXME("called with unsupported parameters, returning error\n");
260 return STATUS_NOT_IMPLEMENTED;
263 NTSTATUS WINAPI BCryptOpenAlgorithmProvider( BCRYPT_ALG_HANDLE *handle, LPCWSTR id, LPCWSTR implementation, DWORD flags )
265 const DWORD supported_flags = BCRYPT_ALG_HANDLE_HMAC_FLAG;
266 struct algorithm *alg;
267 enum alg_id alg_id;
269 TRACE( "%p, %s, %s, %08x\n", handle, wine_dbgstr_w(id), wine_dbgstr_w(implementation), flags );
271 if (!handle || !id) return STATUS_INVALID_PARAMETER;
272 if (flags & ~supported_flags)
274 FIXME( "unsupported flags %08x\n", flags & ~supported_flags);
275 return STATUS_NOT_IMPLEMENTED;
278 if (!strcmpW( id, BCRYPT_AES_ALGORITHM )) alg_id = ALG_ID_AES;
279 else if (!strcmpW( id, BCRYPT_MD2_ALGORITHM )) alg_id = ALG_ID_MD2;
280 else if (!strcmpW( id, BCRYPT_MD4_ALGORITHM )) alg_id = ALG_ID_MD4;
281 else if (!strcmpW( id, BCRYPT_MD5_ALGORITHM )) alg_id = ALG_ID_MD5;
282 else if (!strcmpW( id, BCRYPT_RNG_ALGORITHM )) alg_id = ALG_ID_RNG;
283 else if (!strcmpW( id, BCRYPT_SHA1_ALGORITHM )) alg_id = ALG_ID_SHA1;
284 else if (!strcmpW( id, BCRYPT_SHA256_ALGORITHM )) alg_id = ALG_ID_SHA256;
285 else if (!strcmpW( id, BCRYPT_SHA384_ALGORITHM )) alg_id = ALG_ID_SHA384;
286 else if (!strcmpW( id, BCRYPT_SHA512_ALGORITHM )) alg_id = ALG_ID_SHA512;
287 else
289 FIXME( "algorithm %s not supported\n", debugstr_w(id) );
290 return STATUS_NOT_IMPLEMENTED;
292 if (implementation && strcmpW( implementation, MS_PRIMITIVE_PROVIDER ))
294 FIXME( "implementation %s not supported\n", debugstr_w(implementation) );
295 return STATUS_NOT_IMPLEMENTED;
298 if (!(alg = heap_alloc( sizeof(*alg) ))) return STATUS_NO_MEMORY;
299 alg->hdr.magic = MAGIC_ALG;
300 alg->id = alg_id;
301 alg->hmac = flags & BCRYPT_ALG_HANDLE_HMAC_FLAG;
303 *handle = alg;
304 return STATUS_SUCCESS;
307 NTSTATUS WINAPI BCryptCloseAlgorithmProvider( BCRYPT_ALG_HANDLE handle, DWORD flags )
309 struct algorithm *alg = handle;
311 TRACE( "%p, %08x\n", handle, flags );
313 if (!alg || alg->hdr.magic != MAGIC_ALG) return STATUS_INVALID_HANDLE;
314 heap_free( alg );
315 return STATUS_SUCCESS;
318 NTSTATUS WINAPI BCryptGetFipsAlgorithmMode(BOOLEAN *enabled)
320 FIXME("%p - semi-stub\n", enabled);
322 if (!enabled)
323 return STATUS_INVALID_PARAMETER;
325 *enabled = FALSE;
326 return STATUS_SUCCESS;
329 struct hash_impl
331 union
333 MD2_CTX md2;
334 MD4_CTX md4;
335 MD5_CTX md5;
336 SHA_CTX sha1;
337 SHA256_CTX sha256;
338 SHA512_CTX sha512;
339 } u;
342 static NTSTATUS hash_init( struct hash_impl *hash, enum alg_id alg_id )
344 switch (alg_id)
346 case ALG_ID_MD2:
347 md2_init( &hash->u.md2 );
348 break;
350 case ALG_ID_MD4:
351 MD4Init( &hash->u.md4 );
352 break;
354 case ALG_ID_MD5:
355 MD5Init( &hash->u.md5 );
356 break;
358 case ALG_ID_SHA1:
359 A_SHAInit( &hash->u.sha1 );
360 break;
362 case ALG_ID_SHA256:
363 sha256_init( &hash->u.sha256 );
364 break;
366 case ALG_ID_SHA384:
367 sha384_init( &hash->u.sha512 );
368 break;
370 case ALG_ID_SHA512:
371 sha512_init( &hash->u.sha512 );
372 break;
374 default:
375 ERR( "unhandled id %u\n", alg_id );
376 return STATUS_NOT_IMPLEMENTED;
378 return STATUS_SUCCESS;
381 static NTSTATUS hash_update( struct hash_impl *hash, enum alg_id alg_id,
382 UCHAR *input, ULONG size )
384 switch (alg_id)
386 case ALG_ID_MD2:
387 md2_update( &hash->u.md2, input, size );
388 break;
390 case ALG_ID_MD4:
391 MD4Update( &hash->u.md4, input, size );
392 break;
394 case ALG_ID_MD5:
395 MD5Update( &hash->u.md5, input, size );
396 break;
398 case ALG_ID_SHA1:
399 A_SHAUpdate( &hash->u.sha1, input, size );
400 break;
402 case ALG_ID_SHA256:
403 sha256_update( &hash->u.sha256, input, size );
404 break;
406 case ALG_ID_SHA384:
407 sha384_update( &hash->u.sha512, input, size );
408 break;
410 case ALG_ID_SHA512:
411 sha512_update( &hash->u.sha512, input, size );
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_finish( struct hash_impl *hash, enum alg_id alg_id,
422 UCHAR *output, ULONG size )
424 switch (alg_id)
426 case ALG_ID_MD2:
427 md2_finalize( &hash->u.md2, output );
428 break;
430 case ALG_ID_MD4:
431 MD4Final( &hash->u.md4 );
432 memcpy( output, hash->u.md4.digest, 16 );
433 break;
435 case ALG_ID_MD5:
436 MD5Final( &hash->u.md5 );
437 memcpy( output, hash->u.md5.digest, 16 );
438 break;
440 case ALG_ID_SHA1:
441 A_SHAFinal( &hash->u.sha1, (ULONG *)output );
442 break;
444 case ALG_ID_SHA256:
445 sha256_finalize( &hash->u.sha256, output );
446 break;
448 case ALG_ID_SHA384:
449 sha384_finalize( &hash->u.sha512, output );
450 break;
452 case ALG_ID_SHA512:
453 sha512_finalize( &hash->u.sha512, output );
454 break;
456 default:
457 ERR( "unhandled id %u\n", alg_id );
458 return STATUS_NOT_IMPLEMENTED;
460 return STATUS_SUCCESS;
463 struct hash
465 struct object hdr;
466 enum alg_id alg_id;
467 BOOL hmac;
468 struct hash_impl outer;
469 struct hash_impl inner;
472 #define BLOCK_LENGTH_AES 16
474 static NTSTATUS generic_alg_property( enum alg_id id, const WCHAR *prop, UCHAR *buf, ULONG size, ULONG *ret_size )
476 if (!strcmpW( prop, BCRYPT_OBJECT_LENGTH ))
478 if (!alg_props[id].object_length)
479 return STATUS_NOT_SUPPORTED;
480 *ret_size = sizeof(ULONG);
481 if (size < sizeof(ULONG))
482 return STATUS_BUFFER_TOO_SMALL;
483 if (buf)
484 *(ULONG *)buf = alg_props[id].object_length;
485 return STATUS_SUCCESS;
488 if (!strcmpW( prop, BCRYPT_HASH_LENGTH ))
490 if (!alg_props[id].hash_length)
491 return STATUS_NOT_SUPPORTED;
492 *ret_size = sizeof(ULONG);
493 if (size < sizeof(ULONG))
494 return STATUS_BUFFER_TOO_SMALL;
495 if(buf)
496 *(ULONG*)buf = alg_props[id].hash_length;
497 return STATUS_SUCCESS;
500 if (!strcmpW( prop, BCRYPT_ALGORITHM_NAME ))
502 *ret_size = (strlenW(alg_props[id].alg_name)+1)*sizeof(WCHAR);
503 if (size < *ret_size)
504 return STATUS_BUFFER_TOO_SMALL;
505 if(buf)
506 memcpy(buf, alg_props[id].alg_name, *ret_size);
507 return STATUS_SUCCESS;
510 return STATUS_NOT_IMPLEMENTED;
513 static NTSTATUS get_alg_property( enum alg_id id, const WCHAR *prop, UCHAR *buf, ULONG size, ULONG *ret_size )
515 NTSTATUS status;
517 status = generic_alg_property( id, prop, buf, size, ret_size );
518 if (status != STATUS_NOT_IMPLEMENTED)
519 return status;
521 switch (id)
523 case ALG_ID_AES:
524 if (!strcmpW( prop, BCRYPT_BLOCK_LENGTH ))
526 *ret_size = sizeof(ULONG);
527 if (size < sizeof(ULONG))
528 return STATUS_BUFFER_TOO_SMALL;
529 if (buf)
530 *(ULONG *)buf = BLOCK_LENGTH_AES;
531 return STATUS_SUCCESS;
533 if (!strcmpW( prop, BCRYPT_CHAINING_MODE ))
535 if (size >= sizeof(BCRYPT_CHAIN_MODE_CBC))
537 memcpy(buf, BCRYPT_CHAIN_MODE_CBC, sizeof(BCRYPT_CHAIN_MODE_CBC));
538 *ret_size = sizeof(BCRYPT_CHAIN_MODE_CBC) * sizeof(WCHAR);
539 return STATUS_SUCCESS;
541 else
543 *ret_size = sizeof(BCRYPT_CHAIN_MODE_CBC) * sizeof(WCHAR);
544 return STATUS_BUFFER_TOO_SMALL;
547 if (!strcmpW( prop, BCRYPT_KEY_LENGTHS ))
549 BCRYPT_KEY_LENGTHS_STRUCT *key_lengths = (void *)buf;
550 *ret_size = sizeof(*key_lengths);
551 if (key_lengths && size < *ret_size) return STATUS_BUFFER_TOO_SMALL;
552 if (key_lengths)
554 key_lengths->dwMinLength = 128;
555 key_lengths->dwMaxLength = 256;
556 key_lengths->dwIncrement = 64;
558 return STATUS_SUCCESS;
560 break;
562 default:
563 break;
566 FIXME( "unsupported property %s\n", debugstr_w(prop) );
567 return STATUS_NOT_IMPLEMENTED;
570 static NTSTATUS get_hash_property( enum alg_id id, const WCHAR *prop, UCHAR *buf, ULONG size, ULONG *ret_size )
572 NTSTATUS status;
574 status = generic_alg_property( id, prop, buf, size, ret_size );
575 if (status == STATUS_NOT_IMPLEMENTED)
576 FIXME( "unsupported property %s\n", debugstr_w(prop) );
577 return status;
580 NTSTATUS WINAPI BCryptGetProperty( BCRYPT_HANDLE handle, LPCWSTR prop, UCHAR *buffer, ULONG count, ULONG *res, ULONG flags )
582 struct object *object = handle;
584 TRACE( "%p, %s, %p, %u, %p, %08x\n", handle, wine_dbgstr_w(prop), buffer, count, res, flags );
586 if (!object) return STATUS_INVALID_HANDLE;
587 if (!prop || !res) return STATUS_INVALID_PARAMETER;
589 switch (object->magic)
591 case MAGIC_ALG:
593 const struct algorithm *alg = (const struct algorithm *)object;
594 return get_alg_property( alg->id, prop, buffer, count, res );
596 case MAGIC_HASH:
598 const struct hash *hash = (const struct hash *)object;
599 return get_hash_property( hash->alg_id, prop, buffer, count, res );
601 default:
602 WARN( "unknown magic %08x\n", object->magic );
603 return STATUS_INVALID_HANDLE;
607 NTSTATUS WINAPI BCryptSetProperty( BCRYPT_HANDLE handle, const WCHAR *prop, UCHAR *value, ULONG size, ULONG flags )
609 FIXME( "%p, %s, %p, %u, %08x\n", handle, debugstr_w(prop), value, size, flags );
610 return STATUS_NOT_IMPLEMENTED;
613 NTSTATUS WINAPI BCryptCreateHash( BCRYPT_ALG_HANDLE algorithm, BCRYPT_HASH_HANDLE *handle, UCHAR *object, ULONG objectlen,
614 UCHAR *secret, ULONG secretlen, ULONG flags )
616 struct algorithm *alg = algorithm;
617 UCHAR buffer[MAX_HASH_BLOCK_BITS / 8] = {0};
618 struct hash *hash;
619 int block_bytes;
620 NTSTATUS status;
621 int i;
623 TRACE( "%p, %p, %p, %u, %p, %u, %08x - stub\n", algorithm, handle, object, objectlen,
624 secret, secretlen, flags );
625 if (flags)
627 FIXME( "unimplemented flags %08x\n", flags );
628 return STATUS_NOT_IMPLEMENTED;
631 if (!alg || alg->hdr.magic != MAGIC_ALG) return STATUS_INVALID_HANDLE;
632 if (object) FIXME( "ignoring object buffer\n" );
634 if (!(hash = heap_alloc( sizeof(*hash) ))) return STATUS_NO_MEMORY;
635 hash->hdr.magic = MAGIC_HASH;
636 hash->alg_id = alg->id;
637 hash->hmac = alg->hmac;
639 /* initialize hash */
640 if ((status = hash_init( &hash->inner, hash->alg_id ))) goto end;
641 if (!hash->hmac) goto end;
643 /* initialize hmac */
644 if ((status = hash_init( &hash->outer, hash->alg_id ))) goto end;
645 block_bytes = alg_props[hash->alg_id].block_bits / 8;
646 if (secretlen > block_bytes)
648 struct hash_impl temp;
649 if ((status = hash_init( &temp, hash->alg_id ))) goto end;
650 if ((status = hash_update( &temp, hash->alg_id, secret, secretlen ))) goto end;
651 if ((status = hash_finish( &temp, hash->alg_id, buffer,
652 alg_props[hash->alg_id].hash_length ))) goto end;
654 else
656 memcpy( buffer, secret, secretlen );
658 for (i = 0; i < block_bytes; i++) buffer[i] ^= 0x5c;
659 if ((status = hash_update( &hash->outer, hash->alg_id, buffer, block_bytes ))) goto end;
660 for (i = 0; i < block_bytes; i++) buffer[i] ^= (0x5c ^ 0x36);
661 status = hash_update( &hash->inner, hash->alg_id, buffer, block_bytes );
663 end:
664 if (status != STATUS_SUCCESS)
666 heap_free( hash );
667 return status;
670 *handle = hash;
671 return STATUS_SUCCESS;
674 NTSTATUS WINAPI BCryptDuplicateHash( BCRYPT_HASH_HANDLE handle, BCRYPT_HASH_HANDLE *handle_copy,
675 UCHAR *object, ULONG objectlen, ULONG flags )
677 struct hash *hash_orig = handle;
678 struct hash *hash_copy;
680 TRACE( "%p, %p, %p, %u, %u\n", handle, handle_copy, object, objectlen, flags );
682 if (!hash_orig || hash_orig->hdr.magic != MAGIC_HASH) return STATUS_INVALID_HANDLE;
683 if (!handle_copy) return STATUS_INVALID_PARAMETER;
684 if (object) FIXME( "ignoring object buffer\n" );
686 if (!(hash_copy = heap_alloc( sizeof(*hash_copy) )))
687 return STATUS_NO_MEMORY;
689 memcpy( hash_copy, hash_orig, sizeof(*hash_orig) );
691 *handle_copy = hash_copy;
692 return STATUS_SUCCESS;
695 NTSTATUS WINAPI BCryptDestroyHash( BCRYPT_HASH_HANDLE handle )
697 struct hash *hash = handle;
699 TRACE( "%p\n", handle );
701 if (!hash || hash->hdr.magic != MAGIC_HASH) return STATUS_INVALID_HANDLE;
702 heap_free( hash );
703 return STATUS_SUCCESS;
706 NTSTATUS WINAPI BCryptHashData( BCRYPT_HASH_HANDLE handle, UCHAR *input, ULONG size, ULONG flags )
708 struct hash *hash = handle;
710 TRACE( "%p, %p, %u, %08x\n", handle, input, size, flags );
712 if (!hash || hash->hdr.magic != MAGIC_HASH) return STATUS_INVALID_HANDLE;
713 if (!input) return STATUS_SUCCESS;
715 return hash_update( &hash->inner, hash->alg_id, input, size );
718 NTSTATUS WINAPI BCryptFinishHash( BCRYPT_HASH_HANDLE handle, UCHAR *output, ULONG size, ULONG flags )
720 UCHAR buffer[MAX_HASH_OUTPUT_BYTES];
721 struct hash *hash = handle;
722 NTSTATUS status;
723 int hash_length;
725 TRACE( "%p, %p, %u, %08x\n", handle, output, size, flags );
727 if (!hash || hash->hdr.magic != MAGIC_HASH) return STATUS_INVALID_HANDLE;
728 if (!output) return STATUS_INVALID_PARAMETER;
730 if (!hash->hmac)
731 return hash_finish( &hash->inner, hash->alg_id, output, size );
733 hash_length = alg_props[hash->alg_id].hash_length;
734 if ((status = hash_finish( &hash->inner, hash->alg_id, buffer, hash_length ))) return status;
735 if ((status = hash_update( &hash->outer, hash->alg_id, buffer, hash_length ))) return status;
736 return hash_finish( &hash->outer, hash->alg_id, output, size );
739 NTSTATUS WINAPI BCryptHash( BCRYPT_ALG_HANDLE algorithm, UCHAR *secret, ULONG secretlen,
740 UCHAR *input, ULONG inputlen, UCHAR *output, ULONG outputlen )
742 NTSTATUS status;
743 BCRYPT_HASH_HANDLE handle;
745 TRACE( "%p, %p, %u, %p, %u, %p, %u\n", algorithm, secret, secretlen,
746 input, inputlen, output, outputlen );
748 status = BCryptCreateHash( algorithm, &handle, NULL, 0, secret, secretlen, 0);
749 if (status != STATUS_SUCCESS)
751 return status;
754 status = BCryptHashData( handle, input, inputlen, 0 );
755 if (status != STATUS_SUCCESS)
757 BCryptDestroyHash( handle );
758 return status;
761 status = BCryptFinishHash( handle, output, outputlen, 0 );
762 if (status != STATUS_SUCCESS)
764 BCryptDestroyHash( handle );
765 return status;
768 return BCryptDestroyHash( handle );
771 #if defined(HAVE_GNUTLS_CIPHER_INIT) || defined(HAVE_COMMONCRYPTO_COMMONCRYPTOR_H) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
772 static ULONG get_block_size( enum alg_id alg )
774 ULONG ret = 0, size = sizeof(ret);
775 get_alg_property( alg, BCRYPT_BLOCK_LENGTH, (UCHAR *)&ret, sizeof(ret), &size );
776 return ret;
778 #endif
780 #if defined(HAVE_GNUTLS_CIPHER_INIT) && !defined(HAVE_COMMONCRYPTO_COMMONCRYPTOR_H)
781 struct key
783 struct object hdr;
784 enum alg_id alg_id;
785 ULONG block_size;
786 gnutls_cipher_hd_t handle;
787 UCHAR *secret;
788 ULONG secret_len;
791 static NTSTATUS key_init( struct key *key, enum alg_id id, const UCHAR *secret, ULONG secret_len )
793 UCHAR *buffer;
795 if (!libgnutls_handle) return STATUS_INTERNAL_ERROR;
797 switch (id)
799 case ALG_ID_AES:
800 break;
802 default:
803 FIXME( "algorithm %u not supported\n", id );
804 return STATUS_NOT_SUPPORTED;
807 if (!(key->block_size = get_block_size( id ))) return STATUS_INVALID_PARAMETER;
808 if (!(buffer = heap_alloc( secret_len ))) return STATUS_NO_MEMORY;
809 memcpy( buffer, secret, secret_len );
811 key->alg_id = id;
812 key->handle = 0; /* initialized on first use */
813 key->secret = buffer;
814 key->secret_len = secret_len;
816 return STATUS_SUCCESS;
819 static gnutls_cipher_algorithm_t get_gnutls_cipher( const struct key *key )
821 switch (key->alg_id)
823 case ALG_ID_AES:
824 FIXME( "handle block size and chaining mode\n" );
825 return GNUTLS_CIPHER_AES_128_CBC;
827 default:
828 FIXME( "algorithm %u not supported\n", key->alg_id );
829 return GNUTLS_CIPHER_UNKNOWN;
833 static NTSTATUS key_set_params( struct key *key, UCHAR *iv, ULONG iv_len )
835 gnutls_cipher_algorithm_t cipher;
836 gnutls_datum_t secret, vector;
837 int ret;
839 if (key->handle)
841 pgnutls_cipher_deinit( key->handle );
842 key->handle = NULL;
845 if ((cipher = get_gnutls_cipher( key )) == GNUTLS_CIPHER_UNKNOWN)
846 return STATUS_NOT_SUPPORTED;
848 secret.data = key->secret;
849 secret.size = key->secret_len;
850 if (iv)
852 vector.data = iv;
853 vector.size = iv_len;
856 if ((ret = pgnutls_cipher_init( &key->handle, cipher, &secret, iv ? &vector : NULL )))
858 pgnutls_perror( ret );
859 return STATUS_INTERNAL_ERROR;
862 return STATUS_SUCCESS;
865 static NTSTATUS key_encrypt( struct key *key, const UCHAR *input, ULONG input_len, UCHAR *output,
866 ULONG output_len )
868 int ret;
870 if ((ret = pgnutls_cipher_encrypt2( key->handle, input, input_len, output, output_len )))
872 pgnutls_perror( ret );
873 return STATUS_INTERNAL_ERROR;
876 return STATUS_SUCCESS;
879 static NTSTATUS key_decrypt( struct key *key, const UCHAR *input, ULONG input_len, UCHAR *output,
880 ULONG output_len )
882 int ret;
884 if ((ret = pgnutls_cipher_decrypt2( key->handle, input, input_len, output, output_len )))
886 pgnutls_perror( ret );
887 return STATUS_INTERNAL_ERROR;
890 return STATUS_SUCCESS;
893 static NTSTATUS key_destroy( struct key *key )
895 if (key->handle) pgnutls_cipher_deinit( key->handle );
896 heap_free( key->secret );
897 heap_free( key );
898 return STATUS_SUCCESS;
900 #elif defined(HAVE_COMMONCRYPTO_COMMONCRYPTOR_H) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
901 struct key
903 struct object hdr;
904 enum alg_id alg_id;
905 ULONG block_size;
906 CCCryptorRef ref_encrypt;
907 CCCryptorRef ref_decrypt;
908 UCHAR *secret;
909 ULONG secret_len;
912 static NTSTATUS key_init( struct key *key, enum alg_id id, const UCHAR *secret, ULONG secret_len )
914 UCHAR *buffer;
916 switch (id)
918 case ALG_ID_AES:
919 break;
921 default:
922 FIXME( "algorithm %u not supported\n", id );
923 return STATUS_NOT_SUPPORTED;
926 if (!(key->block_size = get_block_size( id ))) return STATUS_INVALID_PARAMETER;
927 if (!(buffer = heap_alloc( secret_len ))) return STATUS_NO_MEMORY;
928 memcpy( buffer, secret, secret_len );
930 key->alg_id = id;
931 key->ref_encrypt = NULL; /* initialized on first use */
932 key->ref_decrypt = NULL;
933 key->secret = buffer;
934 key->secret_len = secret_len;
936 return STATUS_SUCCESS;
939 static NTSTATUS key_set_params( struct key *key, UCHAR *iv, ULONG iv_len )
941 CCCryptorStatus status;
943 if (key->ref_encrypt)
945 CCCryptorRelease( key->ref_encrypt );
946 key->ref_encrypt = NULL;
948 if (key->ref_decrypt)
950 CCCryptorRelease( key->ref_decrypt );
951 key->ref_decrypt = NULL;
954 if ((status = CCCryptorCreateWithMode( kCCEncrypt, kCCModeCBC, kCCAlgorithmAES128, ccNoPadding, iv,
955 key->secret, key->secret_len, NULL, 0, 0, 0, &key->ref_encrypt )) != kCCSuccess)
957 WARN( "CCCryptorCreateWithMode failed %d\n", status );
958 return STATUS_INTERNAL_ERROR;
960 if ((status = CCCryptorCreateWithMode( kCCDecrypt, kCCModeCBC, kCCAlgorithmAES128, ccNoPadding, iv,
961 key->secret, key->secret_len, NULL, 0, 0, 0, &key->ref_decrypt )) != kCCSuccess)
963 WARN( "CCCryptorCreateWithMode failed %d\n", status );
964 CCCryptorRelease( key->ref_encrypt );
965 key->ref_encrypt = NULL;
966 return STATUS_INTERNAL_ERROR;
969 return STATUS_SUCCESS;
972 static NTSTATUS key_encrypt( struct key *key, const UCHAR *input, ULONG input_len, UCHAR *output,
973 ULONG output_len )
975 CCCryptorStatus status;
977 if ((status = CCCryptorUpdate( key->ref_encrypt, input, input_len, output, output_len, NULL )) != kCCSuccess)
979 WARN( "CCCryptorUpdate failed %d\n", status );
980 return STATUS_INTERNAL_ERROR;
983 return STATUS_SUCCESS;
986 static NTSTATUS key_decrypt( struct key *key, const UCHAR *input, ULONG input_len, UCHAR *output,
987 ULONG output_len )
989 CCCryptorStatus status;
991 if ((status = CCCryptorUpdate( key->ref_decrypt, input, input_len, output, output_len, NULL )) != kCCSuccess)
993 WARN( "CCCryptorUpdate failed %d\n", status );
994 return STATUS_INTERNAL_ERROR;
997 return STATUS_SUCCESS;
1000 static NTSTATUS key_destroy( struct key *key )
1002 if (key->ref_encrypt) CCCryptorRelease( key->ref_encrypt );
1003 if (key->ref_decrypt) CCCryptorRelease( key->ref_decrypt );
1004 heap_free( key->secret );
1005 heap_free( key );
1006 return STATUS_SUCCESS;
1008 #else
1009 struct key
1011 struct object hdr;
1012 ULONG block_size;
1015 static NTSTATUS key_init( struct key *key, enum alg_id id, const UCHAR *secret, ULONG secret_len )
1017 ERR( "support for keys not available at build time\n" );
1018 return STATUS_NOT_IMPLEMENTED;
1021 static NTSTATUS key_set_params( struct key *key, UCHAR *iv, ULONG iv_len )
1023 ERR( "support for keys not available at build time\n" );
1024 return STATUS_NOT_IMPLEMENTED;
1027 static NTSTATUS key_encrypt( struct key *key, const UCHAR *input, ULONG input_len, UCHAR *output,
1028 ULONG output_len )
1030 ERR( "support for keys not available at build time\n" );
1031 return STATUS_NOT_IMPLEMENTED;
1034 static NTSTATUS key_decrypt( struct key *key, const UCHAR *input, ULONG input_len, UCHAR *output,
1035 ULONG output_len )
1037 ERR( "support for keys not available at build time\n" );
1038 return STATUS_NOT_IMPLEMENTED;
1041 static NTSTATUS key_destroy( struct key *key )
1043 ERR( "support for keys not available at build time\n" );
1044 return STATUS_NOT_IMPLEMENTED;
1046 #endif
1048 NTSTATUS WINAPI BCryptGenerateSymmetricKey( BCRYPT_ALG_HANDLE algorithm, BCRYPT_KEY_HANDLE *handle,
1049 UCHAR *object, ULONG object_len, UCHAR *secret, ULONG secret_len,
1050 ULONG flags )
1052 struct algorithm *alg = algorithm;
1053 struct key *key;
1054 NTSTATUS status;
1056 TRACE( "%p, %p, %p, %u, %p, %u, %08x\n", algorithm, handle, object, object_len, secret, secret_len, flags );
1058 if (!alg || alg->hdr.magic != MAGIC_ALG) return STATUS_INVALID_HANDLE;
1059 if (object) FIXME( "ignoring object buffer\n" );
1061 if (!(key = heap_alloc( sizeof(*key) ))) return STATUS_NO_MEMORY;
1062 key->hdr.magic = MAGIC_KEY;
1064 if ((status = key_init( key, alg->id, secret, secret_len )))
1066 heap_free( key );
1067 return status;
1070 *handle = key;
1071 return STATUS_SUCCESS;
1074 NTSTATUS WINAPI BCryptDestroyKey( BCRYPT_KEY_HANDLE handle )
1076 struct key *key = handle;
1078 TRACE( "%p\n", handle );
1080 if (!key || key->hdr.magic != MAGIC_KEY) return STATUS_INVALID_HANDLE;
1081 return key_destroy( key );
1084 NTSTATUS WINAPI BCryptEncrypt( BCRYPT_KEY_HANDLE handle, UCHAR *input, ULONG input_len,
1085 void *padding, UCHAR *iv, ULONG iv_len, UCHAR *output,
1086 ULONG output_len, ULONG *ret_len, ULONG flags )
1088 struct key *key = handle;
1089 ULONG bytes_left = input_len;
1090 UCHAR *buf, *src, *dst;
1091 NTSTATUS status;
1093 TRACE( "%p, %p, %u, %p, %p, %u, %p, %u, %p, %08x\n", handle, input, input_len,
1094 padding, iv, iv_len, output, output_len, ret_len, flags );
1096 if (!key || key->hdr.magic != MAGIC_KEY) return STATUS_INVALID_HANDLE;
1097 if (padding)
1099 FIXME( "padding info not implemented\n" );
1100 return STATUS_NOT_IMPLEMENTED;
1102 if (flags & ~BCRYPT_BLOCK_PADDING)
1104 FIXME( "flags %08x not implemented\n", flags );
1105 return STATUS_NOT_IMPLEMENTED;
1108 if ((status = key_set_params( key, iv, iv_len ))) return status;
1110 *ret_len = input_len;
1112 if (flags & BCRYPT_BLOCK_PADDING)
1113 *ret_len = (input_len + key->block_size) & ~(key->block_size - 1);
1114 else if (input_len & (key->block_size - 1))
1115 return STATUS_INVALID_BUFFER_SIZE;
1117 if (!output) return STATUS_SUCCESS;
1118 if (output_len < *ret_len) return STATUS_BUFFER_TOO_SMALL;
1120 src = input;
1121 dst = output;
1122 while (bytes_left >= key->block_size)
1124 if ((status = key_encrypt( key, src, key->block_size, dst, key->block_size ))) return status;
1125 bytes_left -= key->block_size;
1126 src += key->block_size;
1127 dst += key->block_size;
1130 if (flags & BCRYPT_BLOCK_PADDING)
1132 if (!(buf = heap_alloc( key->block_size ))) return STATUS_NO_MEMORY;
1133 memcpy( buf, src, bytes_left );
1134 memset( buf + bytes_left, key->block_size - bytes_left, key->block_size - bytes_left );
1135 status = key_encrypt( key, buf, key->block_size, dst, key->block_size );
1136 heap_free( buf );
1139 return status;
1142 NTSTATUS WINAPI BCryptDecrypt( BCRYPT_KEY_HANDLE handle, UCHAR *input, ULONG input_len,
1143 void *padding, UCHAR *iv, ULONG iv_len, UCHAR *output,
1144 ULONG output_len, ULONG *ret_len, ULONG flags )
1146 struct key *key = handle;
1147 ULONG bytes_left = input_len;
1148 UCHAR *buf, *src, *dst;
1149 NTSTATUS status;
1151 TRACE( "%p, %p, %u, %p, %p, %u, %p, %u, %p, %08x\n", handle, input, input_len,
1152 padding, iv, iv_len, output, output_len, ret_len, flags );
1154 if (!key || key->hdr.magic != MAGIC_KEY) return STATUS_INVALID_HANDLE;
1155 if (padding)
1157 FIXME( "padding info not implemented\n" );
1158 return STATUS_NOT_IMPLEMENTED;
1160 if (flags & ~BCRYPT_BLOCK_PADDING)
1162 FIXME( "flags %08x not supported\n", flags );
1163 return STATUS_NOT_IMPLEMENTED;
1166 if ((status = key_set_params( key, iv, iv_len ))) return status;
1168 *ret_len = input_len;
1170 if (input_len & (key->block_size - 1)) return STATUS_INVALID_BUFFER_SIZE;
1171 if (!output) return STATUS_SUCCESS;
1172 if (flags & BCRYPT_BLOCK_PADDING)
1174 if (output_len + key->block_size < *ret_len) return STATUS_BUFFER_TOO_SMALL;
1175 if (input_len < key->block_size) return STATUS_BUFFER_TOO_SMALL;
1176 bytes_left -= key->block_size;
1178 else if (output_len < *ret_len)
1179 return STATUS_BUFFER_TOO_SMALL;
1181 src = input;
1182 dst = output;
1183 while (bytes_left >= key->block_size)
1185 if ((status = key_decrypt( key, src, key->block_size, dst, key->block_size ))) return status;
1186 bytes_left -= key->block_size;
1187 src += key->block_size;
1188 dst += key->block_size;
1191 if (flags & BCRYPT_BLOCK_PADDING)
1193 if (!(buf = heap_alloc( key->block_size ))) return STATUS_NO_MEMORY;
1194 status = key_decrypt( key, src, key->block_size, buf, key->block_size );
1195 if (!status && buf[ key->block_size - 1 ] <= key->block_size)
1197 *ret_len -= buf[ key->block_size - 1 ];
1198 if (output_len < *ret_len) status = STATUS_BUFFER_TOO_SMALL;
1199 else memcpy( dst, buf, key->block_size - buf[ key->block_size - 1 ] );
1201 else
1202 status = STATUS_UNSUCCESSFUL; /* FIXME: invalid padding */
1203 heap_free( buf );
1206 return status;
1209 BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
1211 switch (reason)
1213 case DLL_PROCESS_ATTACH:
1214 instance = hinst;
1215 DisableThreadLibraryCalls( hinst );
1216 #if defined(HAVE_GNUTLS_CIPHER_INIT) && !defined(HAVE_COMMONCRYPTO_COMMONCRYPTOR_H)
1217 gnutls_initialize();
1218 #endif
1219 break;
1221 case DLL_PROCESS_DETACH:
1222 if (reserved) break;
1223 #if defined(HAVE_GNUTLS_CIPHER_INIT) && !defined(HAVE_COMMONCRYPTO_COMMONCRYPTOR_H)
1224 gnutls_uninitialize();
1225 #endif
1226 break;
1228 return TRUE;