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_global_deinit
);
55 MAKE_FUNCPTR(gnutls_global_init
);
56 MAKE_FUNCPTR(gnutls_global_set_log_function
);
57 MAKE_FUNCPTR(gnutls_global_set_log_level
);
58 MAKE_FUNCPTR(gnutls_perror
);
61 static void gnutls_log( int level
, const char *msg
)
63 TRACE( "<%d> %s", level
, msg
);
66 static BOOL
gnutls_initialize(void)
70 if (!(libgnutls_handle
= wine_dlopen( SONAME_LIBGNUTLS
, RTLD_NOW
, NULL
, 0 )))
72 ERR_(winediag
)( "failed to load libgnutls, no support for crypto hashes\n" );
76 #define LOAD_FUNCPTR(f) \
77 if (!(p##f = wine_dlsym( libgnutls_handle, #f, NULL, 0 ))) \
79 ERR( "failed to load %s\n", #f ); \
83 LOAD_FUNCPTR(gnutls_global_deinit
)
84 LOAD_FUNCPTR(gnutls_global_init
)
85 LOAD_FUNCPTR(gnutls_global_set_log_function
)
86 LOAD_FUNCPTR(gnutls_global_set_log_level
)
87 LOAD_FUNCPTR(gnutls_perror
)
90 if ((ret
= pgnutls_global_init()) != GNUTLS_E_SUCCESS
)
92 pgnutls_perror( ret
);
96 if (TRACE_ON( bcrypt
))
98 pgnutls_global_set_log_level( 4 );
99 pgnutls_global_set_log_function( gnutls_log
);
105 wine_dlclose( libgnutls_handle
, NULL
, 0 );
106 libgnutls_handle
= NULL
;
110 static void gnutls_uninitialize(void)
112 pgnutls_global_deinit();
113 wine_dlclose( libgnutls_handle
, NULL
, 0 );
114 libgnutls_handle
= NULL
;
116 #endif /* HAVE_GNUTLS_HASH && !HAVE_COMMONCRYPTO_COMMONDIGEST_H */
118 NTSTATUS WINAPI
BCryptEnumAlgorithms(ULONG dwAlgOperations
, ULONG
*pAlgCount
,
119 BCRYPT_ALGORITHM_IDENTIFIER
**ppAlgList
, ULONG dwFlags
)
121 FIXME("%08x, %p, %p, %08x - stub\n", dwAlgOperations
, pAlgCount
, ppAlgList
, dwFlags
);
126 return STATUS_NOT_IMPLEMENTED
;
129 #define MAGIC_ALG (('A' << 24) | ('L' << 16) | ('G' << 8) | '0')
130 #define MAGIC_HASH (('H' << 24) | ('A' << 16) | ('S' << 8) | 'H')
146 #define MAX_HASH_OUTPUT_BYTES 64
147 #define MAX_HASH_BLOCK_BITS 1024
149 static const struct {
153 const WCHAR
*alg_name
;
155 /* ALG_ID_MD5 */ { 274, 16, 512, BCRYPT_MD5_ALGORITHM
},
156 /* ALG_ID_RNG */ { 0, 0, 0, BCRYPT_RNG_ALGORITHM
},
157 /* ALG_ID_SHA1 */ { 278, 20, 512, BCRYPT_SHA1_ALGORITHM
},
158 /* ALG_ID_SHA256 */ { 286, 32, 512, BCRYPT_SHA256_ALGORITHM
},
159 /* ALG_ID_SHA384 */ { 382, 48, 1024, BCRYPT_SHA384_ALGORITHM
},
160 /* ALG_ID_SHA512 */ { 382, 64, 1024, BCRYPT_SHA512_ALGORITHM
}
170 NTSTATUS WINAPI
BCryptGenRandom(BCRYPT_ALG_HANDLE handle
, UCHAR
*buffer
, ULONG count
, ULONG flags
)
172 const DWORD supported_flags
= BCRYPT_USE_SYSTEM_PREFERRED_RNG
;
173 struct algorithm
*algorithm
= handle
;
175 TRACE("%p, %p, %u, %08x - semi-stub\n", handle
, buffer
, count
, flags
);
179 /* It's valid to call without an algorithm if BCRYPT_USE_SYSTEM_PREFERRED_RNG
180 * is set. In this case the preferred system RNG is used.
182 if (!(flags
& BCRYPT_USE_SYSTEM_PREFERRED_RNG
))
183 return STATUS_INVALID_HANDLE
;
185 else if (algorithm
->hdr
.magic
!= MAGIC_ALG
|| algorithm
->id
!= ALG_ID_RNG
)
186 return STATUS_INVALID_HANDLE
;
189 return STATUS_INVALID_PARAMETER
;
191 if (flags
& ~supported_flags
)
192 FIXME("unsupported flags %08x\n", flags
& ~supported_flags
);
195 FIXME("ignoring selected algorithm\n");
197 /* When zero bytes are requested the function returns success too. */
199 return STATUS_SUCCESS
;
201 if (algorithm
|| (flags
& BCRYPT_USE_SYSTEM_PREFERRED_RNG
))
203 if (RtlGenRandom(buffer
, count
))
204 return STATUS_SUCCESS
;
207 FIXME("called with unsupported parameters, returning error\n");
208 return STATUS_NOT_IMPLEMENTED
;
211 NTSTATUS WINAPI
BCryptOpenAlgorithmProvider( BCRYPT_ALG_HANDLE
*handle
, LPCWSTR id
, LPCWSTR implementation
, DWORD flags
)
213 struct algorithm
*alg
;
216 const DWORD supported_flags
= BCRYPT_ALG_HANDLE_HMAC_FLAG
;
218 TRACE( "%p, %s, %s, %08x\n", handle
, wine_dbgstr_w(id
), wine_dbgstr_w(implementation
), flags
);
220 if (!handle
|| !id
) return STATUS_INVALID_PARAMETER
;
221 if (flags
& ~supported_flags
)
223 FIXME( "unsupported flags %08x\n", flags
& ~supported_flags
);
224 return STATUS_NOT_IMPLEMENTED
;
227 if (!strcmpW( id
, BCRYPT_SHA1_ALGORITHM
)) alg_id
= ALG_ID_SHA1
;
228 else if (!strcmpW( id
, BCRYPT_MD5_ALGORITHM
)) alg_id
= ALG_ID_MD5
;
229 else if (!strcmpW( id
, BCRYPT_RNG_ALGORITHM
)) alg_id
= ALG_ID_RNG
;
230 else if (!strcmpW( id
, BCRYPT_SHA256_ALGORITHM
)) alg_id
= ALG_ID_SHA256
;
231 else if (!strcmpW( id
, BCRYPT_SHA384_ALGORITHM
)) alg_id
= ALG_ID_SHA384
;
232 else if (!strcmpW( id
, BCRYPT_SHA512_ALGORITHM
)) alg_id
= ALG_ID_SHA512
;
235 FIXME( "algorithm %s not supported\n", debugstr_w(id
) );
236 return STATUS_NOT_IMPLEMENTED
;
238 if (implementation
&& strcmpW( implementation
, MS_PRIMITIVE_PROVIDER
))
240 FIXME( "implementation %s not supported\n", debugstr_w(implementation
) );
241 return STATUS_NOT_IMPLEMENTED
;
244 if (!(alg
= HeapAlloc( GetProcessHeap(), 0, sizeof(*alg
) ))) return STATUS_NO_MEMORY
;
245 alg
->hdr
.magic
= MAGIC_ALG
;
247 alg
->hmac
= flags
& BCRYPT_ALG_HANDLE_HMAC_FLAG
;
250 return STATUS_SUCCESS
;
253 NTSTATUS WINAPI
BCryptCloseAlgorithmProvider( BCRYPT_ALG_HANDLE handle
, DWORD flags
)
255 struct algorithm
*alg
= handle
;
257 TRACE( "%p, %08x\n", handle
, flags
);
259 if (!alg
|| alg
->hdr
.magic
!= MAGIC_ALG
) return STATUS_INVALID_HANDLE
;
260 HeapFree( GetProcessHeap(), 0, alg
);
261 return STATUS_SUCCESS
;
264 NTSTATUS WINAPI
BCryptGetFipsAlgorithmMode(BOOLEAN
*enabled
)
266 FIXME("%p - semi-stub\n", enabled
);
269 return STATUS_INVALID_PARAMETER
;
272 return STATUS_SUCCESS
;
286 static NTSTATUS
hash_init( struct hash_impl
*hash
, enum alg_id alg_id
)
291 MD5Init( &hash
->u
.md5
);
295 A_SHAInit( &hash
->u
.sha1
);
299 sha256_init( &hash
->u
.sha256
);
303 sha384_init( &hash
->u
.sha512
);
307 sha512_init( &hash
->u
.sha512
);
311 ERR( "unhandled id %u\n", alg_id
);
312 return STATUS_NOT_IMPLEMENTED
;
314 return STATUS_SUCCESS
;
317 static NTSTATUS
hash_update( struct hash_impl
*hash
, enum alg_id alg_id
,
318 UCHAR
*input
, ULONG size
)
323 MD5Update( &hash
->u
.md5
, input
, size
);
327 A_SHAUpdate( &hash
->u
.sha1
, input
, size
);
331 sha256_update( &hash
->u
.sha256
, input
, size
);
335 sha384_update( &hash
->u
.sha512
, input
, size
);
339 sha512_update( &hash
->u
.sha512
, input
, size
);
343 ERR( "unhandled id %u\n", alg_id
);
344 return STATUS_NOT_IMPLEMENTED
;
346 return STATUS_SUCCESS
;
349 static NTSTATUS
hash_finish( struct hash_impl
*hash
, enum alg_id alg_id
,
350 UCHAR
*output
, ULONG size
)
355 MD5Final( &hash
->u
.md5
);
356 memcpy( output
, hash
->u
.md5
.digest
, 16 );
360 A_SHAFinal( &hash
->u
.sha1
, (ULONG
*)output
);
364 sha256_finalize( &hash
->u
.sha256
, output
);
368 sha384_finalize( &hash
->u
.sha512
, output
);
372 sha512_finalize( &hash
->u
.sha512
, output
);
376 ERR( "unhandled id %u\n", alg_id
);
377 return STATUS_NOT_IMPLEMENTED
;
379 return STATUS_SUCCESS
;
387 struct hash_impl outer
;
388 struct hash_impl inner
;
391 static NTSTATUS
generic_alg_property( enum alg_id id
, const WCHAR
*prop
, UCHAR
*buf
, ULONG size
, ULONG
*ret_size
)
393 if (!strcmpW( prop
, BCRYPT_OBJECT_LENGTH
))
395 if (!alg_props
[id
].object_length
)
396 return STATUS_NOT_SUPPORTED
;
397 *ret_size
= sizeof(ULONG
);
398 if (size
< sizeof(ULONG
))
399 return STATUS_BUFFER_TOO_SMALL
;
401 *(ULONG
*)buf
= alg_props
[id
].object_length
;
402 return STATUS_SUCCESS
;
405 if (!strcmpW( prop
, BCRYPT_HASH_LENGTH
))
407 if (!alg_props
[id
].hash_length
)
408 return STATUS_NOT_SUPPORTED
;
409 *ret_size
= sizeof(ULONG
);
410 if (size
< sizeof(ULONG
))
411 return STATUS_BUFFER_TOO_SMALL
;
413 *(ULONG
*)buf
= alg_props
[id
].hash_length
;
414 return STATUS_SUCCESS
;
417 if (!strcmpW( prop
, BCRYPT_ALGORITHM_NAME
))
419 *ret_size
= (strlenW(alg_props
[id
].alg_name
)+1)*sizeof(WCHAR
);
420 if (size
< *ret_size
)
421 return STATUS_BUFFER_TOO_SMALL
;
423 memcpy(buf
, alg_props
[id
].alg_name
, *ret_size
);
424 return STATUS_SUCCESS
;
427 return STATUS_NOT_IMPLEMENTED
;
430 static NTSTATUS
get_alg_property( enum alg_id id
, const WCHAR
*prop
, UCHAR
*buf
, ULONG size
, ULONG
*ret_size
)
434 status
= generic_alg_property( id
, prop
, buf
, size
, ret_size
);
435 if (status
== STATUS_NOT_IMPLEMENTED
)
436 FIXME( "unsupported property %s\n", debugstr_w(prop
) );
440 static NTSTATUS
get_hash_property( enum alg_id id
, const WCHAR
*prop
, UCHAR
*buf
, ULONG size
, ULONG
*ret_size
)
444 status
= generic_alg_property( id
, prop
, buf
, size
, ret_size
);
445 if (status
== STATUS_NOT_IMPLEMENTED
)
446 FIXME( "unsupported property %s\n", debugstr_w(prop
) );
450 NTSTATUS WINAPI
BCryptGetProperty( BCRYPT_HANDLE handle
, LPCWSTR prop
, UCHAR
*buffer
, ULONG count
, ULONG
*res
, ULONG flags
)
452 struct object
*object
= handle
;
454 TRACE( "%p, %s, %p, %u, %p, %08x\n", handle
, wine_dbgstr_w(prop
), buffer
, count
, res
, flags
);
456 if (!object
) return STATUS_INVALID_HANDLE
;
457 if (!prop
|| !res
) return STATUS_INVALID_PARAMETER
;
459 switch (object
->magic
)
463 const struct algorithm
*alg
= (const struct algorithm
*)object
;
464 return get_alg_property( alg
->id
, prop
, buffer
, count
, res
);
468 const struct hash
*hash
= (const struct hash
*)object
;
469 return get_hash_property( hash
->alg_id
, prop
, buffer
, count
, res
);
472 WARN( "unknown magic %08x\n", object
->magic
);
473 return STATUS_INVALID_HANDLE
;
477 NTSTATUS WINAPI
BCryptCreateHash( BCRYPT_ALG_HANDLE algorithm
, BCRYPT_HASH_HANDLE
*handle
, UCHAR
*object
, ULONG objectlen
,
478 UCHAR
*secret
, ULONG secretlen
, ULONG flags
)
480 struct algorithm
*alg
= algorithm
;
481 UCHAR buffer
[MAX_HASH_BLOCK_BITS
/ 8] = {0};
487 TRACE( "%p, %p, %p, %u, %p, %u, %08x - stub\n", algorithm
, handle
, object
, objectlen
,
488 secret
, secretlen
, flags
);
491 FIXME( "unimplemented flags %08x\n", flags
);
492 return STATUS_NOT_IMPLEMENTED
;
495 if (!alg
|| alg
->hdr
.magic
!= MAGIC_ALG
) return STATUS_INVALID_HANDLE
;
496 if (object
) FIXME( "ignoring object buffer\n" );
498 if (!(hash
= HeapAlloc( GetProcessHeap(), 0, sizeof(*hash
) ))) return STATUS_NO_MEMORY
;
499 hash
->hdr
.magic
= MAGIC_HASH
;
500 hash
->alg_id
= alg
->id
;
501 hash
->hmac
= alg
->hmac
;
503 /* initialize hash */
504 if ((status
= hash_init( &hash
->inner
, hash
->alg_id
))) goto end
;
505 if (!hash
->hmac
) goto end
;
507 /* initialize hmac */
508 if ((status
= hash_init( &hash
->outer
, hash
->alg_id
))) goto end
;
509 block_bytes
= alg_props
[hash
->alg_id
].block_bits
/ 8;
510 if (secretlen
> block_bytes
)
512 struct hash_impl temp
;
513 if ((status
= hash_init( &temp
, hash
->alg_id
))) goto end
;
514 if ((status
= hash_update( &temp
, hash
->alg_id
, secret
, secretlen
))) goto end
;
515 if ((status
= hash_finish( &temp
, hash
->alg_id
, buffer
,
516 alg_props
[hash
->alg_id
].hash_length
))) goto end
;
520 memcpy( buffer
, secret
, secretlen
);
522 for (i
= 0; i
< block_bytes
; i
++) buffer
[i
] ^= 0x5c;
523 if ((status
= hash_update( &hash
->outer
, hash
->alg_id
, buffer
, block_bytes
))) goto end
;
524 for (i
= 0; i
< block_bytes
; i
++) buffer
[i
] ^= (0x5c ^ 0x36);
525 status
= hash_update( &hash
->inner
, hash
->alg_id
, buffer
, block_bytes
);
528 if (status
!= STATUS_SUCCESS
)
530 HeapFree( GetProcessHeap(), 0, hash
);
535 return STATUS_SUCCESS
;
538 NTSTATUS WINAPI
BCryptDuplicateHash( BCRYPT_HASH_HANDLE handle
, BCRYPT_HASH_HANDLE
*handle_copy
,
539 UCHAR
*object
, ULONG objectlen
, ULONG flags
)
541 struct hash
*hash_orig
= handle
;
542 struct hash
*hash_copy
;
544 TRACE( "%p, %p, %p, %u, %u\n", handle
, handle_copy
, object
, objectlen
, flags
);
546 if (!hash_orig
|| hash_orig
->hdr
.magic
!= MAGIC_HASH
) return STATUS_INVALID_HANDLE
;
547 if (!handle_copy
) return STATUS_INVALID_PARAMETER
;
548 if (object
) FIXME( "ignoring object buffer\n" );
550 if (!(hash_copy
= HeapAlloc( GetProcessHeap(), 0, sizeof(*hash_copy
) )))
551 return STATUS_NO_MEMORY
;
553 memcpy( hash_copy
, hash_orig
, sizeof(*hash_orig
) );
555 *handle_copy
= hash_copy
;
556 return STATUS_SUCCESS
;
559 NTSTATUS WINAPI
BCryptDestroyHash( BCRYPT_HASH_HANDLE handle
)
561 struct hash
*hash
= handle
;
563 TRACE( "%p\n", handle
);
565 if (!hash
|| hash
->hdr
.magic
!= MAGIC_HASH
) return STATUS_INVALID_HANDLE
;
566 HeapFree( GetProcessHeap(), 0, hash
);
567 return STATUS_SUCCESS
;
570 NTSTATUS WINAPI
BCryptHashData( BCRYPT_HASH_HANDLE handle
, UCHAR
*input
, ULONG size
, ULONG flags
)
572 struct hash
*hash
= handle
;
574 TRACE( "%p, %p, %u, %08x\n", handle
, input
, size
, flags
);
576 if (!hash
|| hash
->hdr
.magic
!= MAGIC_HASH
) return STATUS_INVALID_HANDLE
;
577 if (!input
) return STATUS_SUCCESS
;
579 return hash_update( &hash
->inner
, hash
->alg_id
, input
, size
);
582 NTSTATUS WINAPI
BCryptFinishHash( BCRYPT_HASH_HANDLE handle
, UCHAR
*output
, ULONG size
, ULONG flags
)
584 UCHAR buffer
[MAX_HASH_OUTPUT_BYTES
];
585 struct hash
*hash
= handle
;
589 TRACE( "%p, %p, %u, %08x\n", handle
, output
, size
, flags
);
591 if (!hash
|| hash
->hdr
.magic
!= MAGIC_HASH
) return STATUS_INVALID_HANDLE
;
592 if (!output
) return STATUS_INVALID_PARAMETER
;
595 return hash_finish( &hash
->inner
, hash
->alg_id
, output
, size
);
597 hash_length
= alg_props
[hash
->alg_id
].hash_length
;
598 if ((status
= hash_finish( &hash
->inner
, hash
->alg_id
, buffer
, hash_length
))) return status
;
599 if ((status
= hash_update( &hash
->outer
, hash
->alg_id
, buffer
, hash_length
))) return status
;
600 return hash_finish( &hash
->outer
, hash
->alg_id
, output
, size
);
603 NTSTATUS WINAPI
BCryptHash( BCRYPT_ALG_HANDLE algorithm
, UCHAR
*secret
, ULONG secretlen
,
604 UCHAR
*input
, ULONG inputlen
, UCHAR
*output
, ULONG outputlen
)
607 BCRYPT_HASH_HANDLE handle
;
609 TRACE( "%p, %p, %u, %p, %u, %p, %u\n", algorithm
, secret
, secretlen
,
610 input
, inputlen
, output
, outputlen
);
612 status
= BCryptCreateHash( algorithm
, &handle
, NULL
, 0, secret
, secretlen
, 0);
613 if (status
!= STATUS_SUCCESS
)
618 status
= BCryptHashData( handle
, input
, inputlen
, 0 );
619 if (status
!= STATUS_SUCCESS
)
621 BCryptDestroyHash( handle
);
625 status
= BCryptFinishHash( handle
, output
, outputlen
, 0 );
626 if (status
!= STATUS_SUCCESS
)
628 BCryptDestroyHash( handle
);
632 return BCryptDestroyHash( handle
);
635 BOOL WINAPI
DllMain( HINSTANCE hinst
, DWORD reason
, LPVOID reserved
)
639 case DLL_PROCESS_ATTACH
:
641 DisableThreadLibraryCalls( hinst
);
642 #if defined(HAVE_GNUTLS_HASH) && !defined(HAVE_COMMONCRYPTO_COMMONDIGEST_H)
647 case DLL_PROCESS_DETACH
:
649 #if defined(HAVE_GNUTLS_HASH) && !defined(HAVE_COMMONCRYPTO_COMMONDIGEST_H)
650 gnutls_uninitialize();