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
21 #include "wine/port.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>
33 #define WIN32_NO_STATUS
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
);
64 static void gnutls_log( int level
, const char *msg
)
66 TRACE( "<%d> %s", level
, msg
);
69 static BOOL
gnutls_initialize(void)
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" );
79 #define LOAD_FUNCPTR(f) \
80 if (!(p##f = wine_dlsym( libgnutls_handle, #f, NULL, 0 ))) \
82 ERR( "failed to load %s\n", #f ); \
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
)
96 if ((ret
= pgnutls_global_init()) != GNUTLS_E_SUCCESS
)
98 pgnutls_perror( ret
);
102 if (TRACE_ON( bcrypt
))
104 pgnutls_global_set_log_level( 4 );
105 pgnutls_global_set_log_function( gnutls_log
);
111 wine_dlclose( libgnutls_handle
, NULL
, 0 );
112 libgnutls_handle
= NULL
;
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
);
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')
154 #define MAX_HASH_OUTPUT_BYTES 64
155 #define MAX_HASH_BLOCK_BITS 1024
157 static const struct {
161 const WCHAR
*alg_name
;
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
}
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
);
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
;
198 return STATUS_INVALID_PARAMETER
;
200 if (flags
& ~supported_flags
)
201 FIXME("unsupported flags %08x\n", flags
& ~supported_flags
);
204 FIXME("ignoring selected algorithm\n");
206 /* When zero bytes are requested the function returns success too. */
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
;
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
;
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
;
256 alg
->hmac
= flags
& BCRYPT_ALG_HANDLE_HMAC_FLAG
;
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
);
278 return STATUS_INVALID_PARAMETER
;
281 return STATUS_SUCCESS
;
295 static NTSTATUS
hash_init( struct hash_impl
*hash
, enum alg_id alg_id
)
300 MD5Init( &hash
->u
.md5
);
304 A_SHAInit( &hash
->u
.sha1
);
308 sha256_init( &hash
->u
.sha256
);
312 sha384_init( &hash
->u
.sha512
);
316 sha512_init( &hash
->u
.sha512
);
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
)
332 MD5Update( &hash
->u
.md5
, input
, size
);
336 A_SHAUpdate( &hash
->u
.sha1
, input
, size
);
340 sha256_update( &hash
->u
.sha256
, input
, size
);
344 sha384_update( &hash
->u
.sha512
, input
, size
);
348 sha512_update( &hash
->u
.sha512
, input
, size
);
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
)
364 MD5Final( &hash
->u
.md5
);
365 memcpy( output
, hash
->u
.md5
.digest
, 16 );
369 A_SHAFinal( &hash
->u
.sha1
, (ULONG
*)output
);
373 sha256_finalize( &hash
->u
.sha256
, output
);
377 sha384_finalize( &hash
->u
.sha512
, output
);
381 sha512_finalize( &hash
->u
.sha512
, output
);
385 ERR( "unhandled id %u\n", alg_id
);
386 return STATUS_NOT_IMPLEMENTED
;
388 return STATUS_SUCCESS
;
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
;
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
;
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
;
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
)
445 status
= generic_alg_property( id
, prop
, buf
, size
, ret_size
);
446 if (status
!= STATUS_NOT_IMPLEMENTED
)
452 if (!strcmpW( prop
, BCRYPT_BLOCK_LENGTH
))
454 *ret_size
= sizeof(ULONG
);
455 if (size
< sizeof(ULONG
))
456 return STATUS_BUFFER_TOO_SMALL
;
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
;
471 *ret_size
= sizeof(BCRYPT_CHAIN_MODE_CBC
) * sizeof(WCHAR
);
472 return STATUS_BUFFER_TOO_SMALL
;
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
)
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
) );
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
)
508 const struct algorithm
*alg
= (const struct algorithm
*)object
;
509 return get_alg_property( alg
->id
, prop
, buffer
, count
, res
);
513 const struct hash
*hash
= (const struct hash
*)object
;
514 return get_hash_property( hash
->alg_id
, prop
, buffer
, count
, res
);
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};
538 TRACE( "%p, %p, %p, %u, %p, %u, %08x - stub\n", algorithm
, handle
, object
, objectlen
,
539 secret
, secretlen
, 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
;
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
);
579 if (status
!= STATUS_SUCCESS
)
581 HeapFree( GetProcessHeap(), 0, 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
;
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
;
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
)
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
)
669 status
= BCryptHashData( handle
, input
, inputlen
, 0 );
670 if (status
!= STATUS_SUCCESS
)
672 BCryptDestroyHash( handle
);
676 status
= BCryptFinishHash( handle
, output
, outputlen
, 0 );
677 if (status
!= STATUS_SUCCESS
)
679 BCryptDestroyHash( handle
);
683 return BCryptDestroyHash( handle
);
686 #if defined(HAVE_GNUTLS_HASH) && !defined(HAVE_COMMONCRYPTO_COMMONDIGEST_H)
692 gnutls_cipher_hd_t handle
;
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
);
704 static NTSTATUS
key_init( struct key
*key
, enum alg_id id
, const UCHAR
*secret
, ULONG secret_len
)
708 if (!libgnutls_handle
) return STATUS_INTERNAL_ERROR
;
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
);
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
)
737 FIXME( "handle block size and chaining mode\n" );
738 return GNUTLS_CIPHER_AES_128_CBC
;
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
;
754 pgnutls_cipher_deinit( key
->handle
);
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
;
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
,
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
;
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
,
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
;
832 NTSTATUS WINAPI
BCryptGenerateSymmetricKey( BCRYPT_ALG_HANDLE algorithm
, BCRYPT_KEY_HANDLE
*handle
,
833 UCHAR
*object
, ULONG object_len
, UCHAR
*secret
, ULONG secret_len
,
836 struct algorithm
*alg
= algorithm
;
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
);
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
;
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
;
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
;
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
);
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
)
939 case DLL_PROCESS_ATTACH
:
941 DisableThreadLibraryCalls( hinst
);
942 #if defined(HAVE_GNUTLS_HASH) && !defined(HAVE_COMMONCRYPTO_COMMONDIGEST_H)
947 case DLL_PROCESS_DETACH
:
949 #if defined(HAVE_GNUTLS_HASH) && !defined(HAVE_COMMONCRYPTO_COMMONDIGEST_H)
950 gnutls_uninitialize();