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 <wine/config.h>
23 #define WIN32_NO_STATUS
29 #include <wine/debug.h>
30 #include <wine/unicode.h>
32 WINE_DEFAULT_DEBUG_CHANNEL(bcrypt
);
34 static HINSTANCE instance
;
36 #if defined(HAVE_GNUTLS_HASH) && !defined(HAVE_COMMONCRYPTO_COMMONDIGEST_H)
37 WINE_DECLARE_DEBUG_CHANNEL(winediag
);
39 static void *libgnutls_handle
;
40 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
41 MAKE_FUNCPTR(gnutls_global_deinit
);
42 MAKE_FUNCPTR(gnutls_global_init
);
43 MAKE_FUNCPTR(gnutls_global_set_log_function
);
44 MAKE_FUNCPTR(gnutls_global_set_log_level
);
45 MAKE_FUNCPTR(gnutls_hash
);
46 MAKE_FUNCPTR(gnutls_hash_deinit
);
47 MAKE_FUNCPTR(gnutls_hash_init
);
48 MAKE_FUNCPTR(gnutls_perror
);
51 static void gnutls_log( int level
, const char *msg
)
53 TRACE( "<%d> %s", level
, msg
);
56 static BOOL
gnutls_initialize(void)
60 if (!(libgnutls_handle
= wine_dlopen( SONAME_LIBGNUTLS
, RTLD_NOW
, NULL
, 0 )))
62 ERR_(winediag
)( "failed to load libgnutls, no support for crypto hashes\n" );
66 #define LOAD_FUNCPTR(f) \
67 if (!(p##f = wine_dlsym( libgnutls_handle, #f, NULL, 0 ))) \
69 ERR( "failed to load %s\n", #f ); \
73 LOAD_FUNCPTR(gnutls_global_deinit
)
74 LOAD_FUNCPTR(gnutls_global_init
)
75 LOAD_FUNCPTR(gnutls_global_set_log_function
)
76 LOAD_FUNCPTR(gnutls_global_set_log_level
)
77 LOAD_FUNCPTR(gnutls_hash
);
78 LOAD_FUNCPTR(gnutls_hash_deinit
);
79 LOAD_FUNCPTR(gnutls_hash_init
);
80 LOAD_FUNCPTR(gnutls_perror
)
83 if ((ret
= pgnutls_global_init()) != GNUTLS_E_SUCCESS
)
85 pgnutls_perror( ret
);
89 if (TRACE_ON( bcrypt
))
91 pgnutls_global_set_log_level( 4 );
92 pgnutls_global_set_log_function( gnutls_log
);
98 wine_dlclose( libgnutls_handle
, NULL
, 0 );
99 libgnutls_handle
= NULL
;
103 static void gnutls_uninitialize(void)
105 pgnutls_global_deinit();
106 wine_dlclose( libgnutls_handle
, NULL
, 0 );
107 libgnutls_handle
= NULL
;
109 #endif /* HAVE_GNUTLS_HASH && !HAVE_COMMONCRYPTO_COMMONDIGEST_H */
111 NTSTATUS WINAPI
BCryptEnumAlgorithms(ULONG dwAlgOperations
, ULONG
*pAlgCount
,
112 BCRYPT_ALGORITHM_IDENTIFIER
**ppAlgList
, ULONG dwFlags
)
114 FIXME("%08x, %p, %p, %08x - stub\n", dwAlgOperations
, pAlgCount
, ppAlgList
, dwFlags
);
119 return STATUS_NOT_IMPLEMENTED
;
122 NTSTATUS WINAPI
BCryptGenRandom(BCRYPT_ALG_HANDLE algorithm
, UCHAR
*buffer
, ULONG count
, ULONG flags
)
124 const DWORD supported_flags
= BCRYPT_USE_SYSTEM_PREFERRED_RNG
;
125 TRACE("%p, %p, %u, %08x - semi-stub\n", algorithm
, buffer
, count
, flags
);
129 /* It's valid to call without an algorithm if BCRYPT_USE_SYSTEM_PREFERRED_RNG
130 * is set. In this case the preferred system RNG is used.
132 if (!(flags
& BCRYPT_USE_SYSTEM_PREFERRED_RNG
))
133 return STATUS_INVALID_HANDLE
;
136 return STATUS_INVALID_PARAMETER
;
138 if (flags
& ~supported_flags
)
139 FIXME("unsupported flags %08x\n", flags
& ~supported_flags
);
142 FIXME("ignoring selected algorithm\n");
144 /* When zero bytes are requested the function returns success too. */
146 return STATUS_SUCCESS
;
148 if (flags
& BCRYPT_USE_SYSTEM_PREFERRED_RNG
)
150 if (RtlGenRandom(buffer
, count
))
151 return STATUS_SUCCESS
;
154 FIXME("called with unsupported parameters, returning error\n");
155 return STATUS_NOT_IMPLEMENTED
;
158 #define MAGIC_ALG (('A' << 24) | ('L' << 16) | ('G' << 8) | '0')
159 #define MAGIC_HASH (('H' << 24) | ('A' << 16) | ('S' << 8) | 'H')
173 static const struct {
175 const WCHAR
*alg_name
;
177 /* ALG_ID_SHA1 */ { 20, BCRYPT_SHA1_ALGORITHM
},
178 /* ALG_ID_SHA256 */ { 32, BCRYPT_SHA256_ALGORITHM
},
179 /* ALG_ID_SHA384 */ { 48, BCRYPT_SHA384_ALGORITHM
},
180 /* ALG_ID_SHA512 */ { 64, BCRYPT_SHA512_ALGORITHM
}
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(HAVE_GNUTLS_HASH)
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 static NTSTATUS
generic_alg_property( enum alg_id id
, const WCHAR
*prop
, UCHAR
*buf
, ULONG size
, ULONG
*ret_size
)
426 if (!strcmpW( prop
, BCRYPT_HASH_LENGTH
))
428 *ret_size
= sizeof(ULONG
);
429 if (size
< sizeof(ULONG
))
430 return STATUS_BUFFER_TOO_SMALL
;
432 *(ULONG
*)buf
= alg_props
[id
].hash_length
;
433 return STATUS_SUCCESS
;
436 if (!strcmpW( prop
, BCRYPT_ALGORITHM_NAME
))
438 *ret_size
= (strlenW(alg_props
[id
].alg_name
)+1)*sizeof(WCHAR
);
439 if (size
< *ret_size
)
440 return STATUS_BUFFER_TOO_SMALL
;
442 memcpy(buf
, alg_props
[id
].alg_name
, *ret_size
);
443 return STATUS_SUCCESS
;
446 return STATUS_NOT_IMPLEMENTED
;
449 static NTSTATUS
get_alg_property( enum alg_id id
, const WCHAR
*prop
, UCHAR
*buf
, ULONG size
, ULONG
*ret_size
)
454 status
= generic_alg_property( id
, prop
, buf
, size
, ret_size
);
455 if (status
!= STATUS_NOT_IMPLEMENTED
)
461 if (!strcmpW( prop
, BCRYPT_OBJECT_LENGTH
))
463 value
= OBJECT_LENGTH_SHA1
;
466 FIXME( "unsupported sha1 algorithm property %s\n", debugstr_w(prop
) );
467 return STATUS_NOT_IMPLEMENTED
;
470 if (!strcmpW( prop
, BCRYPT_OBJECT_LENGTH
))
472 value
= OBJECT_LENGTH_SHA256
;
475 FIXME( "unsupported sha256 algorithm property %s\n", debugstr_w(prop
) );
476 return STATUS_NOT_IMPLEMENTED
;
479 if (!strcmpW( prop
, BCRYPT_OBJECT_LENGTH
))
481 value
= OBJECT_LENGTH_SHA384
;
484 FIXME( "unsupported sha384 algorithm property %s\n", debugstr_w(prop
) );
485 return STATUS_NOT_IMPLEMENTED
;
488 if (!strcmpW( prop
, BCRYPT_OBJECT_LENGTH
))
490 value
= OBJECT_LENGTH_SHA512
;
493 FIXME( "unsupported sha512 algorithm property %s\n", debugstr_w(prop
) );
494 return STATUS_NOT_IMPLEMENTED
;
497 FIXME( "unsupported algorithm %u\n", id
);
498 return STATUS_NOT_IMPLEMENTED
;
501 if (size
< sizeof(ULONG
))
503 *ret_size
= sizeof(ULONG
);
504 return STATUS_BUFFER_TOO_SMALL
;
506 if (buf
) *(ULONG
*)buf
= value
;
507 *ret_size
= sizeof(ULONG
);
509 return STATUS_SUCCESS
;
512 static NTSTATUS
get_hash_property( enum alg_id id
, const WCHAR
*prop
, UCHAR
*buf
, ULONG size
, ULONG
*ret_size
)
516 status
= generic_alg_property( id
, prop
, buf
, size
, ret_size
);
517 if (status
== STATUS_NOT_IMPLEMENTED
)
518 FIXME( "unsupported property %s\n", debugstr_w(prop
) );
522 NTSTATUS WINAPI
BCryptGetProperty( BCRYPT_HANDLE handle
, LPCWSTR prop
, UCHAR
*buffer
, ULONG count
, ULONG
*res
, ULONG flags
)
524 struct object
*object
= handle
;
526 TRACE( "%p, %s, %p, %u, %p, %08x\n", handle
, wine_dbgstr_w(prop
), buffer
, count
, res
, flags
);
528 if (!object
) return STATUS_INVALID_HANDLE
;
529 if (!prop
|| !res
) return STATUS_INVALID_PARAMETER
;
531 switch (object
->magic
)
535 const struct algorithm
*alg
= (const struct algorithm
*)object
;
536 return get_alg_property( alg
->id
, prop
, buffer
, count
, res
);
540 const struct hash
*hash
= (const struct hash
*)object
;
541 return get_hash_property( hash
->alg_id
, prop
, buffer
, count
, res
);
544 WARN( "unknown magic %08x\n", object
->magic
);
545 return STATUS_INVALID_HANDLE
;
549 NTSTATUS WINAPI
BCryptCreateHash( BCRYPT_ALG_HANDLE algorithm
, BCRYPT_HASH_HANDLE
*handle
, UCHAR
*object
, ULONG objectlen
,
550 UCHAR
*secret
, ULONG secretlen
, ULONG flags
)
552 struct algorithm
*alg
= algorithm
;
556 TRACE( "%p, %p, %p, %u, %p, %u, %08x - stub\n", algorithm
, handle
, object
, objectlen
,
557 secret
, secretlen
, flags
);
560 FIXME( "unimplemented flags %08x\n", flags
);
561 return STATUS_NOT_IMPLEMENTED
;
564 if (!alg
|| alg
->hdr
.magic
!= MAGIC_ALG
) return STATUS_INVALID_HANDLE
;
565 if (object
) FIXME( "ignoring object buffer\n" );
567 if (!(hash
= HeapAlloc( GetProcessHeap(), 0, sizeof(*hash
) ))) return STATUS_NO_MEMORY
;
568 hash
->hdr
.magic
= MAGIC_HASH
;
569 hash
->alg_id
= alg
->id
;
570 if ((status
= hash_init( hash
)) != STATUS_SUCCESS
)
572 HeapFree( GetProcessHeap(), 0, hash
);
577 return STATUS_SUCCESS
;
580 NTSTATUS WINAPI
BCryptDestroyHash( BCRYPT_HASH_HANDLE handle
)
582 struct hash
*hash
= handle
;
584 TRACE( "%p\n", handle
);
586 if (!hash
|| hash
->hdr
.magic
!= MAGIC_HASH
) return STATUS_INVALID_HANDLE
;
587 HeapFree( GetProcessHeap(), 0, hash
);
588 return STATUS_SUCCESS
;
591 NTSTATUS WINAPI
BCryptHashData( BCRYPT_HASH_HANDLE handle
, UCHAR
*input
, ULONG size
, ULONG flags
)
593 struct hash
*hash
= handle
;
595 TRACE( "%p, %p, %u, %08x\n", handle
, input
, size
, flags
);
597 if (!hash
|| hash
->hdr
.magic
!= MAGIC_HASH
) return STATUS_INVALID_HANDLE
;
598 if (!input
) return STATUS_INVALID_PARAMETER
;
600 return hash_update( hash
, input
, size
);
603 NTSTATUS WINAPI
BCryptFinishHash( BCRYPT_HASH_HANDLE handle
, UCHAR
*output
, ULONG size
, ULONG flags
)
605 struct hash
*hash
= handle
;
607 TRACE( "%p, %p, %u, %08x\n", handle
, output
, size
, flags
);
609 if (!hash
|| hash
->hdr
.magic
!= MAGIC_HASH
) return STATUS_INVALID_HANDLE
;
610 if (!output
) return STATUS_INVALID_PARAMETER
;
612 return hash_finish( hash
, output
, size
);
615 BOOL WINAPI
DllMain( HINSTANCE hinst
, DWORD reason
, LPVOID reserved
)
619 case DLL_PROCESS_ATTACH
:
621 DisableThreadLibraryCalls( hinst
);
622 #if defined(HAVE_GNUTLS_HASH) && !defined(HAVE_COMMONCRYPTO_COMMONDIGEST_H)
627 case DLL_PROCESS_DETACH
:
629 #if defined(HAVE_GNUTLS_HASH) && !defined(HAVE_COMMONCRYPTO_COMMONDIGEST_H)
630 gnutls_uninitialize();