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 #elif defined(SONAME_LIBGNUTLS)
27 #include <gnutls/gnutls.h>
28 #include <gnutls/crypto.h>
32 #define WIN32_NO_STATUS
38 #include "wine/debug.h"
39 #include "wine/library.h"
40 #include "wine/unicode.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(bcrypt
);
44 static HINSTANCE instance
;
46 #if defined(SONAME_LIBGNUTLS) && !defined(HAVE_COMMONCRYPTO_COMMONDIGEST_H)
47 WINE_DECLARE_DEBUG_CHANNEL(winediag
);
49 static void *libgnutls_handle
;
50 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
51 MAKE_FUNCPTR(gnutls_global_deinit
);
52 MAKE_FUNCPTR(gnutls_global_init
);
53 MAKE_FUNCPTR(gnutls_global_set_log_function
);
54 MAKE_FUNCPTR(gnutls_global_set_log_level
);
55 MAKE_FUNCPTR(gnutls_hash
);
56 MAKE_FUNCPTR(gnutls_hash_deinit
);
57 MAKE_FUNCPTR(gnutls_hash_init
);
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_hash
);
88 LOAD_FUNCPTR(gnutls_hash_deinit
);
89 LOAD_FUNCPTR(gnutls_hash_init
);
90 LOAD_FUNCPTR(gnutls_perror
)
93 if ((ret
= pgnutls_global_init()) != GNUTLS_E_SUCCESS
)
95 pgnutls_perror( ret
);
99 if (TRACE_ON( bcrypt
))
101 pgnutls_global_set_log_level( 4 );
102 pgnutls_global_set_log_function( gnutls_log
);
108 wine_dlclose( libgnutls_handle
, NULL
, 0 );
109 libgnutls_handle
= NULL
;
113 static void gnutls_uninitialize(void)
115 pgnutls_global_deinit();
116 wine_dlclose( libgnutls_handle
, NULL
, 0 );
117 libgnutls_handle
= NULL
;
119 #endif /* SONAME_LIBGNUTLS && !HAVE_COMMONCRYPTO_COMMONDIGEST_H */
121 NTSTATUS WINAPI
BCryptEnumAlgorithms(ULONG dwAlgOperations
, ULONG
*pAlgCount
,
122 BCRYPT_ALGORITHM_IDENTIFIER
**ppAlgList
, ULONG dwFlags
)
124 FIXME("%08x, %p, %p, %08x - stub\n", dwAlgOperations
, pAlgCount
, ppAlgList
, dwFlags
);
129 return STATUS_NOT_IMPLEMENTED
;
132 NTSTATUS WINAPI
BCryptGenRandom(BCRYPT_ALG_HANDLE algorithm
, UCHAR
*buffer
, ULONG count
, ULONG flags
)
134 const DWORD supported_flags
= BCRYPT_USE_SYSTEM_PREFERRED_RNG
;
135 TRACE("%p, %p, %u, %08x - semi-stub\n", algorithm
, buffer
, count
, flags
);
139 /* It's valid to call without an algorithm if BCRYPT_USE_SYSTEM_PREFERRED_RNG
140 * is set. In this case the preferred system RNG is used.
142 if (!(flags
& BCRYPT_USE_SYSTEM_PREFERRED_RNG
))
143 return STATUS_INVALID_HANDLE
;
146 return STATUS_INVALID_PARAMETER
;
148 if (flags
& ~supported_flags
)
149 FIXME("unsupported flags %08x\n", flags
& ~supported_flags
);
152 FIXME("ignoring selected algorithm\n");
154 /* When zero bytes are requested the function returns success too. */
156 return STATUS_SUCCESS
;
158 if (flags
& BCRYPT_USE_SYSTEM_PREFERRED_RNG
)
160 if (RtlGenRandom(buffer
, count
))
161 return STATUS_SUCCESS
;
164 FIXME("called with unsupported parameters, returning error\n");
165 return STATUS_NOT_IMPLEMENTED
;
168 #define MAGIC_ALG (('A' << 24) | ('L' << 16) | ('G' << 8) | '0')
169 #define MAGIC_HASH (('H' << 24) | ('A' << 16) | ('S' << 8) | 'H')
189 NTSTATUS WINAPI
BCryptOpenAlgorithmProvider( BCRYPT_ALG_HANDLE
*handle
, LPCWSTR id
, LPCWSTR implementation
, DWORD flags
)
191 struct algorithm
*alg
;
194 TRACE( "%p, %s, %s, %08x\n", handle
, wine_dbgstr_w(id
), wine_dbgstr_w(implementation
), flags
);
196 if (!handle
|| !id
) return STATUS_INVALID_PARAMETER
;
199 FIXME( "unimplemented flags %08x\n", flags
);
200 return STATUS_NOT_IMPLEMENTED
;
203 if (!strcmpW( id
, BCRYPT_SHA1_ALGORITHM
)) alg_id
= ALG_ID_SHA1
;
204 else if (!strcmpW( id
, BCRYPT_SHA256_ALGORITHM
)) alg_id
= ALG_ID_SHA256
;
205 else if (!strcmpW( id
, BCRYPT_SHA384_ALGORITHM
)) alg_id
= ALG_ID_SHA384
;
206 else if (!strcmpW( id
, BCRYPT_SHA512_ALGORITHM
)) alg_id
= ALG_ID_SHA512
;
209 FIXME( "algorithm %s not supported\n", debugstr_w(id
) );
210 return STATUS_NOT_IMPLEMENTED
;
212 if (!implementation
|| strcmpW( implementation
, MS_PRIMITIVE_PROVIDER
))
214 FIXME( "implementation %s not supported\n", debugstr_w(implementation
) );
215 return STATUS_NOT_IMPLEMENTED
;
218 if (!(alg
= HeapAlloc( GetProcessHeap(), 0, sizeof(*alg
) ))) return STATUS_NO_MEMORY
;
219 alg
->hdr
.magic
= MAGIC_ALG
;
223 return STATUS_SUCCESS
;
226 NTSTATUS WINAPI
BCryptCloseAlgorithmProvider( BCRYPT_ALG_HANDLE handle
, DWORD flags
)
228 struct algorithm
*alg
= handle
;
230 TRACE( "%p, %08x\n", handle
, flags
);
232 if (!alg
|| alg
->hdr
.magic
!= MAGIC_ALG
) return STATUS_INVALID_HANDLE
;
233 HeapFree( GetProcessHeap(), 0, alg
);
234 return STATUS_SUCCESS
;
237 NTSTATUS WINAPI
BCryptGetFipsAlgorithmMode(BOOLEAN
*enabled
)
239 FIXME("%p - semi-stub\n", enabled
);
242 return STATUS_INVALID_PARAMETER
;
245 return STATUS_SUCCESS
;
248 #ifdef HAVE_COMMONCRYPTO_COMMONDIGEST_H
255 CC_SHA1_CTX sha1_ctx
;
256 CC_SHA256_CTX sha256_ctx
;
257 CC_SHA512_CTX sha512_ctx
;
261 static NTSTATUS
hash_init( struct hash
*hash
)
263 switch (hash
->alg_id
)
266 CC_SHA1_Init( &hash
->u
.sha1_ctx
);
270 CC_SHA256_Init( &hash
->u
.sha256_ctx
);
274 CC_SHA384_Init( &hash
->u
.sha512_ctx
);
278 CC_SHA512_Init( &hash
->u
.sha512_ctx
);
282 ERR( "unhandled id %u\n", hash
->alg_id
);
283 return STATUS_NOT_IMPLEMENTED
;
285 return STATUS_SUCCESS
;
288 static NTSTATUS
hash_update( struct hash
*hash
, UCHAR
*input
, ULONG size
)
290 switch (hash
->alg_id
)
293 CC_SHA1_Update( &hash
->u
.sha1_ctx
, input
, size
);
297 CC_SHA256_Update( &hash
->u
.sha256_ctx
, input
, size
);
301 CC_SHA384_Update( &hash
->u
.sha512_ctx
, input
, size
);
305 CC_SHA512_Update( &hash
->u
.sha512_ctx
, input
, size
);
309 ERR( "unhandled id %u\n", hash
->alg_id
);
310 return STATUS_NOT_IMPLEMENTED
;
312 return STATUS_SUCCESS
;
315 static NTSTATUS
hash_finish( struct hash
*hash
, UCHAR
*output
, ULONG size
)
317 switch (hash
->alg_id
)
320 CC_SHA1_Final( output
, &hash
->u
.sha1_ctx
);
324 CC_SHA256_Final( output
, &hash
->u
.sha256_ctx
);
328 CC_SHA384_Final( output
, &hash
->u
.sha512_ctx
);
332 CC_SHA512_Final( output
, &hash
->u
.sha512_ctx
);
336 ERR( "unhandled id %u\n", hash
->alg_id
);
339 return STATUS_SUCCESS
;
341 #elif defined(SONAME_LIBGNUTLS)
346 gnutls_hash_hd_t handle
;
349 static NTSTATUS
hash_init( struct hash
*hash
)
351 gnutls_digest_algorithm_t alg
;
353 if (!libgnutls_handle
) return STATUS_INTERNAL_ERROR
;
355 switch (hash
->alg_id
)
358 alg
= GNUTLS_DIG_SHA1
;
362 alg
= GNUTLS_DIG_SHA256
;
366 alg
= GNUTLS_DIG_SHA384
;
370 alg
= GNUTLS_DIG_SHA512
;
374 ERR( "unhandled id %u\n", hash
->alg_id
);
375 return STATUS_NOT_IMPLEMENTED
;
378 if (pgnutls_hash_init( &hash
->handle
, alg
)) return STATUS_INTERNAL_ERROR
;
379 return STATUS_SUCCESS
;
382 static NTSTATUS
hash_update( struct hash
*hash
, UCHAR
*input
, ULONG size
)
384 if (pgnutls_hash( hash
->handle
, input
, size
)) return STATUS_INTERNAL_ERROR
;
385 return STATUS_SUCCESS
;
388 static NTSTATUS
hash_finish( struct hash
*hash
, UCHAR
*output
, ULONG size
)
390 pgnutls_hash_deinit( hash
->handle
, output
);
391 return STATUS_SUCCESS
;
400 static NTSTATUS
hash_init( struct hash
*hash
)
402 ERR( "support for hashes not available at build time\n" );
403 return STATUS_NOT_IMPLEMENTED
;
406 static NTSTATUS
hash_update( struct hash
*hash
, UCHAR
*input
, ULONG size
)
408 ERR( "support for hashes not available at build time\n" );
409 return STATUS_NOT_IMPLEMENTED
;
412 static NTSTATUS
hash_finish( struct hash
*hash
, UCHAR
*output
, ULONG size
)
414 ERR( "support for hashes not available at build time\n" );
415 return STATUS_NOT_IMPLEMENTED
;
419 #define OBJECT_LENGTH_SHA1 278
420 #define OBJECT_LENGTH_SHA256 286
421 #define OBJECT_LENGTH_SHA384 382
422 #define OBJECT_LENGTH_SHA512 382
424 #define HASH_DIGEST_LENGTH_SHA1 20
425 #define HASH_DIGEST_LENGTH_SHA256 32
426 #define HASH_DIGEST_LENGTH_SHA384 48
427 #define HASH_DIGEST_LENGTH_SHA512 64
429 static NTSTATUS
get_alg_property( enum alg_id id
, const WCHAR
*prop
, UCHAR
*buf
, ULONG size
, ULONG
*ret_size
)
436 if (!strcmpW( prop
, BCRYPT_OBJECT_LENGTH
))
438 value
= OBJECT_LENGTH_SHA1
;
441 FIXME( "unsupported sha1 algorithm property %s\n", debugstr_w(prop
) );
442 return STATUS_NOT_IMPLEMENTED
;
445 if (!strcmpW( prop
, BCRYPT_OBJECT_LENGTH
))
447 value
= OBJECT_LENGTH_SHA256
;
450 FIXME( "unsupported sha256 algorithm property %s\n", debugstr_w(prop
) );
451 return STATUS_NOT_IMPLEMENTED
;
454 if (!strcmpW( prop
, BCRYPT_OBJECT_LENGTH
))
456 value
= OBJECT_LENGTH_SHA384
;
459 FIXME( "unsupported sha384 algorithm property %s\n", debugstr_w(prop
) );
460 return STATUS_NOT_IMPLEMENTED
;
463 if (!strcmpW( prop
, BCRYPT_OBJECT_LENGTH
))
465 value
= OBJECT_LENGTH_SHA512
;
468 FIXME( "unsupported sha512 algorithm property %s\n", debugstr_w(prop
) );
469 return STATUS_NOT_IMPLEMENTED
;
472 FIXME( "unsupported algorithm %u\n", id
);
473 return STATUS_NOT_IMPLEMENTED
;
476 if (size
< sizeof(ULONG
))
478 *ret_size
= sizeof(ULONG
);
479 return STATUS_BUFFER_TOO_SMALL
;
481 if (buf
) *(ULONG
*)buf
= value
;
482 *ret_size
= sizeof(ULONG
);
484 return STATUS_SUCCESS
;
487 static NTSTATUS
get_hash_property( enum alg_id id
, const WCHAR
*prop
, UCHAR
*buf
, ULONG size
, ULONG
*ret_size
)
494 if (!strcmpW( prop
, BCRYPT_HASH_LENGTH
))
496 value
= HASH_DIGEST_LENGTH_SHA1
;
499 FIXME( "unsupported sha1 hash property %s\n", debugstr_w(prop
) );
500 return STATUS_NOT_IMPLEMENTED
;
503 if (!strcmpW( prop
, BCRYPT_HASH_LENGTH
))
505 value
= HASH_DIGEST_LENGTH_SHA256
;
508 FIXME( "unsupported sha256 hash property %s\n", debugstr_w(prop
) );
509 return STATUS_NOT_IMPLEMENTED
;
512 if (!strcmpW( prop
, BCRYPT_HASH_LENGTH
))
514 value
= HASH_DIGEST_LENGTH_SHA384
;
517 FIXME( "unsupported sha384 hash property %s\n", debugstr_w(prop
) );
518 return STATUS_NOT_IMPLEMENTED
;
521 if (!strcmpW( prop
, BCRYPT_HASH_LENGTH
))
523 value
= HASH_DIGEST_LENGTH_SHA512
;
526 FIXME( "unsupported sha512 hash property %s\n", debugstr_w(prop
) );
527 return STATUS_NOT_IMPLEMENTED
;
530 FIXME( "unsupported hash %u\n", id
);
531 return STATUS_NOT_IMPLEMENTED
;
534 if (size
< sizeof(ULONG
))
536 *ret_size
= sizeof(ULONG
);
537 return STATUS_BUFFER_TOO_SMALL
;
539 if (buf
) *(ULONG
*)buf
= value
;
540 *ret_size
= sizeof(ULONG
);
542 return STATUS_SUCCESS
;
545 NTSTATUS WINAPI
BCryptGetProperty( BCRYPT_HANDLE handle
, LPCWSTR prop
, UCHAR
*buffer
, ULONG count
, ULONG
*res
, ULONG flags
)
547 struct object
*object
= handle
;
549 TRACE( "%p, %s, %p, %u, %p, %08x\n", handle
, wine_dbgstr_w(prop
), buffer
, count
, res
, flags
);
551 if (!object
) return STATUS_INVALID_HANDLE
;
552 if (!prop
|| !res
) return STATUS_INVALID_PARAMETER
;
554 switch (object
->magic
)
558 const struct algorithm
*alg
= (const struct algorithm
*)object
;
559 return get_alg_property( alg
->id
, prop
, buffer
, count
, res
);
563 const struct hash
*hash
= (const struct hash
*)object
;
564 return get_hash_property( hash
->alg_id
, prop
, buffer
, count
, res
);
567 WARN( "unknown magic %08x", object
->magic
);
568 return STATUS_INVALID_HANDLE
;
572 NTSTATUS WINAPI
BCryptCreateHash( BCRYPT_ALG_HANDLE algorithm
, BCRYPT_HASH_HANDLE
*handle
, UCHAR
*object
, ULONG objectlen
,
573 UCHAR
*secret
, ULONG secretlen
, ULONG flags
)
575 struct algorithm
*alg
= algorithm
;
579 TRACE( "%p, %p, %p, %u, %p, %u, %08x - stub\n", algorithm
, handle
, object
, objectlen
,
580 secret
, secretlen
, flags
);
583 FIXME( "unimplemented flags %08x\n", flags
);
584 return STATUS_NOT_IMPLEMENTED
;
587 if (!alg
|| alg
->hdr
.magic
!= MAGIC_ALG
) return STATUS_INVALID_HANDLE
;
588 if (object
) FIXME( "ignoring object buffer\n" );
590 if (!(hash
= HeapAlloc( GetProcessHeap(), 0, sizeof(*hash
) ))) return STATUS_NO_MEMORY
;
591 hash
->hdr
.magic
= MAGIC_HASH
;
592 hash
->alg_id
= alg
->id
;
593 if ((status
= hash_init( hash
)) != STATUS_SUCCESS
)
595 HeapFree( GetProcessHeap(), 0, hash
);
600 return STATUS_SUCCESS
;
603 NTSTATUS WINAPI
BCryptDestroyHash( BCRYPT_HASH_HANDLE handle
)
605 struct hash
*hash
= handle
;
607 TRACE( "%p\n", handle
);
609 if (!hash
|| hash
->hdr
.magic
!= MAGIC_HASH
) return STATUS_INVALID_HANDLE
;
610 HeapFree( GetProcessHeap(), 0, hash
);
611 return STATUS_SUCCESS
;
614 NTSTATUS WINAPI
BCryptHashData( BCRYPT_HASH_HANDLE handle
, UCHAR
*input
, ULONG size
, ULONG flags
)
616 struct hash
*hash
= handle
;
618 TRACE( "%p, %p, %u, %08x\n", handle
, input
, size
, flags
);
620 if (!hash
|| hash
->hdr
.magic
!= MAGIC_HASH
) return STATUS_INVALID_HANDLE
;
621 if (!input
) return STATUS_INVALID_PARAMETER
;
623 return hash_update( hash
, input
, size
);
626 NTSTATUS WINAPI
BCryptFinishHash( BCRYPT_HASH_HANDLE handle
, UCHAR
*output
, ULONG size
, ULONG flags
)
628 struct hash
*hash
= handle
;
630 TRACE( "%p, %p, %u, %08x\n", handle
, output
, size
, flags
);
632 if (!hash
|| hash
->hdr
.magic
!= MAGIC_HASH
) return STATUS_INVALID_HANDLE
;
633 if (!output
) return STATUS_INVALID_PARAMETER
;
635 return hash_finish( hash
, output
, size
);
638 BOOL WINAPI
DllMain( HINSTANCE hinst
, DWORD reason
, LPVOID reserved
)
642 case DLL_PROCESS_ATTACH
:
644 DisableThreadLibraryCalls( hinst
);
645 #if defined(SONAME_LIBGNUTLS) && !defined(HAVE_COMMONCRYPTO_COMMONDIGEST_H)
650 case DLL_PROCESS_DETACH
:
652 #if defined(SONAME_LIBGNUTLS) && !defined(HAVE_COMMONCRYPTO_COMMONDIGEST_H)
653 gnutls_uninitialize();