bcrypt: Implement BCryptEncrypt for AES GCM mode.
[wine.git] / dlls / bcrypt / bcrypt_main.c
blob96695532b5b74157ec136e7e1b41ceb8e2d06545
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 #if GNUTLS_VERSION_MAJOR < 3
67 #define GNUTLS_CIPHER_AES_192_CBC 92
68 #define GNUTLS_CIPHER_AES_128_GCM 93
69 #define GNUTLS_CIPHER_AES_256_GCM 94
70 #endif
72 static void gnutls_log( int level, const char *msg )
74 TRACE( "<%d> %s", level, msg );
77 static BOOL gnutls_initialize(void)
79 int ret;
81 if (!(libgnutls_handle = wine_dlopen( SONAME_LIBGNUTLS, RTLD_NOW, NULL, 0 )))
83 ERR_(winediag)( "failed to load libgnutls, no support for encryption\n" );
84 return FALSE;
87 #define LOAD_FUNCPTR(f) \
88 if (!(p##f = wine_dlsym( libgnutls_handle, #f, NULL, 0 ))) \
89 { \
90 ERR( "failed to load %s\n", #f ); \
91 goto fail; \
94 LOAD_FUNCPTR(gnutls_cipher_decrypt2)
95 LOAD_FUNCPTR(gnutls_cipher_deinit)
96 LOAD_FUNCPTR(gnutls_cipher_encrypt2)
97 LOAD_FUNCPTR(gnutls_cipher_init)
98 LOAD_FUNCPTR(gnutls_global_deinit)
99 LOAD_FUNCPTR(gnutls_global_init)
100 LOAD_FUNCPTR(gnutls_global_set_log_function)
101 LOAD_FUNCPTR(gnutls_global_set_log_level)
102 LOAD_FUNCPTR(gnutls_perror)
103 #undef LOAD_FUNCPTR
105 if ((ret = pgnutls_global_init()) != GNUTLS_E_SUCCESS)
107 pgnutls_perror( ret );
108 goto fail;
111 if (TRACE_ON( bcrypt ))
113 pgnutls_global_set_log_level( 4 );
114 pgnutls_global_set_log_function( gnutls_log );
117 return TRUE;
119 fail:
120 wine_dlclose( libgnutls_handle, NULL, 0 );
121 libgnutls_handle = NULL;
122 return FALSE;
125 static void gnutls_uninitialize(void)
127 pgnutls_global_deinit();
128 wine_dlclose( libgnutls_handle, NULL, 0 );
129 libgnutls_handle = NULL;
131 #endif /* HAVE_GNUTLS_CIPHER_INIT && !HAVE_COMMONCRYPTO_COMMONCRYPTOR_H */
133 NTSTATUS WINAPI BCryptAddContextFunction(ULONG table, LPCWSTR context, ULONG iface, LPCWSTR function, ULONG pos)
135 FIXME("%08x, %s, %08x, %s, %u: stub\n", table, debugstr_w(context), iface, debugstr_w(function), pos);
136 return STATUS_SUCCESS;
139 NTSTATUS WINAPI BCryptAddContextFunctionProvider(ULONG table, LPCWSTR context, ULONG iface, LPCWSTR function, LPCWSTR provider, ULONG pos)
141 FIXME("%08x, %s, %08x, %s, %s, %u: stub\n", table, debugstr_w(context), iface, debugstr_w(function), debugstr_w(provider), pos);
142 return STATUS_SUCCESS;
145 NTSTATUS WINAPI BCryptRemoveContextFunction(ULONG table, LPCWSTR context, ULONG iface, LPCWSTR function)
147 FIXME("%08x, %s, %08x, %s: stub\n", table, debugstr_w(context), iface, debugstr_w(function));
148 return STATUS_NOT_IMPLEMENTED;
151 NTSTATUS WINAPI BCryptRemoveContextFunctionProvider(ULONG table, LPCWSTR context, ULONG iface, LPCWSTR function, LPCWSTR provider)
153 FIXME("%08x, %s, %08x, %s, %s: stub\n", table, debugstr_w(context), iface, debugstr_w(function), debugstr_w(provider));
154 return STATUS_NOT_IMPLEMENTED;
157 NTSTATUS WINAPI BCryptRegisterProvider(LPCWSTR provider, ULONG flags, PCRYPT_PROVIDER_REG reg)
159 FIXME("%s, %08x, %p: stub\n", debugstr_w(provider), flags, reg);
160 return STATUS_SUCCESS;
163 NTSTATUS WINAPI BCryptUnregisterProvider(LPCWSTR provider)
165 FIXME("%s: stub\n", debugstr_w(provider));
166 return STATUS_NOT_IMPLEMENTED;
169 NTSTATUS WINAPI BCryptEnumAlgorithms(ULONG dwAlgOperations, ULONG *pAlgCount,
170 BCRYPT_ALGORITHM_IDENTIFIER **ppAlgList, ULONG dwFlags)
172 FIXME("%08x, %p, %p, %08x - stub\n", dwAlgOperations, pAlgCount, ppAlgList, dwFlags);
174 *ppAlgList=NULL;
175 *pAlgCount=0;
177 return STATUS_NOT_IMPLEMENTED;
180 #define MAGIC_ALG (('A' << 24) | ('L' << 16) | ('G' << 8) | '0')
181 #define MAGIC_HASH (('H' << 24) | ('A' << 16) | ('S' << 8) | 'H')
182 #define MAGIC_KEY (('K' << 24) | ('E' << 16) | ('Y' << 8) | '0')
183 struct object
185 ULONG magic;
188 enum alg_id
190 ALG_ID_AES,
191 ALG_ID_MD2,
192 ALG_ID_MD4,
193 ALG_ID_MD5,
194 ALG_ID_RNG,
195 ALG_ID_SHA1,
196 ALG_ID_SHA256,
197 ALG_ID_SHA384,
198 ALG_ID_SHA512
201 enum mode_id
203 MODE_ID_CBC,
204 MODE_ID_GCM
207 #define MAX_HASH_OUTPUT_BYTES 64
208 #define MAX_HASH_BLOCK_BITS 1024
210 static const struct {
211 ULONG object_length;
212 ULONG hash_length;
213 ULONG block_bits;
214 const WCHAR *alg_name;
215 } alg_props[] = {
216 /* ALG_ID_AES */ { 654, 0, 0, BCRYPT_AES_ALGORITHM },
217 /* ALG_ID_MD2 */ { 270, 16, 128, BCRYPT_MD2_ALGORITHM },
218 /* ALG_ID_MD4 */ { 270, 16, 512, BCRYPT_MD4_ALGORITHM },
219 /* ALG_ID_MD5 */ { 274, 16, 512, BCRYPT_MD5_ALGORITHM },
220 /* ALG_ID_RNG */ { 0, 0, 0, BCRYPT_RNG_ALGORITHM },
221 /* ALG_ID_SHA1 */ { 278, 20, 512, BCRYPT_SHA1_ALGORITHM },
222 /* ALG_ID_SHA256 */ { 286, 32, 512, BCRYPT_SHA256_ALGORITHM },
223 /* ALG_ID_SHA384 */ { 382, 48, 1024, BCRYPT_SHA384_ALGORITHM },
224 /* ALG_ID_SHA512 */ { 382, 64, 1024, BCRYPT_SHA512_ALGORITHM }
227 struct algorithm
229 struct object hdr;
230 enum alg_id id;
231 enum mode_id mode;
232 BOOL hmac;
235 NTSTATUS WINAPI BCryptGenRandom(BCRYPT_ALG_HANDLE handle, UCHAR *buffer, ULONG count, ULONG flags)
237 const DWORD supported_flags = BCRYPT_USE_SYSTEM_PREFERRED_RNG;
238 struct algorithm *algorithm = handle;
240 TRACE("%p, %p, %u, %08x - semi-stub\n", handle, buffer, count, flags);
242 if (!algorithm)
244 /* It's valid to call without an algorithm if BCRYPT_USE_SYSTEM_PREFERRED_RNG
245 * is set. In this case the preferred system RNG is used.
247 if (!(flags & BCRYPT_USE_SYSTEM_PREFERRED_RNG))
248 return STATUS_INVALID_HANDLE;
250 else if (algorithm->hdr.magic != MAGIC_ALG || algorithm->id != ALG_ID_RNG)
251 return STATUS_INVALID_HANDLE;
253 if (!buffer)
254 return STATUS_INVALID_PARAMETER;
256 if (flags & ~supported_flags)
257 FIXME("unsupported flags %08x\n", flags & ~supported_flags);
259 if (algorithm)
260 FIXME("ignoring selected algorithm\n");
262 /* When zero bytes are requested the function returns success too. */
263 if (!count)
264 return STATUS_SUCCESS;
266 if (algorithm || (flags & BCRYPT_USE_SYSTEM_PREFERRED_RNG))
268 if (RtlGenRandom(buffer, count))
269 return STATUS_SUCCESS;
272 FIXME("called with unsupported parameters, returning error\n");
273 return STATUS_NOT_IMPLEMENTED;
276 NTSTATUS WINAPI BCryptOpenAlgorithmProvider( BCRYPT_ALG_HANDLE *handle, LPCWSTR id, LPCWSTR implementation, DWORD flags )
278 const DWORD supported_flags = BCRYPT_ALG_HANDLE_HMAC_FLAG;
279 struct algorithm *alg;
280 enum alg_id alg_id;
282 TRACE( "%p, %s, %s, %08x\n", handle, wine_dbgstr_w(id), wine_dbgstr_w(implementation), flags );
284 if (!handle || !id) return STATUS_INVALID_PARAMETER;
285 if (flags & ~supported_flags)
287 FIXME( "unsupported flags %08x\n", flags & ~supported_flags);
288 return STATUS_NOT_IMPLEMENTED;
291 if (!strcmpW( id, BCRYPT_AES_ALGORITHM )) alg_id = ALG_ID_AES;
292 else if (!strcmpW( id, BCRYPT_MD2_ALGORITHM )) alg_id = ALG_ID_MD2;
293 else if (!strcmpW( id, BCRYPT_MD4_ALGORITHM )) alg_id = ALG_ID_MD4;
294 else if (!strcmpW( id, BCRYPT_MD5_ALGORITHM )) alg_id = ALG_ID_MD5;
295 else if (!strcmpW( id, BCRYPT_RNG_ALGORITHM )) alg_id = ALG_ID_RNG;
296 else if (!strcmpW( id, BCRYPT_SHA1_ALGORITHM )) alg_id = ALG_ID_SHA1;
297 else if (!strcmpW( id, BCRYPT_SHA256_ALGORITHM )) alg_id = ALG_ID_SHA256;
298 else if (!strcmpW( id, BCRYPT_SHA384_ALGORITHM )) alg_id = ALG_ID_SHA384;
299 else if (!strcmpW( id, BCRYPT_SHA512_ALGORITHM )) alg_id = ALG_ID_SHA512;
300 else
302 FIXME( "algorithm %s not supported\n", debugstr_w(id) );
303 return STATUS_NOT_IMPLEMENTED;
305 if (implementation && strcmpW( implementation, MS_PRIMITIVE_PROVIDER ))
307 FIXME( "implementation %s not supported\n", debugstr_w(implementation) );
308 return STATUS_NOT_IMPLEMENTED;
311 if (!(alg = heap_alloc( sizeof(*alg) ))) return STATUS_NO_MEMORY;
312 alg->hdr.magic = MAGIC_ALG;
313 alg->id = alg_id;
314 alg->mode = MODE_ID_CBC;
315 alg->hmac = flags & BCRYPT_ALG_HANDLE_HMAC_FLAG;
317 *handle = alg;
318 return STATUS_SUCCESS;
321 NTSTATUS WINAPI BCryptCloseAlgorithmProvider( BCRYPT_ALG_HANDLE handle, DWORD flags )
323 struct algorithm *alg = handle;
325 TRACE( "%p, %08x\n", handle, flags );
327 if (!alg || alg->hdr.magic != MAGIC_ALG) return STATUS_INVALID_HANDLE;
328 heap_free( alg );
329 return STATUS_SUCCESS;
332 NTSTATUS WINAPI BCryptGetFipsAlgorithmMode(BOOLEAN *enabled)
334 FIXME("%p - semi-stub\n", enabled);
336 if (!enabled)
337 return STATUS_INVALID_PARAMETER;
339 *enabled = FALSE;
340 return STATUS_SUCCESS;
343 struct hash_impl
345 union
347 MD2_CTX md2;
348 MD4_CTX md4;
349 MD5_CTX md5;
350 SHA_CTX sha1;
351 SHA256_CTX sha256;
352 SHA512_CTX sha512;
353 } u;
356 static NTSTATUS hash_init( struct hash_impl *hash, enum alg_id alg_id )
358 switch (alg_id)
360 case ALG_ID_MD2:
361 md2_init( &hash->u.md2 );
362 break;
364 case ALG_ID_MD4:
365 MD4Init( &hash->u.md4 );
366 break;
368 case ALG_ID_MD5:
369 MD5Init( &hash->u.md5 );
370 break;
372 case ALG_ID_SHA1:
373 A_SHAInit( &hash->u.sha1 );
374 break;
376 case ALG_ID_SHA256:
377 sha256_init( &hash->u.sha256 );
378 break;
380 case ALG_ID_SHA384:
381 sha384_init( &hash->u.sha512 );
382 break;
384 case ALG_ID_SHA512:
385 sha512_init( &hash->u.sha512 );
386 break;
388 default:
389 ERR( "unhandled id %u\n", alg_id );
390 return STATUS_NOT_IMPLEMENTED;
392 return STATUS_SUCCESS;
395 static NTSTATUS hash_update( struct hash_impl *hash, enum alg_id alg_id,
396 UCHAR *input, ULONG size )
398 switch (alg_id)
400 case ALG_ID_MD2:
401 md2_update( &hash->u.md2, input, size );
402 break;
404 case ALG_ID_MD4:
405 MD4Update( &hash->u.md4, input, size );
406 break;
408 case ALG_ID_MD5:
409 MD5Update( &hash->u.md5, input, size );
410 break;
412 case ALG_ID_SHA1:
413 A_SHAUpdate( &hash->u.sha1, input, size );
414 break;
416 case ALG_ID_SHA256:
417 sha256_update( &hash->u.sha256, input, size );
418 break;
420 case ALG_ID_SHA384:
421 sha384_update( &hash->u.sha512, input, size );
422 break;
424 case ALG_ID_SHA512:
425 sha512_update( &hash->u.sha512, input, size );
426 break;
428 default:
429 ERR( "unhandled id %u\n", alg_id );
430 return STATUS_NOT_IMPLEMENTED;
432 return STATUS_SUCCESS;
435 static NTSTATUS hash_finish( struct hash_impl *hash, enum alg_id alg_id,
436 UCHAR *output, ULONG size )
438 switch (alg_id)
440 case ALG_ID_MD2:
441 md2_finalize( &hash->u.md2, output );
442 break;
444 case ALG_ID_MD4:
445 MD4Final( &hash->u.md4 );
446 memcpy( output, hash->u.md4.digest, 16 );
447 break;
449 case ALG_ID_MD5:
450 MD5Final( &hash->u.md5 );
451 memcpy( output, hash->u.md5.digest, 16 );
452 break;
454 case ALG_ID_SHA1:
455 A_SHAFinal( &hash->u.sha1, (ULONG *)output );
456 break;
458 case ALG_ID_SHA256:
459 sha256_finalize( &hash->u.sha256, output );
460 break;
462 case ALG_ID_SHA384:
463 sha384_finalize( &hash->u.sha512, output );
464 break;
466 case ALG_ID_SHA512:
467 sha512_finalize( &hash->u.sha512, output );
468 break;
470 default:
471 ERR( "unhandled id %u\n", alg_id );
472 return STATUS_NOT_IMPLEMENTED;
474 return STATUS_SUCCESS;
477 struct hash
479 struct object hdr;
480 enum alg_id alg_id;
481 BOOL hmac;
482 struct hash_impl outer;
483 struct hash_impl inner;
486 #define BLOCK_LENGTH_AES 16
488 static NTSTATUS generic_alg_property( enum alg_id id, const WCHAR *prop, UCHAR *buf, ULONG size, ULONG *ret_size )
490 if (!strcmpW( prop, BCRYPT_OBJECT_LENGTH ))
492 if (!alg_props[id].object_length)
493 return STATUS_NOT_SUPPORTED;
494 *ret_size = sizeof(ULONG);
495 if (size < sizeof(ULONG))
496 return STATUS_BUFFER_TOO_SMALL;
497 if (buf)
498 *(ULONG *)buf = alg_props[id].object_length;
499 return STATUS_SUCCESS;
502 if (!strcmpW( prop, BCRYPT_HASH_LENGTH ))
504 if (!alg_props[id].hash_length)
505 return STATUS_NOT_SUPPORTED;
506 *ret_size = sizeof(ULONG);
507 if (size < sizeof(ULONG))
508 return STATUS_BUFFER_TOO_SMALL;
509 if(buf)
510 *(ULONG*)buf = alg_props[id].hash_length;
511 return STATUS_SUCCESS;
514 if (!strcmpW( prop, BCRYPT_ALGORITHM_NAME ))
516 *ret_size = (strlenW(alg_props[id].alg_name)+1)*sizeof(WCHAR);
517 if (size < *ret_size)
518 return STATUS_BUFFER_TOO_SMALL;
519 if(buf)
520 memcpy(buf, alg_props[id].alg_name, *ret_size);
521 return STATUS_SUCCESS;
524 return STATUS_NOT_IMPLEMENTED;
527 static NTSTATUS get_alg_property( const struct algorithm *alg, const WCHAR *prop, UCHAR *buf, ULONG size, ULONG *ret_size )
529 NTSTATUS status;
531 status = generic_alg_property( alg->id, prop, buf, size, ret_size );
532 if (status != STATUS_NOT_IMPLEMENTED)
533 return status;
535 switch (alg->id)
537 case ALG_ID_AES:
538 if (!strcmpW( prop, BCRYPT_BLOCK_LENGTH ))
540 *ret_size = sizeof(ULONG);
541 if (size < sizeof(ULONG))
542 return STATUS_BUFFER_TOO_SMALL;
543 if (buf)
544 *(ULONG *)buf = BLOCK_LENGTH_AES;
545 return STATUS_SUCCESS;
547 if (!strcmpW( prop, BCRYPT_CHAINING_MODE ))
549 const WCHAR *mode;
550 switch (alg->mode)
552 case MODE_ID_GCM: mode = BCRYPT_CHAIN_MODE_GCM; break;
553 case MODE_ID_CBC: mode = BCRYPT_CHAIN_MODE_CBC; break;
554 default: return STATUS_NOT_IMPLEMENTED;
557 *ret_size = 64;
558 if (size < *ret_size) return STATUS_BUFFER_TOO_SMALL;
559 memcpy( buf, mode, (strlenW(mode) + 1) * sizeof(WCHAR) );
560 return STATUS_SUCCESS;
562 if (!strcmpW( prop, BCRYPT_KEY_LENGTHS ))
564 BCRYPT_KEY_LENGTHS_STRUCT *key_lengths = (void *)buf;
565 *ret_size = sizeof(*key_lengths);
566 if (key_lengths && size < *ret_size) return STATUS_BUFFER_TOO_SMALL;
567 if (key_lengths)
569 key_lengths->dwMinLength = 128;
570 key_lengths->dwMaxLength = 256;
571 key_lengths->dwIncrement = 64;
573 return STATUS_SUCCESS;
575 if (!strcmpW( prop, BCRYPT_AUTH_TAG_LENGTH ))
577 BCRYPT_AUTH_TAG_LENGTHS_STRUCT *tag_length = (void *)buf;
578 if (alg->mode != MODE_ID_GCM) return STATUS_NOT_SUPPORTED;
579 *ret_size = sizeof(*tag_length);
580 if (tag_length && size < *ret_size) return STATUS_BUFFER_TOO_SMALL;
581 if (tag_length)
583 tag_length->dwMinLength = 12;
584 tag_length->dwMaxLength = 16;
585 tag_length->dwIncrement = 1;
587 return STATUS_SUCCESS;
589 break;
591 default:
592 break;
595 FIXME( "unsupported property %s\n", debugstr_w(prop) );
596 return STATUS_NOT_IMPLEMENTED;
599 static NTSTATUS set_alg_property( struct algorithm *alg, const WCHAR *prop, UCHAR *value, ULONG size, ULONG flags )
601 switch (alg->id)
603 case ALG_ID_AES:
604 if (!strcmpW( prop, BCRYPT_CHAINING_MODE ))
606 if (!strncmpW( (WCHAR *)value, BCRYPT_CHAIN_MODE_CBC, size ))
608 alg->mode = MODE_ID_CBC;
609 return STATUS_SUCCESS;
611 else if (!strncmpW( (WCHAR *)value, BCRYPT_CHAIN_MODE_GCM, size ))
613 alg->mode = MODE_ID_GCM;
614 return STATUS_SUCCESS;
616 else
618 FIXME( "unsupported mode %s\n", debugstr_wn( (WCHAR *)value, size ) );
619 return STATUS_NOT_IMPLEMENTED;
622 FIXME( "unsupported aes algorithm property %s\n", debugstr_w(prop) );
623 return STATUS_NOT_IMPLEMENTED;
625 default:
626 FIXME( "unsupported algorithm %u\n", alg->id );
627 return STATUS_NOT_IMPLEMENTED;
631 static NTSTATUS get_hash_property( const struct hash *hash, const WCHAR *prop, UCHAR *buf, ULONG size, ULONG *ret_size )
633 NTSTATUS status;
635 status = generic_alg_property( hash->alg_id, prop, buf, size, ret_size );
636 if (status == STATUS_NOT_IMPLEMENTED)
637 FIXME( "unsupported property %s\n", debugstr_w(prop) );
638 return status;
641 NTSTATUS WINAPI BCryptGetProperty( BCRYPT_HANDLE handle, LPCWSTR prop, UCHAR *buffer, ULONG count, ULONG *res, ULONG flags )
643 struct object *object = handle;
645 TRACE( "%p, %s, %p, %u, %p, %08x\n", handle, wine_dbgstr_w(prop), buffer, count, res, flags );
647 if (!object) return STATUS_INVALID_HANDLE;
648 if (!prop || !res) return STATUS_INVALID_PARAMETER;
650 switch (object->magic)
652 case MAGIC_ALG:
654 const struct algorithm *alg = (const struct algorithm *)object;
655 return get_alg_property( alg, prop, buffer, count, res );
657 case MAGIC_HASH:
659 const struct hash *hash = (const struct hash *)object;
660 return get_hash_property( hash, prop, buffer, count, res );
662 default:
663 WARN( "unknown magic %08x\n", object->magic );
664 return STATUS_INVALID_HANDLE;
668 NTSTATUS WINAPI BCryptSetProperty( BCRYPT_HANDLE handle, const WCHAR *prop, UCHAR *value, ULONG size, ULONG flags )
670 struct object *object = handle;
672 TRACE( "%p, %s, %p, %u, %08x\n", handle, debugstr_w(prop), value, size, flags );
674 if (!object) return STATUS_INVALID_HANDLE;
676 switch (object->magic)
678 case MAGIC_ALG:
680 struct algorithm *alg = (struct algorithm *)object;
681 return set_alg_property( alg, prop, value, size, flags );
683 case MAGIC_KEY:
685 FIXME( "keys not implemented yet\n" );
686 return STATUS_NOT_IMPLEMENTED;
688 default:
689 WARN( "unknown magic %08x\n", object->magic );
690 return STATUS_INVALID_HANDLE;
694 NTSTATUS WINAPI BCryptCreateHash( BCRYPT_ALG_HANDLE algorithm, BCRYPT_HASH_HANDLE *handle, UCHAR *object, ULONG objectlen,
695 UCHAR *secret, ULONG secretlen, ULONG flags )
697 struct algorithm *alg = algorithm;
698 UCHAR buffer[MAX_HASH_BLOCK_BITS / 8] = {0};
699 struct hash *hash;
700 int block_bytes;
701 NTSTATUS status;
702 int i;
704 TRACE( "%p, %p, %p, %u, %p, %u, %08x - stub\n", algorithm, handle, object, objectlen,
705 secret, secretlen, flags );
706 if (flags)
708 FIXME( "unimplemented flags %08x\n", flags );
709 return STATUS_NOT_IMPLEMENTED;
712 if (!alg || alg->hdr.magic != MAGIC_ALG) return STATUS_INVALID_HANDLE;
713 if (object) FIXME( "ignoring object buffer\n" );
715 if (!(hash = heap_alloc( sizeof(*hash) ))) return STATUS_NO_MEMORY;
716 hash->hdr.magic = MAGIC_HASH;
717 hash->alg_id = alg->id;
718 hash->hmac = alg->hmac;
720 /* initialize hash */
721 if ((status = hash_init( &hash->inner, hash->alg_id ))) goto end;
722 if (!hash->hmac) goto end;
724 /* initialize hmac */
725 if ((status = hash_init( &hash->outer, hash->alg_id ))) goto end;
726 block_bytes = alg_props[hash->alg_id].block_bits / 8;
727 if (secretlen > block_bytes)
729 struct hash_impl temp;
730 if ((status = hash_init( &temp, hash->alg_id ))) goto end;
731 if ((status = hash_update( &temp, hash->alg_id, secret, secretlen ))) goto end;
732 if ((status = hash_finish( &temp, hash->alg_id, buffer,
733 alg_props[hash->alg_id].hash_length ))) goto end;
735 else
737 memcpy( buffer, secret, secretlen );
739 for (i = 0; i < block_bytes; i++) buffer[i] ^= 0x5c;
740 if ((status = hash_update( &hash->outer, hash->alg_id, buffer, block_bytes ))) goto end;
741 for (i = 0; i < block_bytes; i++) buffer[i] ^= (0x5c ^ 0x36);
742 status = hash_update( &hash->inner, hash->alg_id, buffer, block_bytes );
744 end:
745 if (status != STATUS_SUCCESS)
747 heap_free( hash );
748 return status;
751 *handle = hash;
752 return STATUS_SUCCESS;
755 NTSTATUS WINAPI BCryptDuplicateHash( BCRYPT_HASH_HANDLE handle, BCRYPT_HASH_HANDLE *handle_copy,
756 UCHAR *object, ULONG objectlen, ULONG flags )
758 struct hash *hash_orig = handle;
759 struct hash *hash_copy;
761 TRACE( "%p, %p, %p, %u, %u\n", handle, handle_copy, object, objectlen, flags );
763 if (!hash_orig || hash_orig->hdr.magic != MAGIC_HASH) return STATUS_INVALID_HANDLE;
764 if (!handle_copy) return STATUS_INVALID_PARAMETER;
765 if (object) FIXME( "ignoring object buffer\n" );
767 if (!(hash_copy = heap_alloc( sizeof(*hash_copy) )))
768 return STATUS_NO_MEMORY;
770 memcpy( hash_copy, hash_orig, sizeof(*hash_orig) );
772 *handle_copy = hash_copy;
773 return STATUS_SUCCESS;
776 NTSTATUS WINAPI BCryptDestroyHash( BCRYPT_HASH_HANDLE handle )
778 struct hash *hash = handle;
780 TRACE( "%p\n", handle );
782 if (!hash || hash->hdr.magic != MAGIC_HASH) return STATUS_INVALID_HANDLE;
783 heap_free( hash );
784 return STATUS_SUCCESS;
787 NTSTATUS WINAPI BCryptHashData( BCRYPT_HASH_HANDLE handle, UCHAR *input, ULONG size, ULONG flags )
789 struct hash *hash = handle;
791 TRACE( "%p, %p, %u, %08x\n", handle, input, size, flags );
793 if (!hash || hash->hdr.magic != MAGIC_HASH) return STATUS_INVALID_HANDLE;
794 if (!input) return STATUS_SUCCESS;
796 return hash_update( &hash->inner, hash->alg_id, input, size );
799 NTSTATUS WINAPI BCryptFinishHash( BCRYPT_HASH_HANDLE handle, UCHAR *output, ULONG size, ULONG flags )
801 UCHAR buffer[MAX_HASH_OUTPUT_BYTES];
802 struct hash *hash = handle;
803 NTSTATUS status;
804 int hash_length;
806 TRACE( "%p, %p, %u, %08x\n", handle, output, size, flags );
808 if (!hash || hash->hdr.magic != MAGIC_HASH) return STATUS_INVALID_HANDLE;
809 if (!output) return STATUS_INVALID_PARAMETER;
811 if (!hash->hmac)
812 return hash_finish( &hash->inner, hash->alg_id, output, size );
814 hash_length = alg_props[hash->alg_id].hash_length;
815 if ((status = hash_finish( &hash->inner, hash->alg_id, buffer, hash_length ))) return status;
816 if ((status = hash_update( &hash->outer, hash->alg_id, buffer, hash_length ))) return status;
817 return hash_finish( &hash->outer, hash->alg_id, output, size );
820 NTSTATUS WINAPI BCryptHash( BCRYPT_ALG_HANDLE algorithm, UCHAR *secret, ULONG secretlen,
821 UCHAR *input, ULONG inputlen, UCHAR *output, ULONG outputlen )
823 NTSTATUS status;
824 BCRYPT_HASH_HANDLE handle;
826 TRACE( "%p, %p, %u, %p, %u, %p, %u\n", algorithm, secret, secretlen,
827 input, inputlen, output, outputlen );
829 status = BCryptCreateHash( algorithm, &handle, NULL, 0, secret, secretlen, 0);
830 if (status != STATUS_SUCCESS)
832 return status;
835 status = BCryptHashData( handle, input, inputlen, 0 );
836 if (status != STATUS_SUCCESS)
838 BCryptDestroyHash( handle );
839 return status;
842 status = BCryptFinishHash( handle, output, outputlen, 0 );
843 if (status != STATUS_SUCCESS)
845 BCryptDestroyHash( handle );
846 return status;
849 return BCryptDestroyHash( handle );
852 #if defined(HAVE_GNUTLS_CIPHER_INIT) && !defined(HAVE_COMMONCRYPTO_COMMONCRYPTOR_H)
853 struct key
855 struct object hdr;
856 enum alg_id alg_id;
857 enum mode_id mode;
858 ULONG block_size;
859 gnutls_cipher_hd_t handle;
860 UCHAR *secret;
861 ULONG secret_len;
863 #elif defined(HAVE_COMMONCRYPTO_COMMONCRYPTOR_H) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
864 struct key
866 struct object hdr;
867 enum alg_id alg_id;
868 enum mode_id mode;
869 ULONG block_size;
870 CCCryptorRef ref_encrypt;
871 CCCryptorRef ref_decrypt;
872 UCHAR *secret;
873 ULONG secret_len;
875 #else
876 struct key
878 struct object hdr;
879 enum mode_id mode;
880 ULONG block_size;
882 #endif
884 #if defined(HAVE_GNUTLS_CIPHER_INIT) || defined(HAVE_COMMONCRYPTO_COMMONCRYPTOR_H) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
885 static ULONG get_block_size( struct algorithm *alg )
887 ULONG ret = 0, size = sizeof(ret);
888 get_alg_property( alg, BCRYPT_BLOCK_LENGTH, (UCHAR *)&ret, sizeof(ret), &size );
889 return ret;
891 static NTSTATUS key_export( struct key *key, const WCHAR *type, UCHAR *output, ULONG output_len, ULONG *size )
893 if (!strcmpW( type, BCRYPT_KEY_DATA_BLOB ))
895 BCRYPT_KEY_DATA_BLOB_HEADER *header = (BCRYPT_KEY_DATA_BLOB_HEADER *)output;
896 ULONG req_size = sizeof(BCRYPT_KEY_DATA_BLOB_HEADER) + key->secret_len;
898 *size = req_size;
899 if (output_len < req_size) return STATUS_BUFFER_TOO_SMALL;
901 header->dwMagic = BCRYPT_KEY_DATA_BLOB_MAGIC;
902 header->dwVersion = BCRYPT_KEY_DATA_BLOB_VERSION1;
903 header->cbKeyData = key->secret_len;
904 memcpy( &header[1], key->secret, key->secret_len );
905 return STATUS_SUCCESS;
908 FIXME( "unsupported key type %s\n", debugstr_w(type) );
909 return STATUS_NOT_IMPLEMENTED;
911 #endif
913 #if defined(HAVE_GNUTLS_CIPHER_INIT) && !defined(HAVE_COMMONCRYPTO_COMMONCRYPTOR_H)
914 static NTSTATUS key_init( struct key *key, struct algorithm *alg, const UCHAR *secret, ULONG secret_len )
916 UCHAR *buffer;
918 if (!libgnutls_handle) return STATUS_INTERNAL_ERROR;
920 switch (alg->id)
922 case ALG_ID_AES:
923 break;
925 default:
926 FIXME( "algorithm %u not supported\n", alg->id );
927 return STATUS_NOT_SUPPORTED;
930 if (!(key->block_size = get_block_size( alg ))) return STATUS_INVALID_PARAMETER;
931 if (!(buffer = heap_alloc( secret_len ))) return STATUS_NO_MEMORY;
932 memcpy( buffer, secret, secret_len );
934 key->alg_id = alg->id;
935 key->mode = alg->mode;
936 key->handle = 0; /* initialized on first use */
937 key->secret = buffer;
938 key->secret_len = secret_len;
940 return STATUS_SUCCESS;
943 static gnutls_cipher_algorithm_t get_gnutls_cipher( const struct key *key )
945 switch (key->alg_id)
947 case ALG_ID_AES:
948 WARN( "handle block size\n" );
949 switch (key->mode)
951 case MODE_ID_GCM: return GNUTLS_CIPHER_AES_128_GCM;
952 case MODE_ID_CBC:
953 default: return GNUTLS_CIPHER_AES_128_CBC;
955 default:
956 FIXME( "algorithm %u not supported\n", key->alg_id );
957 return GNUTLS_CIPHER_UNKNOWN;
961 static NTSTATUS key_set_params( struct key *key, UCHAR *iv, ULONG iv_len )
963 gnutls_cipher_algorithm_t cipher;
964 gnutls_datum_t secret, vector;
965 int ret;
967 if (key->handle)
969 pgnutls_cipher_deinit( key->handle );
970 key->handle = NULL;
973 if ((cipher = get_gnutls_cipher( key )) == GNUTLS_CIPHER_UNKNOWN)
974 return STATUS_NOT_SUPPORTED;
976 secret.data = key->secret;
977 secret.size = key->secret_len;
978 if (iv)
980 vector.data = iv;
981 vector.size = iv_len;
984 if ((ret = pgnutls_cipher_init( &key->handle, cipher, &secret, iv ? &vector : NULL )))
986 pgnutls_perror( ret );
987 return STATUS_INTERNAL_ERROR;
990 return STATUS_SUCCESS;
993 static NTSTATUS key_encrypt( struct key *key, const UCHAR *input, ULONG input_len, UCHAR *output,
994 ULONG output_len )
996 int ret;
998 if ((ret = pgnutls_cipher_encrypt2( 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_decrypt( struct key *key, const UCHAR *input, ULONG input_len, UCHAR *output,
1008 ULONG output_len )
1010 int ret;
1012 if ((ret = pgnutls_cipher_decrypt2( key->handle, input, input_len, output, output_len )))
1014 pgnutls_perror( ret );
1015 return STATUS_INTERNAL_ERROR;
1018 return STATUS_SUCCESS;
1021 static NTSTATUS key_destroy( struct key *key )
1023 if (key->handle) pgnutls_cipher_deinit( key->handle );
1024 heap_free( key->secret );
1025 heap_free( key );
1026 return STATUS_SUCCESS;
1028 #elif defined(HAVE_COMMONCRYPTO_COMMONCRYPTOR_H) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
1029 static NTSTATUS key_init( struct key *key, struct algorithm *alg, const UCHAR *secret, ULONG secret_len )
1031 UCHAR *buffer;
1033 switch (alg->id)
1035 case ALG_ID_AES:
1036 switch (alg->mode)
1038 case MODE_ID_CBC:
1039 break;
1040 default:
1041 FIXME( "mode %u not supported\n", alg->mode );
1042 return STATUS_NOT_SUPPORTED;
1044 break;
1046 default:
1047 FIXME( "algorithm %u not supported\n", alg->id );
1048 return STATUS_NOT_SUPPORTED;
1051 if (!(key->block_size = get_block_size( alg ))) return STATUS_INVALID_PARAMETER;
1052 if (!(buffer = heap_alloc( secret_len ))) return STATUS_NO_MEMORY;
1053 memcpy( buffer, secret, secret_len );
1055 key->alg_id = alg->id;
1056 key->mode = alg->mode;
1057 key->ref_encrypt = NULL; /* initialized on first use */
1058 key->ref_decrypt = NULL;
1059 key->secret = buffer;
1060 key->secret_len = secret_len;
1062 return STATUS_SUCCESS;
1065 static NTSTATUS key_set_params( struct key *key, UCHAR *iv, ULONG iv_len )
1067 CCCryptorStatus status;
1069 if (key->ref_encrypt)
1071 CCCryptorRelease( key->ref_encrypt );
1072 key->ref_encrypt = NULL;
1074 if (key->ref_decrypt)
1076 CCCryptorRelease( key->ref_decrypt );
1077 key->ref_decrypt = NULL;
1080 if ((status = CCCryptorCreateWithMode( kCCEncrypt, kCCModeCBC, kCCAlgorithmAES128, ccNoPadding, iv,
1081 key->secret, key->secret_len, NULL, 0, 0, 0, &key->ref_encrypt )) != kCCSuccess)
1083 WARN( "CCCryptorCreateWithMode failed %d\n", status );
1084 return STATUS_INTERNAL_ERROR;
1086 if ((status = CCCryptorCreateWithMode( kCCDecrypt, kCCModeCBC, kCCAlgorithmAES128, ccNoPadding, iv,
1087 key->secret, key->secret_len, NULL, 0, 0, 0, &key->ref_decrypt )) != kCCSuccess)
1089 WARN( "CCCryptorCreateWithMode failed %d\n", status );
1090 CCCryptorRelease( key->ref_encrypt );
1091 key->ref_encrypt = NULL;
1092 return STATUS_INTERNAL_ERROR;
1095 return STATUS_SUCCESS;
1098 static NTSTATUS key_encrypt( struct key *key, const UCHAR *input, ULONG input_len, UCHAR *output,
1099 ULONG output_len )
1101 CCCryptorStatus status;
1103 if ((status = CCCryptorUpdate( key->ref_encrypt, input, input_len, output, output_len, NULL )) != kCCSuccess)
1105 WARN( "CCCryptorUpdate failed %d\n", status );
1106 return STATUS_INTERNAL_ERROR;
1109 return STATUS_SUCCESS;
1112 static NTSTATUS key_decrypt( struct key *key, const UCHAR *input, ULONG input_len, UCHAR *output,
1113 ULONG output_len )
1115 CCCryptorStatus status;
1117 if ((status = CCCryptorUpdate( key->ref_decrypt, input, input_len, output, output_len, NULL )) != kCCSuccess)
1119 WARN( "CCCryptorUpdate failed %d\n", status );
1120 return STATUS_INTERNAL_ERROR;
1123 return STATUS_SUCCESS;
1126 static NTSTATUS key_destroy( struct key *key )
1128 if (key->ref_encrypt) CCCryptorRelease( key->ref_encrypt );
1129 if (key->ref_decrypt) CCCryptorRelease( key->ref_decrypt );
1130 heap_free( key->secret );
1131 heap_free( key );
1132 return STATUS_SUCCESS;
1134 #else
1135 static NTSTATUS key_init( struct key *key, struct algorithm *alg, const UCHAR *secret, ULONG secret_len )
1137 ERR( "support for keys not available at build time\n" );
1138 return STATUS_NOT_IMPLEMENTED;
1141 static NTSTATUS key_set_params( struct key *key, UCHAR *iv, ULONG iv_len )
1143 ERR( "support for keys not available at build time\n" );
1144 return STATUS_NOT_IMPLEMENTED;
1147 static NTSTATUS key_encrypt( struct key *key, const UCHAR *input, ULONG input_len, UCHAR *output,
1148 ULONG output_len )
1150 ERR( "support for keys not available at build time\n" );
1151 return STATUS_NOT_IMPLEMENTED;
1154 static NTSTATUS key_decrypt( struct key *key, const UCHAR *input, ULONG input_len, UCHAR *output,
1155 ULONG output_len )
1157 ERR( "support for keys not available at build time\n" );
1158 return STATUS_NOT_IMPLEMENTED;
1161 static NTSTATUS key_destroy( struct key *key )
1163 ERR( "support for keys not available at build time\n" );
1164 return STATUS_NOT_IMPLEMENTED;
1167 static NTSTATUS key_export( struct key *key, const WCHAR *type, UCHAR *output, ULONG output_len, ULONG *size )
1169 ERR( "support for keys not available at build time\n" );
1170 return STATUS_NOT_IMPLEMENTED;
1172 #endif
1174 NTSTATUS WINAPI BCryptGenerateSymmetricKey( BCRYPT_ALG_HANDLE algorithm, BCRYPT_KEY_HANDLE *handle,
1175 UCHAR *object, ULONG object_len, UCHAR *secret, ULONG secret_len,
1176 ULONG flags )
1178 struct algorithm *alg = algorithm;
1179 struct key *key;
1180 NTSTATUS status;
1182 TRACE( "%p, %p, %p, %u, %p, %u, %08x\n", algorithm, handle, object, object_len, secret, secret_len, flags );
1184 if (!alg || alg->hdr.magic != MAGIC_ALG) return STATUS_INVALID_HANDLE;
1185 if (object) FIXME( "ignoring object buffer\n" );
1187 if (!(key = heap_alloc( sizeof(*key) ))) return STATUS_NO_MEMORY;
1188 key->hdr.magic = MAGIC_KEY;
1190 if ((status = key_init( key, alg, secret, secret_len )))
1192 heap_free( key );
1193 return status;
1196 *handle = key;
1197 return STATUS_SUCCESS;
1200 NTSTATUS WINAPI BCryptImportKey(BCRYPT_ALG_HANDLE algorithm, BCRYPT_KEY_HANDLE decrypt_key, LPCWSTR type,
1201 BCRYPT_KEY_HANDLE *key, PUCHAR object, ULONG object_len, PUCHAR input,
1202 ULONG input_len, ULONG flags)
1204 struct algorithm *alg = algorithm;
1206 TRACE("%p, %p, %s, %p, %p, %u, %p, %u, %u\n", algorithm, decrypt_key, debugstr_w(type), key, object,
1207 object_len, input, input_len, flags);
1209 if (!alg || alg->hdr.magic != MAGIC_ALG) return STATUS_INVALID_HANDLE;
1210 if (!key || !type || !input) return STATUS_INVALID_PARAMETER;
1212 if (decrypt_key)
1214 FIXME("Decrypting of key not yet supported\n");
1215 return STATUS_NO_MEMORY;
1218 if (!strcmpW(type, BCRYPT_KEY_DATA_BLOB))
1220 BCRYPT_KEY_DATA_BLOB_HEADER *key_header = (BCRYPT_KEY_DATA_BLOB_HEADER*)input;
1222 if (input_len < sizeof(BCRYPT_KEY_DATA_BLOB_HEADER))
1223 return STATUS_BUFFER_TOO_SMALL;
1225 if (key_header->dwMagic != BCRYPT_KEY_DATA_BLOB_MAGIC)
1226 return STATUS_INVALID_PARAMETER;
1228 if (key_header->dwVersion != BCRYPT_KEY_DATA_BLOB_VERSION1)
1230 FIXME("Unknown key data blob version: %d\n", key_header->dwVersion);
1231 return STATUS_INVALID_PARAMETER;
1234 if (key_header->cbKeyData + sizeof(BCRYPT_KEY_DATA_BLOB_HEADER) > input_len)
1235 return STATUS_INVALID_PARAMETER;
1237 return BCryptGenerateSymmetricKey(algorithm, key, object, object_len, (UCHAR*)&key_header[1], key_header->cbKeyData, 0);
1240 FIXME("Unsupported key type: %s\n", debugstr_w(type));
1241 return STATUS_INVALID_PARAMETER;
1244 NTSTATUS WINAPI BCryptExportKey(BCRYPT_KEY_HANDLE export_key, BCRYPT_KEY_HANDLE encrypt_key, LPCWSTR type,
1245 PUCHAR output, ULONG output_len, ULONG *size, ULONG flags)
1247 struct key *key = export_key;
1249 TRACE("%p, %p, %s, %p, %u, %p, %u\n", key, encrypt_key, debugstr_w(type), output, output_len, size, flags);
1251 if (!key || key->hdr.magic != MAGIC_KEY) return STATUS_INVALID_HANDLE;
1252 if (!output || !output_len || !size) return STATUS_INVALID_PARAMETER;
1254 if (encrypt_key)
1256 FIXME("Encryption of key not yet supported\n");
1257 return STATUS_NO_MEMORY;
1260 return key_export( key, type, output, output_len, size );
1263 NTSTATUS WINAPI BCryptDestroyKey( BCRYPT_KEY_HANDLE handle )
1265 struct key *key = handle;
1267 TRACE( "%p\n", handle );
1269 if (!key || key->hdr.magic != MAGIC_KEY) return STATUS_INVALID_HANDLE;
1270 return key_destroy( key );
1273 NTSTATUS WINAPI BCryptEncrypt( BCRYPT_KEY_HANDLE handle, UCHAR *input, ULONG input_len,
1274 void *padding, UCHAR *iv, ULONG iv_len, UCHAR *output,
1275 ULONG output_len, ULONG *ret_len, ULONG flags )
1277 struct key *key = handle;
1278 ULONG bytes_left = input_len;
1279 UCHAR *buf, *src, *dst;
1280 NTSTATUS status;
1282 TRACE( "%p, %p, %u, %p, %p, %u, %p, %u, %p, %08x\n", handle, input, input_len,
1283 padding, iv, iv_len, output, output_len, ret_len, flags );
1285 if (!key || key->hdr.magic != MAGIC_KEY) return STATUS_INVALID_HANDLE;
1286 if (flags & ~BCRYPT_BLOCK_PADDING)
1288 FIXME( "flags %08x not implemented\n", flags );
1289 return STATUS_NOT_IMPLEMENTED;
1292 if (key->mode == MODE_ID_GCM)
1294 BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO *auth_info = padding;
1296 if (!auth_info) return STATUS_INVALID_PARAMETER;
1297 if (!auth_info->pbNonce) return STATUS_INVALID_PARAMETER;
1298 if (!auth_info->pbTag) return STATUS_INVALID_PARAMETER;
1299 if (auth_info->cbTag < 12 || auth_info->cbTag > 16) return STATUS_INVALID_PARAMETER;
1300 if (auth_info->dwFlags & BCRYPT_AUTH_MODE_CHAIN_CALLS_FLAG)
1301 FIXME( "call chaining not implemented\n" );
1303 if ((status = key_set_params( key, auth_info->pbNonce, auth_info->cbNonce )))
1304 return status;
1306 *ret_len = input_len;
1307 if (flags & BCRYPT_BLOCK_PADDING) return STATUS_INVALID_PARAMETER;
1308 if (!output) return STATUS_SUCCESS;
1309 if (output_len < *ret_len) return STATUS_BUFFER_TOO_SMALL;
1311 if ((status = key_encrypt( key, input, input_len, output, output_len )))
1312 return status;
1314 return STATUS_SUCCESS;
1317 if ((status = key_set_params( key, iv, iv_len ))) return status;
1319 *ret_len = input_len;
1321 if (flags & BCRYPT_BLOCK_PADDING)
1322 *ret_len = (input_len + key->block_size) & ~(key->block_size - 1);
1323 else if (input_len & (key->block_size - 1))
1324 return STATUS_INVALID_BUFFER_SIZE;
1326 if (!output) return STATUS_SUCCESS;
1327 if (output_len < *ret_len) return STATUS_BUFFER_TOO_SMALL;
1329 src = input;
1330 dst = output;
1331 while (bytes_left >= key->block_size)
1333 if ((status = key_encrypt( key, src, key->block_size, dst, key->block_size ))) return status;
1334 bytes_left -= key->block_size;
1335 src += key->block_size;
1336 dst += key->block_size;
1339 if (flags & BCRYPT_BLOCK_PADDING)
1341 if (!(buf = heap_alloc( key->block_size ))) return STATUS_NO_MEMORY;
1342 memcpy( buf, src, bytes_left );
1343 memset( buf + bytes_left, key->block_size - bytes_left, key->block_size - bytes_left );
1344 status = key_encrypt( key, buf, key->block_size, dst, key->block_size );
1345 heap_free( buf );
1348 return status;
1351 NTSTATUS WINAPI BCryptDecrypt( BCRYPT_KEY_HANDLE handle, UCHAR *input, ULONG input_len,
1352 void *padding, UCHAR *iv, ULONG iv_len, UCHAR *output,
1353 ULONG output_len, ULONG *ret_len, ULONG flags )
1355 struct key *key = handle;
1356 ULONG bytes_left = input_len;
1357 UCHAR *buf, *src, *dst;
1358 NTSTATUS status;
1360 TRACE( "%p, %p, %u, %p, %p, %u, %p, %u, %p, %08x\n", handle, input, input_len,
1361 padding, iv, iv_len, output, output_len, ret_len, flags );
1363 if (!key || key->hdr.magic != MAGIC_KEY) return STATUS_INVALID_HANDLE;
1364 if (padding)
1366 FIXME( "padding info not implemented\n" );
1367 return STATUS_NOT_IMPLEMENTED;
1369 if (flags & ~BCRYPT_BLOCK_PADDING)
1371 FIXME( "flags %08x not supported\n", flags );
1372 return STATUS_NOT_IMPLEMENTED;
1375 if ((status = key_set_params( key, iv, iv_len ))) return status;
1377 *ret_len = input_len;
1379 if (input_len & (key->block_size - 1)) return STATUS_INVALID_BUFFER_SIZE;
1380 if (!output) return STATUS_SUCCESS;
1381 if (flags & BCRYPT_BLOCK_PADDING)
1383 if (output_len + key->block_size < *ret_len) return STATUS_BUFFER_TOO_SMALL;
1384 if (input_len < key->block_size) return STATUS_BUFFER_TOO_SMALL;
1385 bytes_left -= key->block_size;
1387 else if (output_len < *ret_len)
1388 return STATUS_BUFFER_TOO_SMALL;
1390 src = input;
1391 dst = output;
1392 while (bytes_left >= key->block_size)
1394 if ((status = key_decrypt( key, src, key->block_size, dst, key->block_size ))) return status;
1395 bytes_left -= key->block_size;
1396 src += key->block_size;
1397 dst += key->block_size;
1400 if (flags & BCRYPT_BLOCK_PADDING)
1402 if (!(buf = heap_alloc( key->block_size ))) return STATUS_NO_MEMORY;
1403 status = key_decrypt( key, src, key->block_size, buf, key->block_size );
1404 if (!status && buf[ key->block_size - 1 ] <= key->block_size)
1406 *ret_len -= buf[ key->block_size - 1 ];
1407 if (output_len < *ret_len) status = STATUS_BUFFER_TOO_SMALL;
1408 else memcpy( dst, buf, key->block_size - buf[ key->block_size - 1 ] );
1410 else
1411 status = STATUS_UNSUCCESSFUL; /* FIXME: invalid padding */
1412 heap_free( buf );
1415 return status;
1418 BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
1420 switch (reason)
1422 case DLL_PROCESS_ATTACH:
1423 instance = hinst;
1424 DisableThreadLibraryCalls( hinst );
1425 #if defined(HAVE_GNUTLS_CIPHER_INIT) && !defined(HAVE_COMMONCRYPTO_COMMONCRYPTOR_H)
1426 gnutls_initialize();
1427 #endif
1428 break;
1430 case DLL_PROCESS_DETACH:
1431 if (reserved) break;
1432 #if defined(HAVE_GNUTLS_CIPHER_INIT) && !defined(HAVE_COMMONCRYPTO_COMMONCRYPTOR_H)
1433 gnutls_uninitialize();
1434 #endif
1435 break;
1437 return TRUE;