bcrypt: Add some crypto-provider related stubs.
[wine.git] / dlls / bcrypt / bcrypt_main.c
blob3bdc463904e8c42174fa1bc4182e453d762098dd
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 <CommonCrypto/CommonCryptor.h>
26 #elif defined(SONAME_LIBGNUTLS)
27 #include <gnutls/gnutls.h>
28 #include <gnutls/crypto.h>
29 #endif
31 #include "ntstatus.h"
32 #define WIN32_NO_STATUS
33 #include "windef.h"
34 #include "winbase.h"
35 #include "ntsecapi.h"
36 #include "bcrypt.h"
38 #include "bcrypt_internal.h"
40 #include "wine/debug.h"
41 #include "wine/library.h"
42 #include "wine/unicode.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(bcrypt);
46 static HINSTANCE instance;
48 #if defined(HAVE_GNUTLS_CIPHER_INIT) && !defined(HAVE_COMMONCRYPTO_COMMONCRYPTOR_H)
49 WINE_DECLARE_DEBUG_CHANNEL(winediag);
51 static void *libgnutls_handle;
52 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
53 MAKE_FUNCPTR(gnutls_cipher_decrypt2);
54 MAKE_FUNCPTR(gnutls_cipher_deinit);
55 MAKE_FUNCPTR(gnutls_cipher_encrypt2);
56 MAKE_FUNCPTR(gnutls_cipher_init);
57 MAKE_FUNCPTR(gnutls_global_deinit);
58 MAKE_FUNCPTR(gnutls_global_init);
59 MAKE_FUNCPTR(gnutls_global_set_log_function);
60 MAKE_FUNCPTR(gnutls_global_set_log_level);
61 MAKE_FUNCPTR(gnutls_perror);
62 #undef MAKE_FUNCPTR
64 static void gnutls_log( int level, const char *msg )
66 TRACE( "<%d> %s", level, msg );
69 static BOOL gnutls_initialize(void)
71 int ret;
73 if (!(libgnutls_handle = wine_dlopen( SONAME_LIBGNUTLS, RTLD_NOW, NULL, 0 )))
75 ERR_(winediag)( "failed to load libgnutls, no support for encryption\n" );
76 return FALSE;
79 #define LOAD_FUNCPTR(f) \
80 if (!(p##f = wine_dlsym( libgnutls_handle, #f, NULL, 0 ))) \
81 { \
82 ERR( "failed to load %s\n", #f ); \
83 goto fail; \
86 LOAD_FUNCPTR(gnutls_cipher_decrypt2)
87 LOAD_FUNCPTR(gnutls_cipher_deinit)
88 LOAD_FUNCPTR(gnutls_cipher_encrypt2)
89 LOAD_FUNCPTR(gnutls_cipher_init)
90 LOAD_FUNCPTR(gnutls_global_deinit)
91 LOAD_FUNCPTR(gnutls_global_init)
92 LOAD_FUNCPTR(gnutls_global_set_log_function)
93 LOAD_FUNCPTR(gnutls_global_set_log_level)
94 LOAD_FUNCPTR(gnutls_perror)
95 #undef LOAD_FUNCPTR
97 if ((ret = pgnutls_global_init()) != GNUTLS_E_SUCCESS)
99 pgnutls_perror( ret );
100 goto fail;
103 if (TRACE_ON( bcrypt ))
105 pgnutls_global_set_log_level( 4 );
106 pgnutls_global_set_log_function( gnutls_log );
109 return TRUE;
111 fail:
112 wine_dlclose( libgnutls_handle, NULL, 0 );
113 libgnutls_handle = NULL;
114 return FALSE;
117 static void gnutls_uninitialize(void)
119 pgnutls_global_deinit();
120 wine_dlclose( libgnutls_handle, NULL, 0 );
121 libgnutls_handle = NULL;
123 #endif /* HAVE_GNUTLS_CIPHER_INIT && !HAVE_COMMONCRYPTO_COMMONCRYPTOR_H */
125 NTSTATUS WINAPI BCryptAddContextFunction(ULONG table, LPCWSTR context, ULONG iface, LPCWSTR function, ULONG pos)
127 FIXME("%08x, %s, %08x, %s, %u: stub\n", table, debugstr_w(context), iface, debugstr_w(function), pos);
128 return STATUS_SUCCESS;
131 NTSTATUS WINAPI BCryptAddContextFunctionProvider(ULONG table, LPCWSTR context, ULONG iface, LPCWSTR function, LPCWSTR provider, ULONG pos)
133 FIXME("%08x, %s, %08x, %s, %s, %u: stub\n", table, debugstr_w(context), iface, debugstr_w(function), debugstr_w(provider), pos);
134 return STATUS_SUCCESS;
137 NTSTATUS WINAPI BCryptRemoveContextFunction(ULONG table, LPCWSTR context, ULONG iface, LPCWSTR function)
139 FIXME("%08x, %s, %08x, %s: stub\n", table, debugstr_w(context), iface, debugstr_w(function));
140 return STATUS_NOT_IMPLEMENTED;
143 NTSTATUS WINAPI BCryptRemoveContextFunctionProvider(ULONG table, LPCWSTR context, ULONG iface, LPCWSTR function, LPCWSTR provider)
145 FIXME("%08x, %s, %08x, %s, %s: stub\n", table, debugstr_w(context), iface, debugstr_w(function), debugstr_w(provider));
146 return STATUS_NOT_IMPLEMENTED;
149 NTSTATUS WINAPI BCryptRegisterProvider(LPCWSTR provider, ULONG flags, PCRYPT_PROVIDER_REG reg)
151 FIXME("%s, %08x, %p: stub\n", debugstr_w(provider), flags, reg);
152 return STATUS_SUCCESS;
155 NTSTATUS WINAPI BCryptUnregisterProvider(LPCWSTR provider)
157 FIXME("%s: stub\n", debugstr_w(provider));
158 return STATUS_NOT_IMPLEMENTED;
161 NTSTATUS WINAPI BCryptEnumAlgorithms(ULONG dwAlgOperations, ULONG *pAlgCount,
162 BCRYPT_ALGORITHM_IDENTIFIER **ppAlgList, ULONG dwFlags)
164 FIXME("%08x, %p, %p, %08x - stub\n", dwAlgOperations, pAlgCount, ppAlgList, dwFlags);
166 *ppAlgList=NULL;
167 *pAlgCount=0;
169 return STATUS_NOT_IMPLEMENTED;
172 #define MAGIC_ALG (('A' << 24) | ('L' << 16) | ('G' << 8) | '0')
173 #define MAGIC_HASH (('H' << 24) | ('A' << 16) | ('S' << 8) | 'H')
174 #define MAGIC_KEY (('K' << 24) | ('E' << 16) | ('Y' << 8) | '0')
175 struct object
177 ULONG magic;
180 enum alg_id
182 ALG_ID_AES,
183 ALG_ID_MD2,
184 ALG_ID_MD4,
185 ALG_ID_MD5,
186 ALG_ID_RNG,
187 ALG_ID_SHA1,
188 ALG_ID_SHA256,
189 ALG_ID_SHA384,
190 ALG_ID_SHA512
193 #define MAX_HASH_OUTPUT_BYTES 64
194 #define MAX_HASH_BLOCK_BITS 1024
196 static const struct {
197 ULONG object_length;
198 ULONG hash_length;
199 ULONG block_bits;
200 const WCHAR *alg_name;
201 } alg_props[] = {
202 /* ALG_ID_AES */ { 654, 0, 0, BCRYPT_AES_ALGORITHM },
203 /* ALG_ID_MD2 */ { 270, 16, 128, BCRYPT_MD2_ALGORITHM },
204 /* ALG_ID_MD4 */ { 270, 16, 512, BCRYPT_MD4_ALGORITHM },
205 /* ALG_ID_MD5 */ { 274, 16, 512, BCRYPT_MD5_ALGORITHM },
206 /* ALG_ID_RNG */ { 0, 0, 0, BCRYPT_RNG_ALGORITHM },
207 /* ALG_ID_SHA1 */ { 278, 20, 512, BCRYPT_SHA1_ALGORITHM },
208 /* ALG_ID_SHA256 */ { 286, 32, 512, BCRYPT_SHA256_ALGORITHM },
209 /* ALG_ID_SHA384 */ { 382, 48, 1024, BCRYPT_SHA384_ALGORITHM },
210 /* ALG_ID_SHA512 */ { 382, 64, 1024, BCRYPT_SHA512_ALGORITHM }
213 struct algorithm
215 struct object hdr;
216 enum alg_id id;
217 BOOL hmac;
220 NTSTATUS WINAPI BCryptGenRandom(BCRYPT_ALG_HANDLE handle, UCHAR *buffer, ULONG count, ULONG flags)
222 const DWORD supported_flags = BCRYPT_USE_SYSTEM_PREFERRED_RNG;
223 struct algorithm *algorithm = handle;
225 TRACE("%p, %p, %u, %08x - semi-stub\n", handle, buffer, count, flags);
227 if (!algorithm)
229 /* It's valid to call without an algorithm if BCRYPT_USE_SYSTEM_PREFERRED_RNG
230 * is set. In this case the preferred system RNG is used.
232 if (!(flags & BCRYPT_USE_SYSTEM_PREFERRED_RNG))
233 return STATUS_INVALID_HANDLE;
235 else if (algorithm->hdr.magic != MAGIC_ALG || algorithm->id != ALG_ID_RNG)
236 return STATUS_INVALID_HANDLE;
238 if (!buffer)
239 return STATUS_INVALID_PARAMETER;
241 if (flags & ~supported_flags)
242 FIXME("unsupported flags %08x\n", flags & ~supported_flags);
244 if (algorithm)
245 FIXME("ignoring selected algorithm\n");
247 /* When zero bytes are requested the function returns success too. */
248 if (!count)
249 return STATUS_SUCCESS;
251 if (algorithm || (flags & BCRYPT_USE_SYSTEM_PREFERRED_RNG))
253 if (RtlGenRandom(buffer, count))
254 return STATUS_SUCCESS;
257 FIXME("called with unsupported parameters, returning error\n");
258 return STATUS_NOT_IMPLEMENTED;
261 NTSTATUS WINAPI BCryptOpenAlgorithmProvider( BCRYPT_ALG_HANDLE *handle, LPCWSTR id, LPCWSTR implementation, DWORD flags )
263 const DWORD supported_flags = BCRYPT_ALG_HANDLE_HMAC_FLAG;
264 struct algorithm *alg;
265 enum alg_id alg_id;
267 TRACE( "%p, %s, %s, %08x\n", handle, wine_dbgstr_w(id), wine_dbgstr_w(implementation), flags );
269 if (!handle || !id) return STATUS_INVALID_PARAMETER;
270 if (flags & ~supported_flags)
272 FIXME( "unsupported flags %08x\n", flags & ~supported_flags);
273 return STATUS_NOT_IMPLEMENTED;
276 if (!strcmpW( id, BCRYPT_AES_ALGORITHM )) alg_id = ALG_ID_AES;
277 else if (!strcmpW( id, BCRYPT_MD2_ALGORITHM )) alg_id = ALG_ID_MD2;
278 else if (!strcmpW( id, BCRYPT_MD4_ALGORITHM )) alg_id = ALG_ID_MD4;
279 else if (!strcmpW( id, BCRYPT_MD5_ALGORITHM )) alg_id = ALG_ID_MD5;
280 else if (!strcmpW( id, BCRYPT_RNG_ALGORITHM )) alg_id = ALG_ID_RNG;
281 else if (!strcmpW( id, BCRYPT_SHA1_ALGORITHM )) alg_id = ALG_ID_SHA1;
282 else if (!strcmpW( id, BCRYPT_SHA256_ALGORITHM )) alg_id = ALG_ID_SHA256;
283 else if (!strcmpW( id, BCRYPT_SHA384_ALGORITHM )) alg_id = ALG_ID_SHA384;
284 else if (!strcmpW( id, BCRYPT_SHA512_ALGORITHM )) alg_id = ALG_ID_SHA512;
285 else
287 FIXME( "algorithm %s not supported\n", debugstr_w(id) );
288 return STATUS_NOT_IMPLEMENTED;
290 if (implementation && strcmpW( implementation, MS_PRIMITIVE_PROVIDER ))
292 FIXME( "implementation %s not supported\n", debugstr_w(implementation) );
293 return STATUS_NOT_IMPLEMENTED;
296 if (!(alg = HeapAlloc( GetProcessHeap(), 0, sizeof(*alg) ))) return STATUS_NO_MEMORY;
297 alg->hdr.magic = MAGIC_ALG;
298 alg->id = alg_id;
299 alg->hmac = flags & BCRYPT_ALG_HANDLE_HMAC_FLAG;
301 *handle = alg;
302 return STATUS_SUCCESS;
305 NTSTATUS WINAPI BCryptCloseAlgorithmProvider( BCRYPT_ALG_HANDLE handle, DWORD flags )
307 struct algorithm *alg = handle;
309 TRACE( "%p, %08x\n", handle, flags );
311 if (!alg || alg->hdr.magic != MAGIC_ALG) return STATUS_INVALID_HANDLE;
312 HeapFree( GetProcessHeap(), 0, alg );
313 return STATUS_SUCCESS;
316 NTSTATUS WINAPI BCryptGetFipsAlgorithmMode(BOOLEAN *enabled)
318 FIXME("%p - semi-stub\n", enabled);
320 if (!enabled)
321 return STATUS_INVALID_PARAMETER;
323 *enabled = FALSE;
324 return STATUS_SUCCESS;
327 struct hash_impl
329 union
331 MD2_CTX md2;
332 MD4_CTX md4;
333 MD5_CTX md5;
334 SHA_CTX sha1;
335 SHA256_CTX sha256;
336 SHA512_CTX sha512;
337 } u;
340 static NTSTATUS hash_init( struct hash_impl *hash, enum alg_id alg_id )
342 switch (alg_id)
344 case ALG_ID_MD2:
345 md2_init( &hash->u.md2 );
346 break;
348 case ALG_ID_MD4:
349 MD4Init( &hash->u.md4 );
350 break;
352 case ALG_ID_MD5:
353 MD5Init( &hash->u.md5 );
354 break;
356 case ALG_ID_SHA1:
357 A_SHAInit( &hash->u.sha1 );
358 break;
360 case ALG_ID_SHA256:
361 sha256_init( &hash->u.sha256 );
362 break;
364 case ALG_ID_SHA384:
365 sha384_init( &hash->u.sha512 );
366 break;
368 case ALG_ID_SHA512:
369 sha512_init( &hash->u.sha512 );
370 break;
372 default:
373 ERR( "unhandled id %u\n", alg_id );
374 return STATUS_NOT_IMPLEMENTED;
376 return STATUS_SUCCESS;
379 static NTSTATUS hash_update( struct hash_impl *hash, enum alg_id alg_id,
380 UCHAR *input, ULONG size )
382 switch (alg_id)
384 case ALG_ID_MD2:
385 md2_update( &hash->u.md2, input, size );
386 break;
388 case ALG_ID_MD4:
389 MD4Update( &hash->u.md4, input, size );
390 break;
392 case ALG_ID_MD5:
393 MD5Update( &hash->u.md5, input, size );
394 break;
396 case ALG_ID_SHA1:
397 A_SHAUpdate( &hash->u.sha1, input, size );
398 break;
400 case ALG_ID_SHA256:
401 sha256_update( &hash->u.sha256, input, size );
402 break;
404 case ALG_ID_SHA384:
405 sha384_update( &hash->u.sha512, input, size );
406 break;
408 case ALG_ID_SHA512:
409 sha512_update( &hash->u.sha512, input, size );
410 break;
412 default:
413 ERR( "unhandled id %u\n", alg_id );
414 return STATUS_NOT_IMPLEMENTED;
416 return STATUS_SUCCESS;
419 static NTSTATUS hash_finish( struct hash_impl *hash, enum alg_id alg_id,
420 UCHAR *output, ULONG size )
422 switch (alg_id)
424 case ALG_ID_MD2:
425 md2_finalize( &hash->u.md2, output );
426 break;
428 case ALG_ID_MD4:
429 MD4Final( &hash->u.md4 );
430 memcpy( output, hash->u.md4.digest, 16 );
431 break;
433 case ALG_ID_MD5:
434 MD5Final( &hash->u.md5 );
435 memcpy( output, hash->u.md5.digest, 16 );
436 break;
438 case ALG_ID_SHA1:
439 A_SHAFinal( &hash->u.sha1, (ULONG *)output );
440 break;
442 case ALG_ID_SHA256:
443 sha256_finalize( &hash->u.sha256, output );
444 break;
446 case ALG_ID_SHA384:
447 sha384_finalize( &hash->u.sha512, output );
448 break;
450 case ALG_ID_SHA512:
451 sha512_finalize( &hash->u.sha512, output );
452 break;
454 default:
455 ERR( "unhandled id %u\n", alg_id );
456 return STATUS_NOT_IMPLEMENTED;
458 return STATUS_SUCCESS;
461 struct hash
463 struct object hdr;
464 enum alg_id alg_id;
465 BOOL hmac;
466 struct hash_impl outer;
467 struct hash_impl inner;
470 #define BLOCK_LENGTH_AES 16
472 static NTSTATUS generic_alg_property( enum alg_id id, const WCHAR *prop, UCHAR *buf, ULONG size, ULONG *ret_size )
474 if (!strcmpW( prop, BCRYPT_OBJECT_LENGTH ))
476 if (!alg_props[id].object_length)
477 return STATUS_NOT_SUPPORTED;
478 *ret_size = sizeof(ULONG);
479 if (size < sizeof(ULONG))
480 return STATUS_BUFFER_TOO_SMALL;
481 if (buf)
482 *(ULONG *)buf = alg_props[id].object_length;
483 return STATUS_SUCCESS;
486 if (!strcmpW( prop, BCRYPT_HASH_LENGTH ))
488 if (!alg_props[id].hash_length)
489 return STATUS_NOT_SUPPORTED;
490 *ret_size = sizeof(ULONG);
491 if (size < sizeof(ULONG))
492 return STATUS_BUFFER_TOO_SMALL;
493 if(buf)
494 *(ULONG*)buf = alg_props[id].hash_length;
495 return STATUS_SUCCESS;
498 if (!strcmpW( prop, BCRYPT_ALGORITHM_NAME ))
500 *ret_size = (strlenW(alg_props[id].alg_name)+1)*sizeof(WCHAR);
501 if (size < *ret_size)
502 return STATUS_BUFFER_TOO_SMALL;
503 if(buf)
504 memcpy(buf, alg_props[id].alg_name, *ret_size);
505 return STATUS_SUCCESS;
508 return STATUS_NOT_IMPLEMENTED;
511 static NTSTATUS get_alg_property( enum alg_id id, const WCHAR *prop, UCHAR *buf, ULONG size, ULONG *ret_size )
513 NTSTATUS status;
515 status = generic_alg_property( id, prop, buf, size, ret_size );
516 if (status != STATUS_NOT_IMPLEMENTED)
517 return status;
519 switch (id)
521 case ALG_ID_AES:
522 if (!strcmpW( prop, BCRYPT_BLOCK_LENGTH ))
524 *ret_size = sizeof(ULONG);
525 if (size < sizeof(ULONG))
526 return STATUS_BUFFER_TOO_SMALL;
527 if (buf)
528 *(ULONG *)buf = BLOCK_LENGTH_AES;
529 return STATUS_SUCCESS;
531 if (!strcmpW( prop, BCRYPT_CHAINING_MODE ))
533 if (size >= sizeof(BCRYPT_CHAIN_MODE_CBC))
535 memcpy(buf, BCRYPT_CHAIN_MODE_CBC, sizeof(BCRYPT_CHAIN_MODE_CBC));
536 *ret_size = sizeof(BCRYPT_CHAIN_MODE_CBC) * sizeof(WCHAR);
537 return STATUS_SUCCESS;
539 else
541 *ret_size = sizeof(BCRYPT_CHAIN_MODE_CBC) * sizeof(WCHAR);
542 return STATUS_BUFFER_TOO_SMALL;
545 if (!strcmpW( prop, BCRYPT_KEY_LENGTHS ))
547 BCRYPT_KEY_LENGTHS_STRUCT *key_lengths = (void *)buf;
548 *ret_size = sizeof(*key_lengths);
549 if (key_lengths && size < *ret_size) return STATUS_BUFFER_TOO_SMALL;
550 if (key_lengths)
552 key_lengths->dwMinLength = 128;
553 key_lengths->dwMaxLength = 256;
554 key_lengths->dwIncrement = 64;
556 return STATUS_SUCCESS;
558 break;
560 default:
561 break;
564 FIXME( "unsupported property %s\n", debugstr_w(prop) );
565 return STATUS_NOT_IMPLEMENTED;
568 static NTSTATUS get_hash_property( enum alg_id id, const WCHAR *prop, UCHAR *buf, ULONG size, ULONG *ret_size )
570 NTSTATUS status;
572 status = generic_alg_property( id, prop, buf, size, ret_size );
573 if (status == STATUS_NOT_IMPLEMENTED)
574 FIXME( "unsupported property %s\n", debugstr_w(prop) );
575 return status;
578 NTSTATUS WINAPI BCryptGetProperty( BCRYPT_HANDLE handle, LPCWSTR prop, UCHAR *buffer, ULONG count, ULONG *res, ULONG flags )
580 struct object *object = handle;
582 TRACE( "%p, %s, %p, %u, %p, %08x\n", handle, wine_dbgstr_w(prop), buffer, count, res, flags );
584 if (!object) return STATUS_INVALID_HANDLE;
585 if (!prop || !res) return STATUS_INVALID_PARAMETER;
587 switch (object->magic)
589 case MAGIC_ALG:
591 const struct algorithm *alg = (const struct algorithm *)object;
592 return get_alg_property( alg->id, prop, buffer, count, res );
594 case MAGIC_HASH:
596 const struct hash *hash = (const struct hash *)object;
597 return get_hash_property( hash->alg_id, prop, buffer, count, res );
599 default:
600 WARN( "unknown magic %08x\n", object->magic );
601 return STATUS_INVALID_HANDLE;
605 NTSTATUS WINAPI BCryptSetProperty( BCRYPT_HANDLE handle, const WCHAR *prop, UCHAR *value, ULONG size, ULONG flags )
607 FIXME( "%p, %s, %p, %u, %08x\n", handle, debugstr_w(prop), value, size, flags );
608 return STATUS_NOT_IMPLEMENTED;
611 NTSTATUS WINAPI BCryptCreateHash( BCRYPT_ALG_HANDLE algorithm, BCRYPT_HASH_HANDLE *handle, UCHAR *object, ULONG objectlen,
612 UCHAR *secret, ULONG secretlen, ULONG flags )
614 struct algorithm *alg = algorithm;
615 UCHAR buffer[MAX_HASH_BLOCK_BITS / 8] = {0};
616 struct hash *hash;
617 int block_bytes;
618 NTSTATUS status;
619 int i;
621 TRACE( "%p, %p, %p, %u, %p, %u, %08x - stub\n", algorithm, handle, object, objectlen,
622 secret, secretlen, flags );
623 if (flags)
625 FIXME( "unimplemented flags %08x\n", flags );
626 return STATUS_NOT_IMPLEMENTED;
629 if (!alg || alg->hdr.magic != MAGIC_ALG) return STATUS_INVALID_HANDLE;
630 if (object) FIXME( "ignoring object buffer\n" );
632 if (!(hash = HeapAlloc( GetProcessHeap(), 0, sizeof(*hash) ))) return STATUS_NO_MEMORY;
633 hash->hdr.magic = MAGIC_HASH;
634 hash->alg_id = alg->id;
635 hash->hmac = alg->hmac;
637 /* initialize hash */
638 if ((status = hash_init( &hash->inner, hash->alg_id ))) goto end;
639 if (!hash->hmac) goto end;
641 /* initialize hmac */
642 if ((status = hash_init( &hash->outer, hash->alg_id ))) goto end;
643 block_bytes = alg_props[hash->alg_id].block_bits / 8;
644 if (secretlen > block_bytes)
646 struct hash_impl temp;
647 if ((status = hash_init( &temp, hash->alg_id ))) goto end;
648 if ((status = hash_update( &temp, hash->alg_id, secret, secretlen ))) goto end;
649 if ((status = hash_finish( &temp, hash->alg_id, buffer,
650 alg_props[hash->alg_id].hash_length ))) goto end;
652 else
654 memcpy( buffer, secret, secretlen );
656 for (i = 0; i < block_bytes; i++) buffer[i] ^= 0x5c;
657 if ((status = hash_update( &hash->outer, hash->alg_id, buffer, block_bytes ))) goto end;
658 for (i = 0; i < block_bytes; i++) buffer[i] ^= (0x5c ^ 0x36);
659 status = hash_update( &hash->inner, hash->alg_id, buffer, block_bytes );
661 end:
662 if (status != STATUS_SUCCESS)
664 HeapFree( GetProcessHeap(), 0, hash );
665 return status;
668 *handle = hash;
669 return STATUS_SUCCESS;
672 NTSTATUS WINAPI BCryptDuplicateHash( BCRYPT_HASH_HANDLE handle, BCRYPT_HASH_HANDLE *handle_copy,
673 UCHAR *object, ULONG objectlen, ULONG flags )
675 struct hash *hash_orig = handle;
676 struct hash *hash_copy;
678 TRACE( "%p, %p, %p, %u, %u\n", handle, handle_copy, object, objectlen, flags );
680 if (!hash_orig || hash_orig->hdr.magic != MAGIC_HASH) return STATUS_INVALID_HANDLE;
681 if (!handle_copy) return STATUS_INVALID_PARAMETER;
682 if (object) FIXME( "ignoring object buffer\n" );
684 if (!(hash_copy = HeapAlloc( GetProcessHeap(), 0, sizeof(*hash_copy) )))
685 return STATUS_NO_MEMORY;
687 memcpy( hash_copy, hash_orig, sizeof(*hash_orig) );
689 *handle_copy = hash_copy;
690 return STATUS_SUCCESS;
693 NTSTATUS WINAPI BCryptDestroyHash( BCRYPT_HASH_HANDLE handle )
695 struct hash *hash = handle;
697 TRACE( "%p\n", handle );
699 if (!hash || hash->hdr.magic != MAGIC_HASH) return STATUS_INVALID_HANDLE;
700 HeapFree( GetProcessHeap(), 0, hash );
701 return STATUS_SUCCESS;
704 NTSTATUS WINAPI BCryptHashData( BCRYPT_HASH_HANDLE handle, UCHAR *input, ULONG size, ULONG flags )
706 struct hash *hash = handle;
708 TRACE( "%p, %p, %u, %08x\n", handle, input, size, flags );
710 if (!hash || hash->hdr.magic != MAGIC_HASH) return STATUS_INVALID_HANDLE;
711 if (!input) return STATUS_SUCCESS;
713 return hash_update( &hash->inner, hash->alg_id, input, size );
716 NTSTATUS WINAPI BCryptFinishHash( BCRYPT_HASH_HANDLE handle, UCHAR *output, ULONG size, ULONG flags )
718 UCHAR buffer[MAX_HASH_OUTPUT_BYTES];
719 struct hash *hash = handle;
720 NTSTATUS status;
721 int hash_length;
723 TRACE( "%p, %p, %u, %08x\n", handle, output, size, flags );
725 if (!hash || hash->hdr.magic != MAGIC_HASH) return STATUS_INVALID_HANDLE;
726 if (!output) return STATUS_INVALID_PARAMETER;
728 if (!hash->hmac)
729 return hash_finish( &hash->inner, hash->alg_id, output, size );
731 hash_length = alg_props[hash->alg_id].hash_length;
732 if ((status = hash_finish( &hash->inner, hash->alg_id, buffer, hash_length ))) return status;
733 if ((status = hash_update( &hash->outer, hash->alg_id, buffer, hash_length ))) return status;
734 return hash_finish( &hash->outer, hash->alg_id, output, size );
737 NTSTATUS WINAPI BCryptHash( BCRYPT_ALG_HANDLE algorithm, UCHAR *secret, ULONG secretlen,
738 UCHAR *input, ULONG inputlen, UCHAR *output, ULONG outputlen )
740 NTSTATUS status;
741 BCRYPT_HASH_HANDLE handle;
743 TRACE( "%p, %p, %u, %p, %u, %p, %u\n", algorithm, secret, secretlen,
744 input, inputlen, output, outputlen );
746 status = BCryptCreateHash( algorithm, &handle, NULL, 0, secret, secretlen, 0);
747 if (status != STATUS_SUCCESS)
749 return status;
752 status = BCryptHashData( handle, input, inputlen, 0 );
753 if (status != STATUS_SUCCESS)
755 BCryptDestroyHash( handle );
756 return status;
759 status = BCryptFinishHash( handle, output, outputlen, 0 );
760 if (status != STATUS_SUCCESS)
762 BCryptDestroyHash( handle );
763 return status;
766 return BCryptDestroyHash( handle );
769 #if defined(HAVE_GNUTLS_CIPHER_INIT) || defined(HAVE_COMMONCRYPTO_COMMONCRYPTOR_H)
770 static ULONG get_block_size( enum alg_id alg )
772 ULONG ret = 0, size = sizeof(ret);
773 get_alg_property( alg, BCRYPT_BLOCK_LENGTH, (UCHAR *)&ret, sizeof(ret), &size );
774 return ret;
776 #endif
778 #if defined(HAVE_GNUTLS_CIPHER_INIT) && !defined(HAVE_COMMONCRYPTO_COMMONCRYPTOR_H)
779 struct key
781 struct object hdr;
782 enum alg_id alg_id;
783 ULONG block_size;
784 gnutls_cipher_hd_t handle;
785 UCHAR *secret;
786 ULONG secret_len;
789 static NTSTATUS key_init( struct key *key, enum alg_id id, const UCHAR *secret, ULONG secret_len )
791 UCHAR *buffer;
793 if (!libgnutls_handle) return STATUS_INTERNAL_ERROR;
795 switch (id)
797 case ALG_ID_AES:
798 break;
800 default:
801 FIXME( "algorithm %u not supported\n", id );
802 return STATUS_NOT_SUPPORTED;
805 if (!(key->block_size = get_block_size( id ))) return STATUS_INVALID_PARAMETER;
806 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, secret_len ))) return STATUS_NO_MEMORY;
807 memcpy( buffer, secret, secret_len );
809 key->alg_id = id;
810 key->handle = 0; /* initialized on first use */
811 key->secret = buffer;
812 key->secret_len = secret_len;
814 return STATUS_SUCCESS;
817 static gnutls_cipher_algorithm_t get_gnutls_cipher( const struct key *key )
819 switch (key->alg_id)
821 case ALG_ID_AES:
822 FIXME( "handle block size and chaining mode\n" );
823 return GNUTLS_CIPHER_AES_128_CBC;
825 default:
826 FIXME( "algorithm %u not supported\n", key->alg_id );
827 return GNUTLS_CIPHER_UNKNOWN;
831 static NTSTATUS key_set_params( struct key *key, UCHAR *iv, ULONG iv_len )
833 gnutls_cipher_algorithm_t cipher;
834 gnutls_datum_t secret, vector;
835 int ret;
837 if (key->handle)
839 pgnutls_cipher_deinit( key->handle );
840 key->handle = NULL;
843 if ((cipher = get_gnutls_cipher( key )) == GNUTLS_CIPHER_UNKNOWN)
844 return STATUS_NOT_SUPPORTED;
846 secret.data = key->secret;
847 secret.size = key->secret_len;
848 if (iv)
850 vector.data = iv;
851 vector.size = iv_len;
854 if ((ret = pgnutls_cipher_init( &key->handle, cipher, &secret, iv ? &vector : NULL )))
856 pgnutls_perror( ret );
857 return STATUS_INTERNAL_ERROR;
860 return STATUS_SUCCESS;
863 static NTSTATUS key_encrypt( struct key *key, const UCHAR *input, ULONG input_len, UCHAR *output,
864 ULONG output_len )
866 int ret;
868 if ((ret = pgnutls_cipher_encrypt2( key->handle, input, input_len, output, output_len )))
870 pgnutls_perror( ret );
871 return STATUS_INTERNAL_ERROR;
874 return STATUS_SUCCESS;
877 static NTSTATUS key_decrypt( struct key *key, const UCHAR *input, ULONG input_len, UCHAR *output,
878 ULONG output_len )
880 int ret;
882 if ((ret = pgnutls_cipher_decrypt2( key->handle, input, input_len, output, output_len )))
884 pgnutls_perror( ret );
885 return STATUS_INTERNAL_ERROR;
888 return STATUS_SUCCESS;
891 static NTSTATUS key_destroy( struct key *key )
893 if (key->handle) pgnutls_cipher_deinit( key->handle );
894 HeapFree( GetProcessHeap(), 0, key->secret );
895 HeapFree( GetProcessHeap(), 0, key );
896 return STATUS_SUCCESS;
898 #elif defined(HAVE_COMMONCRYPTO_COMMONCRYPTOR_H)
899 struct key
901 struct object hdr;
902 enum alg_id alg_id;
903 ULONG block_size;
904 CCCryptorRef ref_encrypt;
905 CCCryptorRef ref_decrypt;
906 UCHAR *secret;
907 ULONG secret_len;
910 static NTSTATUS key_init( struct key *key, enum alg_id id, const UCHAR *secret, ULONG secret_len )
912 UCHAR *buffer;
914 switch (id)
916 case ALG_ID_AES:
917 break;
919 default:
920 FIXME( "algorithm %u not supported\n", id );
921 return STATUS_NOT_SUPPORTED;
924 if (!(key->block_size = get_block_size( id ))) return STATUS_INVALID_PARAMETER;
925 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, secret_len ))) return STATUS_NO_MEMORY;
926 memcpy( buffer, secret, secret_len );
928 key->alg_id = id;
929 key->ref_encrypt = NULL; /* initialized on first use */
930 key->ref_decrypt = NULL;
931 key->secret = buffer;
932 key->secret_len = secret_len;
934 return STATUS_SUCCESS;
937 static NTSTATUS key_set_params( struct key *key, UCHAR *iv, ULONG iv_len )
939 CCCryptorStatus status;
941 if (key->ref_encrypt)
943 CCCryptorRelease( key->ref_encrypt );
944 key->ref_encrypt = NULL;
946 if (key->ref_decrypt)
948 CCCryptorRelease( key->ref_decrypt );
949 key->ref_decrypt = NULL;
952 if ((status = CCCryptorCreateWithMode( kCCEncrypt, kCCModeCBC, kCCAlgorithmAES, ccNoPadding, iv,
953 key->secret, key->secret_len, NULL, 0, 0, 0, &key->ref_encrypt )) != kCCSuccess)
955 WARN( "CCCryptorCreateWithMode failed %d\n", status );
956 return STATUS_INTERNAL_ERROR;
958 if ((status = CCCryptorCreateWithMode( kCCDecrypt, kCCModeCBC, kCCAlgorithmAES, ccNoPadding, iv,
959 key->secret, key->secret_len, NULL, 0, 0, 0, &key->ref_decrypt )) != kCCSuccess)
961 WARN( "CCCryptorCreateWithMode failed %d\n", status );
962 CCCryptorRelease( key->ref_encrypt );
963 key->ref_encrypt = NULL;
964 return STATUS_INTERNAL_ERROR;
967 return STATUS_SUCCESS;
970 static NTSTATUS key_encrypt( struct key *key, const UCHAR *input, ULONG input_len, UCHAR *output,
971 ULONG output_len )
973 CCCryptorStatus status;
975 if ((status = CCCryptorUpdate( key->ref_encrypt, input, input_len, output, output_len, NULL )) != kCCSuccess)
977 WARN( "CCCryptorUpdate failed %d\n", status );
978 return STATUS_INTERNAL_ERROR;
981 return STATUS_SUCCESS;
984 static NTSTATUS key_decrypt( struct key *key, const UCHAR *input, ULONG input_len, UCHAR *output,
985 ULONG output_len )
987 CCCryptorStatus status;
989 if ((status = CCCryptorUpdate( key->ref_decrypt, input, input_len, output, output_len, NULL )) != kCCSuccess)
991 WARN( "CCCryptorUpdate failed %d\n", status );
992 return STATUS_INTERNAL_ERROR;
995 return STATUS_SUCCESS;
998 static NTSTATUS key_destroy( struct key *key )
1000 if (key->ref_encrypt) CCCryptorRelease( key->ref_encrypt );
1001 if (key->ref_decrypt) CCCryptorRelease( key->ref_decrypt );
1002 HeapFree( GetProcessHeap(), 0, key->secret );
1003 HeapFree( GetProcessHeap(), 0, key );
1004 return STATUS_SUCCESS;
1006 #else
1007 struct key
1009 struct object hdr;
1010 ULONG block_size;
1013 static NTSTATUS key_init( struct key *key, enum alg_id id, const UCHAR *secret, ULONG secret_len )
1015 ERR( "support for keys not available at build time\n" );
1016 return STATUS_NOT_IMPLEMENTED;
1019 static NTSTATUS key_set_params( struct key *key, UCHAR *iv, ULONG iv_len )
1021 ERR( "support for keys not available at build time\n" );
1022 return STATUS_NOT_IMPLEMENTED;
1025 static NTSTATUS key_encrypt( struct key *key, const UCHAR *input, ULONG input_len, UCHAR *output,
1026 ULONG output_len )
1028 ERR( "support for keys not available at build time\n" );
1029 return STATUS_NOT_IMPLEMENTED;
1032 static NTSTATUS key_decrypt( struct key *key, const UCHAR *input, ULONG input_len, UCHAR *output,
1033 ULONG output_len )
1035 ERR( "support for keys not available at build time\n" );
1036 return STATUS_NOT_IMPLEMENTED;
1039 static NTSTATUS key_destroy( struct key *key )
1041 ERR( "support for keys not available at build time\n" );
1042 return STATUS_NOT_IMPLEMENTED;
1044 #endif
1046 NTSTATUS WINAPI BCryptGenerateSymmetricKey( BCRYPT_ALG_HANDLE algorithm, BCRYPT_KEY_HANDLE *handle,
1047 UCHAR *object, ULONG object_len, UCHAR *secret, ULONG secret_len,
1048 ULONG flags )
1050 struct algorithm *alg = algorithm;
1051 struct key *key;
1052 NTSTATUS status;
1054 TRACE( "%p, %p, %p, %u, %p, %u, %08x\n", algorithm, handle, object, object_len, secret, secret_len, flags );
1056 if (!alg || alg->hdr.magic != MAGIC_ALG) return STATUS_INVALID_HANDLE;
1057 if (object) FIXME( "ignoring object buffer\n" );
1059 if (!(key = HeapAlloc( GetProcessHeap(), 0, sizeof(*key) ))) return STATUS_NO_MEMORY;
1060 key->hdr.magic = MAGIC_KEY;
1062 if ((status = key_init( key, alg->id, secret, secret_len )))
1064 HeapFree( GetProcessHeap(), 0, key );
1065 return status;
1068 *handle = key;
1069 return STATUS_SUCCESS;
1072 NTSTATUS WINAPI BCryptDestroyKey( BCRYPT_KEY_HANDLE handle )
1074 struct key *key = handle;
1076 TRACE( "%p\n", handle );
1078 if (!key || key->hdr.magic != MAGIC_KEY) return STATUS_INVALID_HANDLE;
1079 return key_destroy( key );
1082 NTSTATUS WINAPI BCryptEncrypt( BCRYPT_KEY_HANDLE handle, UCHAR *input, ULONG input_len,
1083 void *padding, UCHAR *iv, ULONG iv_len, UCHAR *output,
1084 ULONG output_len, ULONG *ret_len, ULONG flags )
1086 struct key *key = handle;
1087 ULONG bytes_left = input_len;
1088 UCHAR *buf, *src, *dst;
1089 NTSTATUS status;
1091 TRACE( "%p, %p, %u, %p, %p, %u, %p, %u, %p, %08x\n", handle, input, input_len,
1092 padding, iv, iv_len, output, output_len, ret_len, flags );
1094 if (!key || key->hdr.magic != MAGIC_KEY) return STATUS_INVALID_HANDLE;
1095 if (padding)
1097 FIXME( "padding info not implemented\n" );
1098 return STATUS_NOT_IMPLEMENTED;
1100 if (flags & ~BCRYPT_BLOCK_PADDING)
1102 FIXME( "flags %08x not implemented\n", flags );
1103 return STATUS_NOT_IMPLEMENTED;
1106 if ((status = key_set_params( key, iv, iv_len ))) return status;
1108 *ret_len = input_len;
1110 if (flags & BCRYPT_BLOCK_PADDING)
1111 *ret_len = (input_len + key->block_size) & ~(key->block_size - 1);
1112 else if (input_len & (key->block_size - 1))
1113 return STATUS_INVALID_BUFFER_SIZE;
1115 if (!output) return STATUS_SUCCESS;
1116 if (output_len < *ret_len) return STATUS_BUFFER_TOO_SMALL;
1118 src = input;
1119 dst = output;
1120 while (bytes_left >= key->block_size)
1122 if ((status = key_encrypt( key, src, key->block_size, dst, key->block_size ))) return status;
1123 bytes_left -= key->block_size;
1124 src += key->block_size;
1125 dst += key->block_size;
1128 if (flags & BCRYPT_BLOCK_PADDING)
1130 if (!(buf = HeapAlloc( GetProcessHeap(), 0, key->block_size ))) return STATUS_NO_MEMORY;
1131 memcpy( buf, src, bytes_left );
1132 memset( buf + bytes_left, key->block_size - bytes_left, key->block_size - bytes_left );
1133 status = key_encrypt( key, buf, key->block_size, dst, key->block_size );
1134 HeapFree( GetProcessHeap(), 0, buf );
1137 return status;
1140 NTSTATUS WINAPI BCryptDecrypt( BCRYPT_KEY_HANDLE handle, UCHAR *input, ULONG input_len,
1141 void *padding, UCHAR *iv, ULONG iv_len, UCHAR *output,
1142 ULONG output_len, ULONG *ret_len, ULONG flags )
1144 struct key *key = handle;
1145 ULONG bytes_left = input_len;
1146 UCHAR *buf, *src, *dst;
1147 NTSTATUS status;
1149 TRACE( "%p, %p, %u, %p, %p, %u, %p, %u, %p, %08x\n", handle, input, input_len,
1150 padding, iv, iv_len, output, output_len, ret_len, flags );
1152 if (!key || key->hdr.magic != MAGIC_KEY) return STATUS_INVALID_HANDLE;
1153 if (padding)
1155 FIXME( "padding info not implemented\n" );
1156 return STATUS_NOT_IMPLEMENTED;
1158 if (flags & ~BCRYPT_BLOCK_PADDING)
1160 FIXME( "flags %08x not supported\n", flags );
1161 return STATUS_NOT_IMPLEMENTED;
1164 if ((status = key_set_params( key, iv, iv_len ))) return status;
1166 *ret_len = input_len;
1168 if (input_len & (key->block_size - 1)) return STATUS_INVALID_BUFFER_SIZE;
1169 if (!output) return STATUS_SUCCESS;
1170 if (flags & BCRYPT_BLOCK_PADDING)
1172 if (output_len + key->block_size < *ret_len) return STATUS_BUFFER_TOO_SMALL;
1173 if (input_len < key->block_size) return STATUS_BUFFER_TOO_SMALL;
1174 bytes_left -= key->block_size;
1176 else if (output_len < *ret_len)
1177 return STATUS_BUFFER_TOO_SMALL;
1179 src = input;
1180 dst = output;
1181 while (bytes_left >= key->block_size)
1183 if ((status = key_decrypt( key, src, key->block_size, dst, key->block_size ))) return status;
1184 bytes_left -= key->block_size;
1185 src += key->block_size;
1186 dst += key->block_size;
1189 if (flags & BCRYPT_BLOCK_PADDING)
1191 if (!(buf = HeapAlloc( GetProcessHeap(), 0, key->block_size ))) return STATUS_NO_MEMORY;
1192 status = key_decrypt( key, src, key->block_size, buf, key->block_size );
1193 if (!status && buf[ key->block_size - 1 ] <= key->block_size)
1195 *ret_len -= buf[ key->block_size - 1 ];
1196 if (output_len < *ret_len) status = STATUS_BUFFER_TOO_SMALL;
1197 else memcpy( dst, buf, key->block_size - buf[ key->block_size - 1 ] );
1199 else
1200 status = STATUS_UNSUCCESSFUL; /* FIXME: invalid padding */
1201 HeapFree( GetProcessHeap(), 0, buf );
1204 return status;
1207 BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
1209 switch (reason)
1211 case DLL_PROCESS_ATTACH:
1212 instance = hinst;
1213 DisableThreadLibraryCalls( hinst );
1214 #if defined(HAVE_GNUTLS_CIPHER_INIT) && !defined(HAVE_COMMONCRYPTO_COMMONCRYPTOR_H)
1215 gnutls_initialize();
1216 #endif
1217 break;
1219 case DLL_PROCESS_DETACH:
1220 if (reserved) break;
1221 #if defined(HAVE_GNUTLS_CIPHER_INIT) && !defined(HAVE_COMMONCRYPTO_COMMONCRYPTOR_H)
1222 gnutls_uninitialize();
1223 #endif
1224 break;
1226 return TRUE;