bcrypt: Implement BCryptEncrypt.
[wine.git] / dlls / bcrypt / bcrypt_main.c
blob633765bb931f438a075ac2999d68e0462c407f9b
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_COMMONDIGEST_H
25 #include <CommonCrypto/CommonDigest.h>
26 #include <CommonCrypto/CommonHMAC.h>
27 #elif defined(SONAME_LIBGNUTLS)
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/library.h"
43 #include "wine/unicode.h"
45 WINE_DEFAULT_DEBUG_CHANNEL(bcrypt);
47 static HINSTANCE instance;
49 #if defined(HAVE_GNUTLS_HASH) && !defined(HAVE_COMMONCRYPTO_COMMONDIGEST_H)
50 WINE_DECLARE_DEBUG_CHANNEL(winediag);
52 static void *libgnutls_handle;
53 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
54 MAKE_FUNCPTR(gnutls_cipher_init);
55 MAKE_FUNCPTR(gnutls_cipher_deinit);
56 MAKE_FUNCPTR(gnutls_cipher_encrypt2);
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 crypto hashes\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_init)
87 LOAD_FUNCPTR(gnutls_cipher_deinit)
88 LOAD_FUNCPTR(gnutls_cipher_encrypt2)
89 LOAD_FUNCPTR(gnutls_global_deinit)
90 LOAD_FUNCPTR(gnutls_global_init)
91 LOAD_FUNCPTR(gnutls_global_set_log_function)
92 LOAD_FUNCPTR(gnutls_global_set_log_level)
93 LOAD_FUNCPTR(gnutls_perror)
94 #undef LOAD_FUNCPTR
96 if ((ret = pgnutls_global_init()) != GNUTLS_E_SUCCESS)
98 pgnutls_perror( ret );
99 goto fail;
102 if (TRACE_ON( bcrypt ))
104 pgnutls_global_set_log_level( 4 );
105 pgnutls_global_set_log_function( gnutls_log );
108 return TRUE;
110 fail:
111 wine_dlclose( libgnutls_handle, NULL, 0 );
112 libgnutls_handle = NULL;
113 return FALSE;
116 static void gnutls_uninitialize(void)
118 pgnutls_global_deinit();
119 wine_dlclose( libgnutls_handle, NULL, 0 );
120 libgnutls_handle = NULL;
122 #endif /* HAVE_GNUTLS_HASH && !HAVE_COMMONCRYPTO_COMMONDIGEST_H */
124 NTSTATUS WINAPI BCryptEnumAlgorithms(ULONG dwAlgOperations, ULONG *pAlgCount,
125 BCRYPT_ALGORITHM_IDENTIFIER **ppAlgList, ULONG dwFlags)
127 FIXME("%08x, %p, %p, %08x - stub\n", dwAlgOperations, pAlgCount, ppAlgList, dwFlags);
129 *ppAlgList=NULL;
130 *pAlgCount=0;
132 return STATUS_NOT_IMPLEMENTED;
135 #define MAGIC_ALG (('A' << 24) | ('L' << 16) | ('G' << 8) | '0')
136 #define MAGIC_HASH (('H' << 24) | ('A' << 16) | ('S' << 8) | 'H')
137 #define MAGIC_KEY (('K' << 24) | ('E' << 16) | ('Y' << 8) | '0')
138 struct object
140 ULONG magic;
143 enum alg_id
145 ALG_ID_AES,
146 ALG_ID_MD5,
147 ALG_ID_RNG,
148 ALG_ID_SHA1,
149 ALG_ID_SHA256,
150 ALG_ID_SHA384,
151 ALG_ID_SHA512
154 #define MAX_HASH_OUTPUT_BYTES 64
155 #define MAX_HASH_BLOCK_BITS 1024
157 static const struct {
158 ULONG object_length;
159 ULONG hash_length;
160 ULONG block_bits;
161 const WCHAR *alg_name;
162 } alg_props[] = {
163 /* ALG_ID_AES */ { 654, 0, 0, BCRYPT_AES_ALGORITHM },
164 /* ALG_ID_MD5 */ { 274, 16, 512, BCRYPT_MD5_ALGORITHM },
165 /* ALG_ID_RNG */ { 0, 0, 0, BCRYPT_RNG_ALGORITHM },
166 /* ALG_ID_SHA1 */ { 278, 20, 512, BCRYPT_SHA1_ALGORITHM },
167 /* ALG_ID_SHA256 */ { 286, 32, 512, BCRYPT_SHA256_ALGORITHM },
168 /* ALG_ID_SHA384 */ { 382, 48, 1024, BCRYPT_SHA384_ALGORITHM },
169 /* ALG_ID_SHA512 */ { 382, 64, 1024, BCRYPT_SHA512_ALGORITHM }
172 struct algorithm
174 struct object hdr;
175 enum alg_id id;
176 BOOL hmac;
179 NTSTATUS WINAPI BCryptGenRandom(BCRYPT_ALG_HANDLE handle, UCHAR *buffer, ULONG count, ULONG flags)
181 const DWORD supported_flags = BCRYPT_USE_SYSTEM_PREFERRED_RNG;
182 struct algorithm *algorithm = handle;
184 TRACE("%p, %p, %u, %08x - semi-stub\n", handle, buffer, count, flags);
186 if (!algorithm)
188 /* It's valid to call without an algorithm if BCRYPT_USE_SYSTEM_PREFERRED_RNG
189 * is set. In this case the preferred system RNG is used.
191 if (!(flags & BCRYPT_USE_SYSTEM_PREFERRED_RNG))
192 return STATUS_INVALID_HANDLE;
194 else if (algorithm->hdr.magic != MAGIC_ALG || algorithm->id != ALG_ID_RNG)
195 return STATUS_INVALID_HANDLE;
197 if (!buffer)
198 return STATUS_INVALID_PARAMETER;
200 if (flags & ~supported_flags)
201 FIXME("unsupported flags %08x\n", flags & ~supported_flags);
203 if (algorithm)
204 FIXME("ignoring selected algorithm\n");
206 /* When zero bytes are requested the function returns success too. */
207 if (!count)
208 return STATUS_SUCCESS;
210 if (algorithm || (flags & BCRYPT_USE_SYSTEM_PREFERRED_RNG))
212 if (RtlGenRandom(buffer, count))
213 return STATUS_SUCCESS;
216 FIXME("called with unsupported parameters, returning error\n");
217 return STATUS_NOT_IMPLEMENTED;
220 NTSTATUS WINAPI BCryptOpenAlgorithmProvider( BCRYPT_ALG_HANDLE *handle, LPCWSTR id, LPCWSTR implementation, DWORD flags )
222 const DWORD supported_flags = BCRYPT_ALG_HANDLE_HMAC_FLAG;
223 struct algorithm *alg;
224 enum alg_id alg_id;
226 TRACE( "%p, %s, %s, %08x\n", handle, wine_dbgstr_w(id), wine_dbgstr_w(implementation), flags );
228 if (!handle || !id) return STATUS_INVALID_PARAMETER;
229 if (flags & ~supported_flags)
231 FIXME( "unsupported flags %08x\n", flags & ~supported_flags);
232 return STATUS_NOT_IMPLEMENTED;
235 if (!strcmpW( id, BCRYPT_AES_ALGORITHM )) alg_id = ALG_ID_AES;
236 else if (!strcmpW( id, BCRYPT_MD5_ALGORITHM )) alg_id = ALG_ID_MD5;
237 else if (!strcmpW( id, BCRYPT_RNG_ALGORITHM )) alg_id = ALG_ID_RNG;
238 else if (!strcmpW( id, BCRYPT_SHA1_ALGORITHM )) alg_id = ALG_ID_SHA1;
239 else if (!strcmpW( id, BCRYPT_SHA256_ALGORITHM )) alg_id = ALG_ID_SHA256;
240 else if (!strcmpW( id, BCRYPT_SHA384_ALGORITHM )) alg_id = ALG_ID_SHA384;
241 else if (!strcmpW( id, BCRYPT_SHA512_ALGORITHM )) alg_id = ALG_ID_SHA512;
242 else
244 FIXME( "algorithm %s not supported\n", debugstr_w(id) );
245 return STATUS_NOT_IMPLEMENTED;
247 if (implementation && strcmpW( implementation, MS_PRIMITIVE_PROVIDER ))
249 FIXME( "implementation %s not supported\n", debugstr_w(implementation) );
250 return STATUS_NOT_IMPLEMENTED;
253 if (!(alg = HeapAlloc( GetProcessHeap(), 0, sizeof(*alg) ))) return STATUS_NO_MEMORY;
254 alg->hdr.magic = MAGIC_ALG;
255 alg->id = alg_id;
256 alg->hmac = flags & BCRYPT_ALG_HANDLE_HMAC_FLAG;
258 *handle = alg;
259 return STATUS_SUCCESS;
262 NTSTATUS WINAPI BCryptCloseAlgorithmProvider( BCRYPT_ALG_HANDLE handle, DWORD flags )
264 struct algorithm *alg = handle;
266 TRACE( "%p, %08x\n", handle, flags );
268 if (!alg || alg->hdr.magic != MAGIC_ALG) return STATUS_INVALID_HANDLE;
269 HeapFree( GetProcessHeap(), 0, alg );
270 return STATUS_SUCCESS;
273 NTSTATUS WINAPI BCryptGetFipsAlgorithmMode(BOOLEAN *enabled)
275 FIXME("%p - semi-stub\n", enabled);
277 if (!enabled)
278 return STATUS_INVALID_PARAMETER;
280 *enabled = FALSE;
281 return STATUS_SUCCESS;
284 struct hash_impl
286 union
288 MD5_CTX md5;
289 SHA_CTX sha1;
290 SHA256_CTX sha256;
291 SHA512_CTX sha512;
292 } u;
295 static NTSTATUS hash_init( struct hash_impl *hash, enum alg_id alg_id )
297 switch (alg_id)
299 case ALG_ID_MD5:
300 MD5Init( &hash->u.md5 );
301 break;
303 case ALG_ID_SHA1:
304 A_SHAInit( &hash->u.sha1 );
305 break;
307 case ALG_ID_SHA256:
308 sha256_init( &hash->u.sha256 );
309 break;
311 case ALG_ID_SHA384:
312 sha384_init( &hash->u.sha512 );
313 break;
315 case ALG_ID_SHA512:
316 sha512_init( &hash->u.sha512 );
317 break;
319 default:
320 ERR( "unhandled id %u\n", alg_id );
321 return STATUS_NOT_IMPLEMENTED;
323 return STATUS_SUCCESS;
326 static NTSTATUS hash_update( struct hash_impl *hash, enum alg_id alg_id,
327 UCHAR *input, ULONG size )
329 switch (alg_id)
331 case ALG_ID_MD5:
332 MD5Update( &hash->u.md5, input, size );
333 break;
335 case ALG_ID_SHA1:
336 A_SHAUpdate( &hash->u.sha1, input, size );
337 break;
339 case ALG_ID_SHA256:
340 sha256_update( &hash->u.sha256, input, size );
341 break;
343 case ALG_ID_SHA384:
344 sha384_update( &hash->u.sha512, input, size );
345 break;
347 case ALG_ID_SHA512:
348 sha512_update( &hash->u.sha512, input, size );
349 break;
351 default:
352 ERR( "unhandled id %u\n", alg_id );
353 return STATUS_NOT_IMPLEMENTED;
355 return STATUS_SUCCESS;
358 static NTSTATUS hash_finish( struct hash_impl *hash, enum alg_id alg_id,
359 UCHAR *output, ULONG size )
361 switch (alg_id)
363 case ALG_ID_MD5:
364 MD5Final( &hash->u.md5 );
365 memcpy( output, hash->u.md5.digest, 16 );
366 break;
368 case ALG_ID_SHA1:
369 A_SHAFinal( &hash->u.sha1, (ULONG *)output );
370 break;
372 case ALG_ID_SHA256:
373 sha256_finalize( &hash->u.sha256, output );
374 break;
376 case ALG_ID_SHA384:
377 sha384_finalize( &hash->u.sha512, output );
378 break;
380 case ALG_ID_SHA512:
381 sha512_finalize( &hash->u.sha512, output );
382 break;
384 default:
385 ERR( "unhandled id %u\n", alg_id );
386 return STATUS_NOT_IMPLEMENTED;
388 return STATUS_SUCCESS;
391 struct hash
393 struct object hdr;
394 enum alg_id alg_id;
395 BOOL hmac;
396 struct hash_impl outer;
397 struct hash_impl inner;
400 #define BLOCK_LENGTH_AES 16
402 static NTSTATUS generic_alg_property( enum alg_id id, const WCHAR *prop, UCHAR *buf, ULONG size, ULONG *ret_size )
404 if (!strcmpW( prop, BCRYPT_OBJECT_LENGTH ))
406 if (!alg_props[id].object_length)
407 return STATUS_NOT_SUPPORTED;
408 *ret_size = sizeof(ULONG);
409 if (size < sizeof(ULONG))
410 return STATUS_BUFFER_TOO_SMALL;
411 if (buf)
412 *(ULONG *)buf = alg_props[id].object_length;
413 return STATUS_SUCCESS;
416 if (!strcmpW( prop, BCRYPT_HASH_LENGTH ))
418 if (!alg_props[id].hash_length)
419 return STATUS_NOT_SUPPORTED;
420 *ret_size = sizeof(ULONG);
421 if (size < sizeof(ULONG))
422 return STATUS_BUFFER_TOO_SMALL;
423 if(buf)
424 *(ULONG*)buf = alg_props[id].hash_length;
425 return STATUS_SUCCESS;
428 if (!strcmpW( prop, BCRYPT_ALGORITHM_NAME ))
430 *ret_size = (strlenW(alg_props[id].alg_name)+1)*sizeof(WCHAR);
431 if (size < *ret_size)
432 return STATUS_BUFFER_TOO_SMALL;
433 if(buf)
434 memcpy(buf, alg_props[id].alg_name, *ret_size);
435 return STATUS_SUCCESS;
438 return STATUS_NOT_IMPLEMENTED;
441 static NTSTATUS get_alg_property( enum alg_id id, const WCHAR *prop, UCHAR *buf, ULONG size, ULONG *ret_size )
443 NTSTATUS status;
445 status = generic_alg_property( id, prop, buf, size, ret_size );
446 if (status != STATUS_NOT_IMPLEMENTED)
447 return status;
449 switch (id)
451 case ALG_ID_AES:
452 if (!strcmpW( prop, BCRYPT_BLOCK_LENGTH ))
454 *ret_size = sizeof(ULONG);
455 if (size < sizeof(ULONG))
456 return STATUS_BUFFER_TOO_SMALL;
457 if (buf)
458 *(ULONG *)buf = BLOCK_LENGTH_AES;
459 return STATUS_SUCCESS;
461 if (!strcmpW( prop, BCRYPT_CHAINING_MODE ))
463 if (size >= sizeof(BCRYPT_CHAIN_MODE_CBC))
465 memcpy(buf, BCRYPT_CHAIN_MODE_CBC, sizeof(BCRYPT_CHAIN_MODE_CBC));
466 *ret_size = sizeof(BCRYPT_CHAIN_MODE_CBC) * sizeof(WCHAR);
467 return STATUS_SUCCESS;
469 else
471 *ret_size = sizeof(BCRYPT_CHAIN_MODE_CBC) * sizeof(WCHAR);
472 return STATUS_BUFFER_TOO_SMALL;
475 break;
477 default:
478 break;
481 FIXME( "unsupported property %s\n", debugstr_w(prop) );
482 return STATUS_NOT_IMPLEMENTED;
485 static NTSTATUS get_hash_property( enum alg_id id, const WCHAR *prop, UCHAR *buf, ULONG size, ULONG *ret_size )
487 NTSTATUS status;
489 status = generic_alg_property( id, prop, buf, size, ret_size );
490 if (status == STATUS_NOT_IMPLEMENTED)
491 FIXME( "unsupported property %s\n", debugstr_w(prop) );
492 return status;
495 NTSTATUS WINAPI BCryptGetProperty( BCRYPT_HANDLE handle, LPCWSTR prop, UCHAR *buffer, ULONG count, ULONG *res, ULONG flags )
497 struct object *object = handle;
499 TRACE( "%p, %s, %p, %u, %p, %08x\n", handle, wine_dbgstr_w(prop), buffer, count, res, flags );
501 if (!object) return STATUS_INVALID_HANDLE;
502 if (!prop || !res) return STATUS_INVALID_PARAMETER;
504 switch (object->magic)
506 case MAGIC_ALG:
508 const struct algorithm *alg = (const struct algorithm *)object;
509 return get_alg_property( alg->id, prop, buffer, count, res );
511 case MAGIC_HASH:
513 const struct hash *hash = (const struct hash *)object;
514 return get_hash_property( hash->alg_id, prop, buffer, count, res );
516 default:
517 WARN( "unknown magic %08x\n", object->magic );
518 return STATUS_INVALID_HANDLE;
522 NTSTATUS WINAPI BCryptSetProperty( BCRYPT_HANDLE handle, const WCHAR *prop, UCHAR *value, ULONG size, ULONG flags )
524 FIXME( "%p, %s, %p, %u, %08x\n", handle, debugstr_w(prop), value, size, flags );
525 return STATUS_NOT_IMPLEMENTED;
528 NTSTATUS WINAPI BCryptCreateHash( BCRYPT_ALG_HANDLE algorithm, BCRYPT_HASH_HANDLE *handle, UCHAR *object, ULONG objectlen,
529 UCHAR *secret, ULONG secretlen, ULONG flags )
531 struct algorithm *alg = algorithm;
532 UCHAR buffer[MAX_HASH_BLOCK_BITS / 8] = {0};
533 struct hash *hash;
534 int block_bytes;
535 NTSTATUS status;
536 int i;
538 TRACE( "%p, %p, %p, %u, %p, %u, %08x - stub\n", algorithm, handle, object, objectlen,
539 secret, secretlen, flags );
540 if (flags)
542 FIXME( "unimplemented flags %08x\n", flags );
543 return STATUS_NOT_IMPLEMENTED;
546 if (!alg || alg->hdr.magic != MAGIC_ALG) return STATUS_INVALID_HANDLE;
547 if (object) FIXME( "ignoring object buffer\n" );
549 if (!(hash = HeapAlloc( GetProcessHeap(), 0, sizeof(*hash) ))) return STATUS_NO_MEMORY;
550 hash->hdr.magic = MAGIC_HASH;
551 hash->alg_id = alg->id;
552 hash->hmac = alg->hmac;
554 /* initialize hash */
555 if ((status = hash_init( &hash->inner, hash->alg_id ))) goto end;
556 if (!hash->hmac) goto end;
558 /* initialize hmac */
559 if ((status = hash_init( &hash->outer, hash->alg_id ))) goto end;
560 block_bytes = alg_props[hash->alg_id].block_bits / 8;
561 if (secretlen > block_bytes)
563 struct hash_impl temp;
564 if ((status = hash_init( &temp, hash->alg_id ))) goto end;
565 if ((status = hash_update( &temp, hash->alg_id, secret, secretlen ))) goto end;
566 if ((status = hash_finish( &temp, hash->alg_id, buffer,
567 alg_props[hash->alg_id].hash_length ))) goto end;
569 else
571 memcpy( buffer, secret, secretlen );
573 for (i = 0; i < block_bytes; i++) buffer[i] ^= 0x5c;
574 if ((status = hash_update( &hash->outer, hash->alg_id, buffer, block_bytes ))) goto end;
575 for (i = 0; i < block_bytes; i++) buffer[i] ^= (0x5c ^ 0x36);
576 status = hash_update( &hash->inner, hash->alg_id, buffer, block_bytes );
578 end:
579 if (status != STATUS_SUCCESS)
581 HeapFree( GetProcessHeap(), 0, hash );
582 return status;
585 *handle = hash;
586 return STATUS_SUCCESS;
589 NTSTATUS WINAPI BCryptDuplicateHash( BCRYPT_HASH_HANDLE handle, BCRYPT_HASH_HANDLE *handle_copy,
590 UCHAR *object, ULONG objectlen, ULONG flags )
592 struct hash *hash_orig = handle;
593 struct hash *hash_copy;
595 TRACE( "%p, %p, %p, %u, %u\n", handle, handle_copy, object, objectlen, flags );
597 if (!hash_orig || hash_orig->hdr.magic != MAGIC_HASH) return STATUS_INVALID_HANDLE;
598 if (!handle_copy) return STATUS_INVALID_PARAMETER;
599 if (object) FIXME( "ignoring object buffer\n" );
601 if (!(hash_copy = HeapAlloc( GetProcessHeap(), 0, sizeof(*hash_copy) )))
602 return STATUS_NO_MEMORY;
604 memcpy( hash_copy, hash_orig, sizeof(*hash_orig) );
606 *handle_copy = hash_copy;
607 return STATUS_SUCCESS;
610 NTSTATUS WINAPI BCryptDestroyHash( BCRYPT_HASH_HANDLE handle )
612 struct hash *hash = handle;
614 TRACE( "%p\n", handle );
616 if (!hash || hash->hdr.magic != MAGIC_HASH) return STATUS_INVALID_HANDLE;
617 HeapFree( GetProcessHeap(), 0, hash );
618 return STATUS_SUCCESS;
621 NTSTATUS WINAPI BCryptHashData( BCRYPT_HASH_HANDLE handle, UCHAR *input, ULONG size, ULONG flags )
623 struct hash *hash = handle;
625 TRACE( "%p, %p, %u, %08x\n", handle, input, size, flags );
627 if (!hash || hash->hdr.magic != MAGIC_HASH) return STATUS_INVALID_HANDLE;
628 if (!input) return STATUS_SUCCESS;
630 return hash_update( &hash->inner, hash->alg_id, input, size );
633 NTSTATUS WINAPI BCryptFinishHash( BCRYPT_HASH_HANDLE handle, UCHAR *output, ULONG size, ULONG flags )
635 UCHAR buffer[MAX_HASH_OUTPUT_BYTES];
636 struct hash *hash = handle;
637 NTSTATUS status;
638 int hash_length;
640 TRACE( "%p, %p, %u, %08x\n", handle, output, size, flags );
642 if (!hash || hash->hdr.magic != MAGIC_HASH) return STATUS_INVALID_HANDLE;
643 if (!output) return STATUS_INVALID_PARAMETER;
645 if (!hash->hmac)
646 return hash_finish( &hash->inner, hash->alg_id, output, size );
648 hash_length = alg_props[hash->alg_id].hash_length;
649 if ((status = hash_finish( &hash->inner, hash->alg_id, buffer, hash_length ))) return status;
650 if ((status = hash_update( &hash->outer, hash->alg_id, buffer, hash_length ))) return status;
651 return hash_finish( &hash->outer, hash->alg_id, output, size );
654 NTSTATUS WINAPI BCryptHash( BCRYPT_ALG_HANDLE algorithm, UCHAR *secret, ULONG secretlen,
655 UCHAR *input, ULONG inputlen, UCHAR *output, ULONG outputlen )
657 NTSTATUS status;
658 BCRYPT_HASH_HANDLE handle;
660 TRACE( "%p, %p, %u, %p, %u, %p, %u\n", algorithm, secret, secretlen,
661 input, inputlen, output, outputlen );
663 status = BCryptCreateHash( algorithm, &handle, NULL, 0, secret, secretlen, 0);
664 if (status != STATUS_SUCCESS)
666 return status;
669 status = BCryptHashData( handle, input, inputlen, 0 );
670 if (status != STATUS_SUCCESS)
672 BCryptDestroyHash( handle );
673 return status;
676 status = BCryptFinishHash( handle, output, outputlen, 0 );
677 if (status != STATUS_SUCCESS)
679 BCryptDestroyHash( handle );
680 return status;
683 return BCryptDestroyHash( handle );
686 #if defined(HAVE_GNUTLS_HASH) && !defined(HAVE_COMMONCRYPTO_COMMONDIGEST_H)
687 struct key
689 struct object hdr;
690 enum alg_id alg_id;
691 ULONG block_size;
692 gnutls_cipher_hd_t handle;
693 UCHAR *secret;
694 ULONG secret_len;
697 static ULONG get_block_size( enum alg_id alg )
699 ULONG ret = 0, size = sizeof(ret);
700 get_alg_property( alg, BCRYPT_BLOCK_LENGTH, (UCHAR *)&ret, sizeof(ret), &size );
701 return ret;
704 static NTSTATUS key_init( struct key *key, enum alg_id id, const UCHAR *secret, ULONG secret_len )
706 UCHAR *buffer;
708 if (!libgnutls_handle) return STATUS_INTERNAL_ERROR;
710 switch (id)
712 case ALG_ID_AES:
713 break;
715 default:
716 FIXME( "algorithm %u not supported\n", id );
717 return STATUS_NOT_SUPPORTED;
720 if (!(key->block_size = get_block_size( id ))) return STATUS_INVALID_PARAMETER;
721 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, secret_len ))) return STATUS_NO_MEMORY;
722 memcpy( buffer, secret, secret_len );
724 key->alg_id = id;
725 key->handle = 0; /* initialized on first use */
726 key->secret = buffer;
727 key->secret_len = secret_len;
729 return STATUS_SUCCESS;
732 static gnutls_cipher_algorithm_t get_gnutls_cipher( const struct key *key )
734 switch (key->alg_id)
736 case ALG_ID_AES:
737 FIXME( "handle block size and chaining mode\n" );
738 return GNUTLS_CIPHER_AES_128_CBC;
740 default:
741 FIXME( "algorithm %u not supported\n", key->alg_id );
742 return GNUTLS_CIPHER_UNKNOWN;
746 static NTSTATUS key_set_params( struct key *key, UCHAR *iv, ULONG iv_len )
748 gnutls_cipher_algorithm_t cipher;
749 gnutls_datum_t secret, vector;
750 int ret;
752 if (key->handle)
754 pgnutls_cipher_deinit( key->handle );
755 key->handle = NULL;
758 if ((cipher = get_gnutls_cipher( key )) == GNUTLS_CIPHER_UNKNOWN)
759 return STATUS_NOT_SUPPORTED;
761 secret.data = key->secret;
762 secret.size = key->secret_len;
763 if (iv)
765 vector.data = iv;
766 vector.size = iv_len;
769 if ((ret = pgnutls_cipher_init( &key->handle, cipher, &secret, iv ? &vector : NULL )))
771 pgnutls_perror( ret );
772 return STATUS_INTERNAL_ERROR;
775 return STATUS_SUCCESS;
778 static NTSTATUS key_encrypt( struct key *key, const UCHAR *input, ULONG input_len, UCHAR *output,
779 ULONG output_len )
781 int ret;
783 if ((ret = pgnutls_cipher_encrypt2( key->handle, input, input_len, output, output_len )))
785 pgnutls_perror( ret );
786 return STATUS_INTERNAL_ERROR;
789 return STATUS_SUCCESS;
792 static NTSTATUS key_destroy( struct key *key )
794 if (key->handle) pgnutls_cipher_deinit( key->handle );
795 HeapFree( GetProcessHeap(), 0, key->secret );
796 HeapFree( GetProcessHeap(), 0, key );
797 return STATUS_SUCCESS;
799 #else
800 struct key
802 struct object hdr;
803 ULONG block_size;
806 static NTSTATUS key_init( struct key *key, enum alg_id id, const UCHAR *secret, ULONG secret_len )
808 ERR( "support for keys not available at build time\n" );
809 return STATUS_NOT_IMPLEMENTED;
812 static NTSTATUS key_set_params( struct key *key, UCHAR *iv, ULONG iv_len )
814 ERR( "support for keys not available at build time\n" );
815 return STATUS_NOT_IMPLEMENTED;
818 static NTSTATUS key_encrypt( struct key *key, const UCHAR *input, ULONG input_len, UCHAR *output,
819 ULONG output_len )
821 ERR( "support for keys not available at build time\n" );
822 return STATUS_NOT_IMPLEMENTED;
825 static NTSTATUS key_destroy( struct key *key )
827 ERR( "support for keys not available at build time\n" );
828 return STATUS_NOT_IMPLEMENTED;
830 #endif
832 NTSTATUS WINAPI BCryptGenerateSymmetricKey( BCRYPT_ALG_HANDLE algorithm, BCRYPT_KEY_HANDLE *handle,
833 UCHAR *object, ULONG object_len, UCHAR *secret, ULONG secret_len,
834 ULONG flags )
836 struct algorithm *alg = algorithm;
837 struct key *key;
838 NTSTATUS status;
840 TRACE( "%p, %p, %p, %u, %p, %u, %08x\n", algorithm, handle, object, object_len, secret, secret_len, flags );
842 if (!alg || alg->hdr.magic != MAGIC_ALG) return STATUS_INVALID_HANDLE;
843 if (object) FIXME( "ignoring object buffer\n" );
845 if (!(key = HeapAlloc( GetProcessHeap(), 0, sizeof(*key) ))) return STATUS_NO_MEMORY;
846 key->hdr.magic = MAGIC_KEY;
848 if ((status = key_init( key, alg->id, secret, secret_len )))
850 HeapFree( GetProcessHeap(), 0, key );
851 return status;
854 *handle = key;
855 return STATUS_SUCCESS;
858 NTSTATUS WINAPI BCryptDestroyKey( BCRYPT_KEY_HANDLE handle )
860 struct key *key = handle;
862 TRACE( "%p\n", handle );
864 if (!key || key->hdr.magic != MAGIC_KEY) return STATUS_INVALID_HANDLE;
865 return key_destroy( key );
868 NTSTATUS WINAPI BCryptEncrypt( BCRYPT_KEY_HANDLE handle, UCHAR *input, ULONG input_len,
869 void *padding, UCHAR *iv, ULONG iv_len, UCHAR *output,
870 ULONG output_len, ULONG *ret_len, ULONG flags )
872 struct key *key = handle;
873 ULONG bytes_left = input_len;
874 UCHAR *buf, *src, *dst;
875 NTSTATUS status;
877 TRACE( "%p, %p, %u, %p, %p, %u, %p, %u, %p, %08x\n", handle, input, input_len,
878 padding, iv, iv_len, output, output_len, ret_len, flags );
880 if (!key || key->hdr.magic != MAGIC_KEY) return STATUS_INVALID_HANDLE;
881 if (padding)
883 FIXME( "padding info not implemented\n" );
884 return STATUS_NOT_IMPLEMENTED;
886 if (flags & ~BCRYPT_BLOCK_PADDING)
888 FIXME( "flags %08x not implemented\n", flags );
889 return STATUS_NOT_IMPLEMENTED;
892 if ((status = key_set_params( key, iv, iv_len ))) return status;
894 *ret_len = input_len;
896 if (flags & BCRYPT_BLOCK_PADDING)
897 *ret_len = (input_len + key->block_size) & ~(key->block_size - 1);
898 else if (input_len & (key->block_size - 1))
899 return STATUS_INVALID_BUFFER_SIZE;
901 if (!output) return STATUS_SUCCESS;
902 if (output_len < *ret_len) return STATUS_BUFFER_TOO_SMALL;
904 src = input;
905 dst = output;
906 while (bytes_left >= key->block_size)
908 if ((status = key_encrypt( key, src, key->block_size, dst, key->block_size ))) return status;
909 bytes_left -= key->block_size;
910 src += key->block_size;
911 dst += key->block_size;
914 if (flags & BCRYPT_BLOCK_PADDING)
916 if (!(buf = HeapAlloc( GetProcessHeap(), 0, key->block_size ))) return STATUS_NO_MEMORY;
917 memcpy( buf, src, bytes_left );
918 memset( buf + bytes_left, key->block_size - bytes_left, key->block_size - bytes_left );
919 status = key_encrypt( key, buf, key->block_size, dst, key->block_size );
920 HeapFree( GetProcessHeap(), 0, buf );
923 return status;
926 NTSTATUS WINAPI BCryptDecrypt( BCRYPT_KEY_HANDLE handle, UCHAR *input, ULONG input_len,
927 void *padding, UCHAR *iv, ULONG iv_len, UCHAR *output,
928 ULONG output_len, ULONG *ret_len, ULONG flags )
930 FIXME( "%p, %p, %u, %p, %p, %u, %p, %u, %p, %08x\n", handle, input, input_len,
931 padding, iv, iv_len, output, output_len, ret_len, flags );
932 return STATUS_NOT_IMPLEMENTED;
935 BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
937 switch (reason)
939 case DLL_PROCESS_ATTACH:
940 instance = hinst;
941 DisableThreadLibraryCalls( hinst );
942 #if defined(HAVE_GNUTLS_HASH) && !defined(HAVE_COMMONCRYPTO_COMMONDIGEST_H)
943 gnutls_initialize();
944 #endif
945 break;
947 case DLL_PROCESS_DETACH:
948 if (reserved) break;
949 #if defined(HAVE_GNUTLS_HASH) && !defined(HAVE_COMMONCRYPTO_COMMONDIGEST_H)
950 gnutls_uninitialize();
951 #endif
952 break;
954 return TRUE;