bcrypt: Implement BCryptGetProperty for BCRYPT_AUTH_TAG_LENGTH.
[wine.git] / dlls / bcrypt / bcrypt_main.c
blobfa80318f28f40472baed0908cca8c5a8a9f8d2b4
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 enum mode_id
197 MODE_ID_CBC,
198 MODE_ID_GCM
201 #define MAX_HASH_OUTPUT_BYTES 64
202 #define MAX_HASH_BLOCK_BITS 1024
204 static const struct {
205 ULONG object_length;
206 ULONG hash_length;
207 ULONG block_bits;
208 const WCHAR *alg_name;
209 } alg_props[] = {
210 /* ALG_ID_AES */ { 654, 0, 0, BCRYPT_AES_ALGORITHM },
211 /* ALG_ID_MD2 */ { 270, 16, 128, BCRYPT_MD2_ALGORITHM },
212 /* ALG_ID_MD4 */ { 270, 16, 512, BCRYPT_MD4_ALGORITHM },
213 /* ALG_ID_MD5 */ { 274, 16, 512, BCRYPT_MD5_ALGORITHM },
214 /* ALG_ID_RNG */ { 0, 0, 0, BCRYPT_RNG_ALGORITHM },
215 /* ALG_ID_SHA1 */ { 278, 20, 512, BCRYPT_SHA1_ALGORITHM },
216 /* ALG_ID_SHA256 */ { 286, 32, 512, BCRYPT_SHA256_ALGORITHM },
217 /* ALG_ID_SHA384 */ { 382, 48, 1024, BCRYPT_SHA384_ALGORITHM },
218 /* ALG_ID_SHA512 */ { 382, 64, 1024, BCRYPT_SHA512_ALGORITHM }
221 struct algorithm
223 struct object hdr;
224 enum alg_id id;
225 enum mode_id mode;
226 BOOL hmac;
229 NTSTATUS WINAPI BCryptGenRandom(BCRYPT_ALG_HANDLE handle, UCHAR *buffer, ULONG count, ULONG flags)
231 const DWORD supported_flags = BCRYPT_USE_SYSTEM_PREFERRED_RNG;
232 struct algorithm *algorithm = handle;
234 TRACE("%p, %p, %u, %08x - semi-stub\n", handle, buffer, count, flags);
236 if (!algorithm)
238 /* It's valid to call without an algorithm if BCRYPT_USE_SYSTEM_PREFERRED_RNG
239 * is set. In this case the preferred system RNG is used.
241 if (!(flags & BCRYPT_USE_SYSTEM_PREFERRED_RNG))
242 return STATUS_INVALID_HANDLE;
244 else if (algorithm->hdr.magic != MAGIC_ALG || algorithm->id != ALG_ID_RNG)
245 return STATUS_INVALID_HANDLE;
247 if (!buffer)
248 return STATUS_INVALID_PARAMETER;
250 if (flags & ~supported_flags)
251 FIXME("unsupported flags %08x\n", flags & ~supported_flags);
253 if (algorithm)
254 FIXME("ignoring selected algorithm\n");
256 /* When zero bytes are requested the function returns success too. */
257 if (!count)
258 return STATUS_SUCCESS;
260 if (algorithm || (flags & BCRYPT_USE_SYSTEM_PREFERRED_RNG))
262 if (RtlGenRandom(buffer, count))
263 return STATUS_SUCCESS;
266 FIXME("called with unsupported parameters, returning error\n");
267 return STATUS_NOT_IMPLEMENTED;
270 NTSTATUS WINAPI BCryptOpenAlgorithmProvider( BCRYPT_ALG_HANDLE *handle, LPCWSTR id, LPCWSTR implementation, DWORD flags )
272 const DWORD supported_flags = BCRYPT_ALG_HANDLE_HMAC_FLAG;
273 struct algorithm *alg;
274 enum alg_id alg_id;
276 TRACE( "%p, %s, %s, %08x\n", handle, wine_dbgstr_w(id), wine_dbgstr_w(implementation), flags );
278 if (!handle || !id) return STATUS_INVALID_PARAMETER;
279 if (flags & ~supported_flags)
281 FIXME( "unsupported flags %08x\n", flags & ~supported_flags);
282 return STATUS_NOT_IMPLEMENTED;
285 if (!strcmpW( id, BCRYPT_AES_ALGORITHM )) alg_id = ALG_ID_AES;
286 else if (!strcmpW( id, BCRYPT_MD2_ALGORITHM )) alg_id = ALG_ID_MD2;
287 else if (!strcmpW( id, BCRYPT_MD4_ALGORITHM )) alg_id = ALG_ID_MD4;
288 else if (!strcmpW( id, BCRYPT_MD5_ALGORITHM )) alg_id = ALG_ID_MD5;
289 else if (!strcmpW( id, BCRYPT_RNG_ALGORITHM )) alg_id = ALG_ID_RNG;
290 else if (!strcmpW( id, BCRYPT_SHA1_ALGORITHM )) alg_id = ALG_ID_SHA1;
291 else if (!strcmpW( id, BCRYPT_SHA256_ALGORITHM )) alg_id = ALG_ID_SHA256;
292 else if (!strcmpW( id, BCRYPT_SHA384_ALGORITHM )) alg_id = ALG_ID_SHA384;
293 else if (!strcmpW( id, BCRYPT_SHA512_ALGORITHM )) alg_id = ALG_ID_SHA512;
294 else
296 FIXME( "algorithm %s not supported\n", debugstr_w(id) );
297 return STATUS_NOT_IMPLEMENTED;
299 if (implementation && strcmpW( implementation, MS_PRIMITIVE_PROVIDER ))
301 FIXME( "implementation %s not supported\n", debugstr_w(implementation) );
302 return STATUS_NOT_IMPLEMENTED;
305 if (!(alg = heap_alloc( sizeof(*alg) ))) return STATUS_NO_MEMORY;
306 alg->hdr.magic = MAGIC_ALG;
307 alg->id = alg_id;
308 alg->mode = MODE_ID_CBC;
309 alg->hmac = flags & BCRYPT_ALG_HANDLE_HMAC_FLAG;
311 *handle = alg;
312 return STATUS_SUCCESS;
315 NTSTATUS WINAPI BCryptCloseAlgorithmProvider( BCRYPT_ALG_HANDLE handle, DWORD flags )
317 struct algorithm *alg = handle;
319 TRACE( "%p, %08x\n", handle, flags );
321 if (!alg || alg->hdr.magic != MAGIC_ALG) return STATUS_INVALID_HANDLE;
322 heap_free( alg );
323 return STATUS_SUCCESS;
326 NTSTATUS WINAPI BCryptGetFipsAlgorithmMode(BOOLEAN *enabled)
328 FIXME("%p - semi-stub\n", enabled);
330 if (!enabled)
331 return STATUS_INVALID_PARAMETER;
333 *enabled = FALSE;
334 return STATUS_SUCCESS;
337 struct hash_impl
339 union
341 MD2_CTX md2;
342 MD4_CTX md4;
343 MD5_CTX md5;
344 SHA_CTX sha1;
345 SHA256_CTX sha256;
346 SHA512_CTX sha512;
347 } u;
350 static NTSTATUS hash_init( struct hash_impl *hash, enum alg_id alg_id )
352 switch (alg_id)
354 case ALG_ID_MD2:
355 md2_init( &hash->u.md2 );
356 break;
358 case ALG_ID_MD4:
359 MD4Init( &hash->u.md4 );
360 break;
362 case ALG_ID_MD5:
363 MD5Init( &hash->u.md5 );
364 break;
366 case ALG_ID_SHA1:
367 A_SHAInit( &hash->u.sha1 );
368 break;
370 case ALG_ID_SHA256:
371 sha256_init( &hash->u.sha256 );
372 break;
374 case ALG_ID_SHA384:
375 sha384_init( &hash->u.sha512 );
376 break;
378 case ALG_ID_SHA512:
379 sha512_init( &hash->u.sha512 );
380 break;
382 default:
383 ERR( "unhandled id %u\n", alg_id );
384 return STATUS_NOT_IMPLEMENTED;
386 return STATUS_SUCCESS;
389 static NTSTATUS hash_update( struct hash_impl *hash, enum alg_id alg_id,
390 UCHAR *input, ULONG size )
392 switch (alg_id)
394 case ALG_ID_MD2:
395 md2_update( &hash->u.md2, input, size );
396 break;
398 case ALG_ID_MD4:
399 MD4Update( &hash->u.md4, input, size );
400 break;
402 case ALG_ID_MD5:
403 MD5Update( &hash->u.md5, input, size );
404 break;
406 case ALG_ID_SHA1:
407 A_SHAUpdate( &hash->u.sha1, input, size );
408 break;
410 case ALG_ID_SHA256:
411 sha256_update( &hash->u.sha256, input, size );
412 break;
414 case ALG_ID_SHA384:
415 sha384_update( &hash->u.sha512, input, size );
416 break;
418 case ALG_ID_SHA512:
419 sha512_update( &hash->u.sha512, input, size );
420 break;
422 default:
423 ERR( "unhandled id %u\n", alg_id );
424 return STATUS_NOT_IMPLEMENTED;
426 return STATUS_SUCCESS;
429 static NTSTATUS hash_finish( struct hash_impl *hash, enum alg_id alg_id,
430 UCHAR *output, ULONG size )
432 switch (alg_id)
434 case ALG_ID_MD2:
435 md2_finalize( &hash->u.md2, output );
436 break;
438 case ALG_ID_MD4:
439 MD4Final( &hash->u.md4 );
440 memcpy( output, hash->u.md4.digest, 16 );
441 break;
443 case ALG_ID_MD5:
444 MD5Final( &hash->u.md5 );
445 memcpy( output, hash->u.md5.digest, 16 );
446 break;
448 case ALG_ID_SHA1:
449 A_SHAFinal( &hash->u.sha1, (ULONG *)output );
450 break;
452 case ALG_ID_SHA256:
453 sha256_finalize( &hash->u.sha256, output );
454 break;
456 case ALG_ID_SHA384:
457 sha384_finalize( &hash->u.sha512, output );
458 break;
460 case ALG_ID_SHA512:
461 sha512_finalize( &hash->u.sha512, output );
462 break;
464 default:
465 ERR( "unhandled id %u\n", alg_id );
466 return STATUS_NOT_IMPLEMENTED;
468 return STATUS_SUCCESS;
471 struct hash
473 struct object hdr;
474 enum alg_id alg_id;
475 BOOL hmac;
476 struct hash_impl outer;
477 struct hash_impl inner;
480 #define BLOCK_LENGTH_AES 16
482 static NTSTATUS generic_alg_property( enum alg_id id, const WCHAR *prop, UCHAR *buf, ULONG size, ULONG *ret_size )
484 if (!strcmpW( prop, BCRYPT_OBJECT_LENGTH ))
486 if (!alg_props[id].object_length)
487 return STATUS_NOT_SUPPORTED;
488 *ret_size = sizeof(ULONG);
489 if (size < sizeof(ULONG))
490 return STATUS_BUFFER_TOO_SMALL;
491 if (buf)
492 *(ULONG *)buf = alg_props[id].object_length;
493 return STATUS_SUCCESS;
496 if (!strcmpW( prop, BCRYPT_HASH_LENGTH ))
498 if (!alg_props[id].hash_length)
499 return STATUS_NOT_SUPPORTED;
500 *ret_size = sizeof(ULONG);
501 if (size < sizeof(ULONG))
502 return STATUS_BUFFER_TOO_SMALL;
503 if(buf)
504 *(ULONG*)buf = alg_props[id].hash_length;
505 return STATUS_SUCCESS;
508 if (!strcmpW( prop, BCRYPT_ALGORITHM_NAME ))
510 *ret_size = (strlenW(alg_props[id].alg_name)+1)*sizeof(WCHAR);
511 if (size < *ret_size)
512 return STATUS_BUFFER_TOO_SMALL;
513 if(buf)
514 memcpy(buf, alg_props[id].alg_name, *ret_size);
515 return STATUS_SUCCESS;
518 return STATUS_NOT_IMPLEMENTED;
521 static NTSTATUS get_alg_property( const struct algorithm *alg, const WCHAR *prop, UCHAR *buf, ULONG size, ULONG *ret_size )
523 NTSTATUS status;
525 status = generic_alg_property( alg->id, prop, buf, size, ret_size );
526 if (status != STATUS_NOT_IMPLEMENTED)
527 return status;
529 switch (alg->id)
531 case ALG_ID_AES:
532 if (!strcmpW( prop, BCRYPT_BLOCK_LENGTH ))
534 *ret_size = sizeof(ULONG);
535 if (size < sizeof(ULONG))
536 return STATUS_BUFFER_TOO_SMALL;
537 if (buf)
538 *(ULONG *)buf = BLOCK_LENGTH_AES;
539 return STATUS_SUCCESS;
541 if (!strcmpW( prop, BCRYPT_CHAINING_MODE ))
543 const WCHAR *mode;
544 switch (alg->mode)
546 case MODE_ID_GCM: mode = BCRYPT_CHAIN_MODE_GCM; break;
547 case MODE_ID_CBC: mode = BCRYPT_CHAIN_MODE_CBC; break;
548 default: return STATUS_NOT_IMPLEMENTED;
551 *ret_size = 64;
552 if (size < *ret_size) return STATUS_BUFFER_TOO_SMALL;
553 memcpy( buf, mode, (strlenW(mode) + 1) * sizeof(WCHAR) );
554 return STATUS_SUCCESS;
556 if (!strcmpW( prop, BCRYPT_KEY_LENGTHS ))
558 BCRYPT_KEY_LENGTHS_STRUCT *key_lengths = (void *)buf;
559 *ret_size = sizeof(*key_lengths);
560 if (key_lengths && size < *ret_size) return STATUS_BUFFER_TOO_SMALL;
561 if (key_lengths)
563 key_lengths->dwMinLength = 128;
564 key_lengths->dwMaxLength = 256;
565 key_lengths->dwIncrement = 64;
567 return STATUS_SUCCESS;
569 if (!strcmpW( prop, BCRYPT_AUTH_TAG_LENGTH ))
571 BCRYPT_AUTH_TAG_LENGTHS_STRUCT *tag_length = (void *)buf;
572 if (alg->mode != MODE_ID_GCM) return STATUS_NOT_SUPPORTED;
573 *ret_size = sizeof(*tag_length);
574 if (tag_length && size < *ret_size) return STATUS_BUFFER_TOO_SMALL;
575 if (tag_length)
577 tag_length->dwMinLength = 12;
578 tag_length->dwMaxLength = 16;
579 tag_length->dwIncrement = 1;
581 return STATUS_SUCCESS;
583 break;
585 default:
586 break;
589 FIXME( "unsupported property %s\n", debugstr_w(prop) );
590 return STATUS_NOT_IMPLEMENTED;
593 static NTSTATUS set_alg_property( struct algorithm *alg, const WCHAR *prop, UCHAR *value, ULONG size, ULONG flags )
595 switch (alg->id)
597 case ALG_ID_AES:
598 if (!strcmpW( prop, BCRYPT_CHAINING_MODE ))
600 if (!strncmpW( (WCHAR *)value, BCRYPT_CHAIN_MODE_CBC, size ))
602 alg->mode = MODE_ID_CBC;
603 return STATUS_SUCCESS;
605 else if (!strncmpW( (WCHAR *)value, BCRYPT_CHAIN_MODE_GCM, size ))
607 alg->mode = MODE_ID_GCM;
608 return STATUS_SUCCESS;
610 else
612 FIXME( "unsupported mode %s\n", debugstr_wn( (WCHAR *)value, size ) );
613 return STATUS_NOT_IMPLEMENTED;
616 FIXME( "unsupported aes algorithm property %s\n", debugstr_w(prop) );
617 return STATUS_NOT_IMPLEMENTED;
619 default:
620 FIXME( "unsupported algorithm %u\n", alg->id );
621 return STATUS_NOT_IMPLEMENTED;
625 static NTSTATUS get_hash_property( const struct hash *hash, const WCHAR *prop, UCHAR *buf, ULONG size, ULONG *ret_size )
627 NTSTATUS status;
629 status = generic_alg_property( hash->alg_id, prop, buf, size, ret_size );
630 if (status == STATUS_NOT_IMPLEMENTED)
631 FIXME( "unsupported property %s\n", debugstr_w(prop) );
632 return status;
635 NTSTATUS WINAPI BCryptGetProperty( BCRYPT_HANDLE handle, LPCWSTR prop, UCHAR *buffer, ULONG count, ULONG *res, ULONG flags )
637 struct object *object = handle;
639 TRACE( "%p, %s, %p, %u, %p, %08x\n", handle, wine_dbgstr_w(prop), buffer, count, res, flags );
641 if (!object) return STATUS_INVALID_HANDLE;
642 if (!prop || !res) return STATUS_INVALID_PARAMETER;
644 switch (object->magic)
646 case MAGIC_ALG:
648 const struct algorithm *alg = (const struct algorithm *)object;
649 return get_alg_property( alg, prop, buffer, count, res );
651 case MAGIC_HASH:
653 const struct hash *hash = (const struct hash *)object;
654 return get_hash_property( hash, prop, buffer, count, res );
656 default:
657 WARN( "unknown magic %08x\n", object->magic );
658 return STATUS_INVALID_HANDLE;
662 NTSTATUS WINAPI BCryptSetProperty( BCRYPT_HANDLE handle, const WCHAR *prop, UCHAR *value, ULONG size, ULONG flags )
664 struct object *object = handle;
666 TRACE( "%p, %s, %p, %u, %08x\n", handle, debugstr_w(prop), value, size, flags );
668 if (!object) return STATUS_INVALID_HANDLE;
670 switch (object->magic)
672 case MAGIC_ALG:
674 struct algorithm *alg = (struct algorithm *)object;
675 return set_alg_property( alg, prop, value, size, flags );
677 case MAGIC_KEY:
679 FIXME( "keys not implemented yet\n" );
680 return STATUS_NOT_IMPLEMENTED;
682 default:
683 WARN( "unknown magic %08x\n", object->magic );
684 return STATUS_INVALID_HANDLE;
688 NTSTATUS WINAPI BCryptCreateHash( BCRYPT_ALG_HANDLE algorithm, BCRYPT_HASH_HANDLE *handle, UCHAR *object, ULONG objectlen,
689 UCHAR *secret, ULONG secretlen, ULONG flags )
691 struct algorithm *alg = algorithm;
692 UCHAR buffer[MAX_HASH_BLOCK_BITS / 8] = {0};
693 struct hash *hash;
694 int block_bytes;
695 NTSTATUS status;
696 int i;
698 TRACE( "%p, %p, %p, %u, %p, %u, %08x - stub\n", algorithm, handle, object, objectlen,
699 secret, secretlen, flags );
700 if (flags)
702 FIXME( "unimplemented flags %08x\n", flags );
703 return STATUS_NOT_IMPLEMENTED;
706 if (!alg || alg->hdr.magic != MAGIC_ALG) return STATUS_INVALID_HANDLE;
707 if (object) FIXME( "ignoring object buffer\n" );
709 if (!(hash = heap_alloc( sizeof(*hash) ))) return STATUS_NO_MEMORY;
710 hash->hdr.magic = MAGIC_HASH;
711 hash->alg_id = alg->id;
712 hash->hmac = alg->hmac;
714 /* initialize hash */
715 if ((status = hash_init( &hash->inner, hash->alg_id ))) goto end;
716 if (!hash->hmac) goto end;
718 /* initialize hmac */
719 if ((status = hash_init( &hash->outer, hash->alg_id ))) goto end;
720 block_bytes = alg_props[hash->alg_id].block_bits / 8;
721 if (secretlen > block_bytes)
723 struct hash_impl temp;
724 if ((status = hash_init( &temp, hash->alg_id ))) goto end;
725 if ((status = hash_update( &temp, hash->alg_id, secret, secretlen ))) goto end;
726 if ((status = hash_finish( &temp, hash->alg_id, buffer,
727 alg_props[hash->alg_id].hash_length ))) goto end;
729 else
731 memcpy( buffer, secret, secretlen );
733 for (i = 0; i < block_bytes; i++) buffer[i] ^= 0x5c;
734 if ((status = hash_update( &hash->outer, hash->alg_id, buffer, block_bytes ))) goto end;
735 for (i = 0; i < block_bytes; i++) buffer[i] ^= (0x5c ^ 0x36);
736 status = hash_update( &hash->inner, hash->alg_id, buffer, block_bytes );
738 end:
739 if (status != STATUS_SUCCESS)
741 heap_free( hash );
742 return status;
745 *handle = hash;
746 return STATUS_SUCCESS;
749 NTSTATUS WINAPI BCryptDuplicateHash( BCRYPT_HASH_HANDLE handle, BCRYPT_HASH_HANDLE *handle_copy,
750 UCHAR *object, ULONG objectlen, ULONG flags )
752 struct hash *hash_orig = handle;
753 struct hash *hash_copy;
755 TRACE( "%p, %p, %p, %u, %u\n", handle, handle_copy, object, objectlen, flags );
757 if (!hash_orig || hash_orig->hdr.magic != MAGIC_HASH) return STATUS_INVALID_HANDLE;
758 if (!handle_copy) return STATUS_INVALID_PARAMETER;
759 if (object) FIXME( "ignoring object buffer\n" );
761 if (!(hash_copy = heap_alloc( sizeof(*hash_copy) )))
762 return STATUS_NO_MEMORY;
764 memcpy( hash_copy, hash_orig, sizeof(*hash_orig) );
766 *handle_copy = hash_copy;
767 return STATUS_SUCCESS;
770 NTSTATUS WINAPI BCryptDestroyHash( BCRYPT_HASH_HANDLE handle )
772 struct hash *hash = handle;
774 TRACE( "%p\n", handle );
776 if (!hash || hash->hdr.magic != MAGIC_HASH) return STATUS_INVALID_HANDLE;
777 heap_free( hash );
778 return STATUS_SUCCESS;
781 NTSTATUS WINAPI BCryptHashData( BCRYPT_HASH_HANDLE handle, UCHAR *input, ULONG size, ULONG flags )
783 struct hash *hash = handle;
785 TRACE( "%p, %p, %u, %08x\n", handle, input, size, flags );
787 if (!hash || hash->hdr.magic != MAGIC_HASH) return STATUS_INVALID_HANDLE;
788 if (!input) return STATUS_SUCCESS;
790 return hash_update( &hash->inner, hash->alg_id, input, size );
793 NTSTATUS WINAPI BCryptFinishHash( BCRYPT_HASH_HANDLE handle, UCHAR *output, ULONG size, ULONG flags )
795 UCHAR buffer[MAX_HASH_OUTPUT_BYTES];
796 struct hash *hash = handle;
797 NTSTATUS status;
798 int hash_length;
800 TRACE( "%p, %p, %u, %08x\n", handle, output, size, flags );
802 if (!hash || hash->hdr.magic != MAGIC_HASH) return STATUS_INVALID_HANDLE;
803 if (!output) return STATUS_INVALID_PARAMETER;
805 if (!hash->hmac)
806 return hash_finish( &hash->inner, hash->alg_id, output, size );
808 hash_length = alg_props[hash->alg_id].hash_length;
809 if ((status = hash_finish( &hash->inner, hash->alg_id, buffer, hash_length ))) return status;
810 if ((status = hash_update( &hash->outer, hash->alg_id, buffer, hash_length ))) return status;
811 return hash_finish( &hash->outer, hash->alg_id, output, size );
814 NTSTATUS WINAPI BCryptHash( BCRYPT_ALG_HANDLE algorithm, UCHAR *secret, ULONG secretlen,
815 UCHAR *input, ULONG inputlen, UCHAR *output, ULONG outputlen )
817 NTSTATUS status;
818 BCRYPT_HASH_HANDLE handle;
820 TRACE( "%p, %p, %u, %p, %u, %p, %u\n", algorithm, secret, secretlen,
821 input, inputlen, output, outputlen );
823 status = BCryptCreateHash( algorithm, &handle, NULL, 0, secret, secretlen, 0);
824 if (status != STATUS_SUCCESS)
826 return status;
829 status = BCryptHashData( handle, input, inputlen, 0 );
830 if (status != STATUS_SUCCESS)
832 BCryptDestroyHash( handle );
833 return status;
836 status = BCryptFinishHash( handle, output, outputlen, 0 );
837 if (status != STATUS_SUCCESS)
839 BCryptDestroyHash( handle );
840 return status;
843 return BCryptDestroyHash( handle );
846 #if defined(HAVE_GNUTLS_CIPHER_INIT) && !defined(HAVE_COMMONCRYPTO_COMMONCRYPTOR_H)
847 struct key
849 struct object hdr;
850 enum alg_id alg_id;
851 ULONG block_size;
852 gnutls_cipher_hd_t handle;
853 UCHAR *secret;
854 ULONG secret_len;
856 #elif defined(HAVE_COMMONCRYPTO_COMMONCRYPTOR_H) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
857 struct key
859 struct object hdr;
860 enum alg_id alg_id;
861 ULONG block_size;
862 CCCryptorRef ref_encrypt;
863 CCCryptorRef ref_decrypt;
864 UCHAR *secret;
865 ULONG secret_len;
867 #else
868 struct key
870 struct object hdr;
871 ULONG block_size;
873 #endif
875 #if defined(HAVE_GNUTLS_CIPHER_INIT) || defined(HAVE_COMMONCRYPTO_COMMONCRYPTOR_H) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
876 static ULONG get_block_size( struct algorithm *alg )
878 ULONG ret = 0, size = sizeof(ret);
879 get_alg_property( alg, BCRYPT_BLOCK_LENGTH, (UCHAR *)&ret, sizeof(ret), &size );
880 return ret;
882 static NTSTATUS key_export( struct key *key, const WCHAR *type, UCHAR *output, ULONG output_len, ULONG *size )
884 if (!strcmpW( type, BCRYPT_KEY_DATA_BLOB ))
886 BCRYPT_KEY_DATA_BLOB_HEADER *header = (BCRYPT_KEY_DATA_BLOB_HEADER *)output;
887 ULONG req_size = sizeof(BCRYPT_KEY_DATA_BLOB_HEADER) + key->secret_len;
889 *size = req_size;
890 if (output_len < req_size) return STATUS_BUFFER_TOO_SMALL;
892 header->dwMagic = BCRYPT_KEY_DATA_BLOB_MAGIC;
893 header->dwVersion = BCRYPT_KEY_DATA_BLOB_VERSION1;
894 header->cbKeyData = key->secret_len;
895 memcpy( &header[1], key->secret, key->secret_len );
896 return STATUS_SUCCESS;
899 FIXME( "unsupported key type %s\n", debugstr_w(type) );
900 return STATUS_NOT_IMPLEMENTED;
902 #endif
904 #if defined(HAVE_GNUTLS_CIPHER_INIT) && !defined(HAVE_COMMONCRYPTO_COMMONCRYPTOR_H)
905 static NTSTATUS key_init( struct key *key, struct algorithm *alg, const UCHAR *secret, ULONG secret_len )
907 UCHAR *buffer;
909 if (!libgnutls_handle) return STATUS_INTERNAL_ERROR;
911 switch (alg->id)
913 case ALG_ID_AES:
914 break;
916 default:
917 FIXME( "algorithm %u not supported\n", alg->id );
918 return STATUS_NOT_SUPPORTED;
921 if (!(key->block_size = get_block_size( alg ))) return STATUS_INVALID_PARAMETER;
922 if (!(buffer = heap_alloc( secret_len ))) return STATUS_NO_MEMORY;
923 memcpy( buffer, secret, secret_len );
925 key->alg_id = alg->id;
926 key->handle = 0; /* initialized on first use */
927 key->secret = buffer;
928 key->secret_len = secret_len;
930 return STATUS_SUCCESS;
933 static gnutls_cipher_algorithm_t get_gnutls_cipher( const struct key *key )
935 switch (key->alg_id)
937 case ALG_ID_AES:
938 FIXME( "handle block size and chaining mode\n" );
939 return GNUTLS_CIPHER_AES_128_CBC;
941 default:
942 FIXME( "algorithm %u not supported\n", key->alg_id );
943 return GNUTLS_CIPHER_UNKNOWN;
947 static NTSTATUS key_set_params( struct key *key, UCHAR *iv, ULONG iv_len )
949 gnutls_cipher_algorithm_t cipher;
950 gnutls_datum_t secret, vector;
951 int ret;
953 if (key->handle)
955 pgnutls_cipher_deinit( key->handle );
956 key->handle = NULL;
959 if ((cipher = get_gnutls_cipher( key )) == GNUTLS_CIPHER_UNKNOWN)
960 return STATUS_NOT_SUPPORTED;
962 secret.data = key->secret;
963 secret.size = key->secret_len;
964 if (iv)
966 vector.data = iv;
967 vector.size = iv_len;
970 if ((ret = pgnutls_cipher_init( &key->handle, cipher, &secret, iv ? &vector : NULL )))
972 pgnutls_perror( ret );
973 return STATUS_INTERNAL_ERROR;
976 return STATUS_SUCCESS;
979 static NTSTATUS key_encrypt( struct key *key, const UCHAR *input, ULONG input_len, UCHAR *output,
980 ULONG output_len )
982 int ret;
984 if ((ret = pgnutls_cipher_encrypt2( key->handle, input, input_len, output, output_len )))
986 pgnutls_perror( ret );
987 return STATUS_INTERNAL_ERROR;
990 return STATUS_SUCCESS;
993 static NTSTATUS key_decrypt( struct key *key, const UCHAR *input, ULONG input_len, UCHAR *output,
994 ULONG output_len )
996 int ret;
998 if ((ret = pgnutls_cipher_decrypt2( key->handle, input, input_len, output, output_len )))
1000 pgnutls_perror( ret );
1001 return STATUS_INTERNAL_ERROR;
1004 return STATUS_SUCCESS;
1007 static NTSTATUS key_destroy( struct key *key )
1009 if (key->handle) pgnutls_cipher_deinit( key->handle );
1010 heap_free( key->secret );
1011 heap_free( key );
1012 return STATUS_SUCCESS;
1014 #elif defined(HAVE_COMMONCRYPTO_COMMONCRYPTOR_H) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
1015 static NTSTATUS key_init( struct key *key, struct algorithm *alg, const UCHAR *secret, ULONG secret_len )
1017 UCHAR *buffer;
1019 switch (alg->id)
1021 case ALG_ID_AES:
1022 break;
1024 default:
1025 FIXME( "algorithm %u not supported\n", alg->id );
1026 return STATUS_NOT_SUPPORTED;
1029 if (!(key->block_size = get_block_size( alg ))) return STATUS_INVALID_PARAMETER;
1030 if (!(buffer = heap_alloc( secret_len ))) return STATUS_NO_MEMORY;
1031 memcpy( buffer, secret, secret_len );
1033 key->alg_id = alg->id;
1034 key->ref_encrypt = NULL; /* initialized on first use */
1035 key->ref_decrypt = NULL;
1036 key->secret = buffer;
1037 key->secret_len = secret_len;
1039 return STATUS_SUCCESS;
1042 static NTSTATUS key_set_params( struct key *key, UCHAR *iv, ULONG iv_len )
1044 CCCryptorStatus status;
1046 if (key->ref_encrypt)
1048 CCCryptorRelease( key->ref_encrypt );
1049 key->ref_encrypt = NULL;
1051 if (key->ref_decrypt)
1053 CCCryptorRelease( key->ref_decrypt );
1054 key->ref_decrypt = NULL;
1057 if ((status = CCCryptorCreateWithMode( kCCEncrypt, kCCModeCBC, kCCAlgorithmAES128, ccNoPadding, iv,
1058 key->secret, key->secret_len, NULL, 0, 0, 0, &key->ref_encrypt )) != kCCSuccess)
1060 WARN( "CCCryptorCreateWithMode failed %d\n", status );
1061 return STATUS_INTERNAL_ERROR;
1063 if ((status = CCCryptorCreateWithMode( kCCDecrypt, kCCModeCBC, kCCAlgorithmAES128, ccNoPadding, iv,
1064 key->secret, key->secret_len, NULL, 0, 0, 0, &key->ref_decrypt )) != kCCSuccess)
1066 WARN( "CCCryptorCreateWithMode failed %d\n", status );
1067 CCCryptorRelease( key->ref_encrypt );
1068 key->ref_encrypt = NULL;
1069 return STATUS_INTERNAL_ERROR;
1072 return STATUS_SUCCESS;
1075 static NTSTATUS key_encrypt( struct key *key, const UCHAR *input, ULONG input_len, UCHAR *output,
1076 ULONG output_len )
1078 CCCryptorStatus status;
1080 if ((status = CCCryptorUpdate( key->ref_encrypt, input, input_len, output, output_len, NULL )) != kCCSuccess)
1082 WARN( "CCCryptorUpdate failed %d\n", status );
1083 return STATUS_INTERNAL_ERROR;
1086 return STATUS_SUCCESS;
1089 static NTSTATUS key_decrypt( struct key *key, const UCHAR *input, ULONG input_len, UCHAR *output,
1090 ULONG output_len )
1092 CCCryptorStatus status;
1094 if ((status = CCCryptorUpdate( key->ref_decrypt, input, input_len, output, output_len, NULL )) != kCCSuccess)
1096 WARN( "CCCryptorUpdate failed %d\n", status );
1097 return STATUS_INTERNAL_ERROR;
1100 return STATUS_SUCCESS;
1103 static NTSTATUS key_destroy( struct key *key )
1105 if (key->ref_encrypt) CCCryptorRelease( key->ref_encrypt );
1106 if (key->ref_decrypt) CCCryptorRelease( key->ref_decrypt );
1107 heap_free( key->secret );
1108 heap_free( key );
1109 return STATUS_SUCCESS;
1111 #else
1112 static NTSTATUS key_init( struct key *key, struct algorithm *alg, const UCHAR *secret, ULONG secret_len )
1114 ERR( "support for keys not available at build time\n" );
1115 return STATUS_NOT_IMPLEMENTED;
1118 static NTSTATUS key_set_params( struct key *key, UCHAR *iv, ULONG iv_len )
1120 ERR( "support for keys not available at build time\n" );
1121 return STATUS_NOT_IMPLEMENTED;
1124 static NTSTATUS key_encrypt( struct key *key, const UCHAR *input, ULONG input_len, UCHAR *output,
1125 ULONG output_len )
1127 ERR( "support for keys not available at build time\n" );
1128 return STATUS_NOT_IMPLEMENTED;
1131 static NTSTATUS key_decrypt( struct key *key, const UCHAR *input, ULONG input_len, UCHAR *output,
1132 ULONG output_len )
1134 ERR( "support for keys not available at build time\n" );
1135 return STATUS_NOT_IMPLEMENTED;
1138 static NTSTATUS key_destroy( struct key *key )
1140 ERR( "support for keys not available at build time\n" );
1141 return STATUS_NOT_IMPLEMENTED;
1144 static NTSTATUS key_export( struct key *key, const WCHAR *type, UCHAR *output, ULONG output_len, ULONG *size )
1146 ERR( "support for keys not available at build time\n" );
1147 return STATUS_NOT_IMPLEMENTED;
1149 #endif
1151 NTSTATUS WINAPI BCryptGenerateSymmetricKey( BCRYPT_ALG_HANDLE algorithm, BCRYPT_KEY_HANDLE *handle,
1152 UCHAR *object, ULONG object_len, UCHAR *secret, ULONG secret_len,
1153 ULONG flags )
1155 struct algorithm *alg = algorithm;
1156 struct key *key;
1157 NTSTATUS status;
1159 TRACE( "%p, %p, %p, %u, %p, %u, %08x\n", algorithm, handle, object, object_len, secret, secret_len, flags );
1161 if (!alg || alg->hdr.magic != MAGIC_ALG) return STATUS_INVALID_HANDLE;
1162 if (object) FIXME( "ignoring object buffer\n" );
1164 if (!(key = heap_alloc( sizeof(*key) ))) return STATUS_NO_MEMORY;
1165 key->hdr.magic = MAGIC_KEY;
1167 if ((status = key_init( key, alg, secret, secret_len )))
1169 heap_free( key );
1170 return status;
1173 *handle = key;
1174 return STATUS_SUCCESS;
1177 NTSTATUS WINAPI BCryptImportKey(BCRYPT_ALG_HANDLE algorithm, BCRYPT_KEY_HANDLE decrypt_key, LPCWSTR type,
1178 BCRYPT_KEY_HANDLE *key, PUCHAR object, ULONG object_len, PUCHAR input,
1179 ULONG input_len, ULONG flags)
1181 struct algorithm *alg = algorithm;
1183 TRACE("%p, %p, %s, %p, %p, %u, %p, %u, %u\n", algorithm, decrypt_key, debugstr_w(type), key, object,
1184 object_len, input, input_len, flags);
1186 if (!alg || alg->hdr.magic != MAGIC_ALG) return STATUS_INVALID_HANDLE;
1187 if (!key || !type || !input) return STATUS_INVALID_PARAMETER;
1189 if (decrypt_key)
1191 FIXME("Decrypting of key not yet supported\n");
1192 return STATUS_NO_MEMORY;
1195 if (!strcmpW(type, BCRYPT_KEY_DATA_BLOB))
1197 BCRYPT_KEY_DATA_BLOB_HEADER *key_header = (BCRYPT_KEY_DATA_BLOB_HEADER*)input;
1199 if (input_len < sizeof(BCRYPT_KEY_DATA_BLOB_HEADER))
1200 return STATUS_BUFFER_TOO_SMALL;
1202 if (key_header->dwMagic != BCRYPT_KEY_DATA_BLOB_MAGIC)
1203 return STATUS_INVALID_PARAMETER;
1205 if (key_header->dwVersion != BCRYPT_KEY_DATA_BLOB_VERSION1)
1207 FIXME("Unknown key data blob version: %d\n", key_header->dwVersion);
1208 return STATUS_INVALID_PARAMETER;
1211 if (key_header->cbKeyData + sizeof(BCRYPT_KEY_DATA_BLOB_HEADER) > input_len)
1212 return STATUS_INVALID_PARAMETER;
1214 return BCryptGenerateSymmetricKey(algorithm, key, object, object_len, (UCHAR*)&key_header[1], key_header->cbKeyData, 0);
1217 FIXME("Unsupported key type: %s\n", debugstr_w(type));
1218 return STATUS_INVALID_PARAMETER;
1221 NTSTATUS WINAPI BCryptExportKey(BCRYPT_KEY_HANDLE export_key, BCRYPT_KEY_HANDLE encrypt_key, LPCWSTR type,
1222 PUCHAR output, ULONG output_len, ULONG *size, ULONG flags)
1224 struct key *key = export_key;
1226 TRACE("%p, %p, %s, %p, %u, %p, %u\n", key, encrypt_key, debugstr_w(type), output, output_len, size, flags);
1228 if (!key || key->hdr.magic != MAGIC_KEY) return STATUS_INVALID_HANDLE;
1229 if (!output || !output_len || !size) return STATUS_INVALID_PARAMETER;
1231 if (encrypt_key)
1233 FIXME("Encryption of key not yet supported\n");
1234 return STATUS_NO_MEMORY;
1237 return key_export( key, type, output, output_len, size );
1240 NTSTATUS WINAPI BCryptDestroyKey( BCRYPT_KEY_HANDLE handle )
1242 struct key *key = handle;
1244 TRACE( "%p\n", handle );
1246 if (!key || key->hdr.magic != MAGIC_KEY) return STATUS_INVALID_HANDLE;
1247 return key_destroy( key );
1250 NTSTATUS WINAPI BCryptEncrypt( BCRYPT_KEY_HANDLE handle, UCHAR *input, ULONG input_len,
1251 void *padding, UCHAR *iv, ULONG iv_len, UCHAR *output,
1252 ULONG output_len, ULONG *ret_len, ULONG flags )
1254 struct key *key = handle;
1255 ULONG bytes_left = input_len;
1256 UCHAR *buf, *src, *dst;
1257 NTSTATUS status;
1259 TRACE( "%p, %p, %u, %p, %p, %u, %p, %u, %p, %08x\n", handle, input, input_len,
1260 padding, iv, iv_len, output, output_len, ret_len, flags );
1262 if (!key || key->hdr.magic != MAGIC_KEY) return STATUS_INVALID_HANDLE;
1263 if (padding)
1265 FIXME( "padding info not implemented\n" );
1266 return STATUS_NOT_IMPLEMENTED;
1268 if (flags & ~BCRYPT_BLOCK_PADDING)
1270 FIXME( "flags %08x not implemented\n", flags );
1271 return STATUS_NOT_IMPLEMENTED;
1274 if ((status = key_set_params( key, iv, iv_len ))) return status;
1276 *ret_len = input_len;
1278 if (flags & BCRYPT_BLOCK_PADDING)
1279 *ret_len = (input_len + key->block_size) & ~(key->block_size - 1);
1280 else if (input_len & (key->block_size - 1))
1281 return STATUS_INVALID_BUFFER_SIZE;
1283 if (!output) return STATUS_SUCCESS;
1284 if (output_len < *ret_len) return STATUS_BUFFER_TOO_SMALL;
1286 src = input;
1287 dst = output;
1288 while (bytes_left >= key->block_size)
1290 if ((status = key_encrypt( key, src, key->block_size, dst, key->block_size ))) return status;
1291 bytes_left -= key->block_size;
1292 src += key->block_size;
1293 dst += key->block_size;
1296 if (flags & BCRYPT_BLOCK_PADDING)
1298 if (!(buf = heap_alloc( key->block_size ))) return STATUS_NO_MEMORY;
1299 memcpy( buf, src, bytes_left );
1300 memset( buf + bytes_left, key->block_size - bytes_left, key->block_size - bytes_left );
1301 status = key_encrypt( key, buf, key->block_size, dst, key->block_size );
1302 heap_free( buf );
1305 return status;
1308 NTSTATUS WINAPI BCryptDecrypt( BCRYPT_KEY_HANDLE handle, UCHAR *input, ULONG input_len,
1309 void *padding, UCHAR *iv, ULONG iv_len, UCHAR *output,
1310 ULONG output_len, ULONG *ret_len, ULONG flags )
1312 struct key *key = handle;
1313 ULONG bytes_left = input_len;
1314 UCHAR *buf, *src, *dst;
1315 NTSTATUS status;
1317 TRACE( "%p, %p, %u, %p, %p, %u, %p, %u, %p, %08x\n", handle, input, input_len,
1318 padding, iv, iv_len, output, output_len, ret_len, flags );
1320 if (!key || key->hdr.magic != MAGIC_KEY) return STATUS_INVALID_HANDLE;
1321 if (padding)
1323 FIXME( "padding info not implemented\n" );
1324 return STATUS_NOT_IMPLEMENTED;
1326 if (flags & ~BCRYPT_BLOCK_PADDING)
1328 FIXME( "flags %08x not supported\n", flags );
1329 return STATUS_NOT_IMPLEMENTED;
1332 if ((status = key_set_params( key, iv, iv_len ))) return status;
1334 *ret_len = input_len;
1336 if (input_len & (key->block_size - 1)) return STATUS_INVALID_BUFFER_SIZE;
1337 if (!output) return STATUS_SUCCESS;
1338 if (flags & BCRYPT_BLOCK_PADDING)
1340 if (output_len + key->block_size < *ret_len) return STATUS_BUFFER_TOO_SMALL;
1341 if (input_len < key->block_size) return STATUS_BUFFER_TOO_SMALL;
1342 bytes_left -= key->block_size;
1344 else if (output_len < *ret_len)
1345 return STATUS_BUFFER_TOO_SMALL;
1347 src = input;
1348 dst = output;
1349 while (bytes_left >= key->block_size)
1351 if ((status = key_decrypt( key, src, key->block_size, dst, key->block_size ))) return status;
1352 bytes_left -= key->block_size;
1353 src += key->block_size;
1354 dst += key->block_size;
1357 if (flags & BCRYPT_BLOCK_PADDING)
1359 if (!(buf = heap_alloc( key->block_size ))) return STATUS_NO_MEMORY;
1360 status = key_decrypt( key, src, key->block_size, buf, key->block_size );
1361 if (!status && buf[ key->block_size - 1 ] <= key->block_size)
1363 *ret_len -= buf[ key->block_size - 1 ];
1364 if (output_len < *ret_len) status = STATUS_BUFFER_TOO_SMALL;
1365 else memcpy( dst, buf, key->block_size - buf[ key->block_size - 1 ] );
1367 else
1368 status = STATUS_UNSUCCESSFUL; /* FIXME: invalid padding */
1369 heap_free( buf );
1372 return status;
1375 BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
1377 switch (reason)
1379 case DLL_PROCESS_ATTACH:
1380 instance = hinst;
1381 DisableThreadLibraryCalls( hinst );
1382 #if defined(HAVE_GNUTLS_CIPHER_INIT) && !defined(HAVE_COMMONCRYPTO_COMMONCRYPTOR_H)
1383 gnutls_initialize();
1384 #endif
1385 break;
1387 case DLL_PROCESS_DETACH:
1388 if (reserved) break;
1389 #if defined(HAVE_GNUTLS_CIPHER_INIT) && !defined(HAVE_COMMONCRYPTO_COMMONCRYPTOR_H)
1390 gnutls_uninitialize();
1391 #endif
1392 break;
1394 return TRUE;