po: Updated Polish translation.
[wine.git] / dlls / bcrypt / bcrypt_main.c
blob80d7ddb946660eaf2335924bcfe62fcce82fca15
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_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>
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/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);
59 #undef MAKE_FUNCPTR
61 static void gnutls_log( int level, const char *msg )
63 TRACE( "<%d> %s", level, msg );
66 static BOOL gnutls_initialize(void)
68 int ret;
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" );
73 return FALSE;
76 #define LOAD_FUNCPTR(f) \
77 if (!(p##f = wine_dlsym( libgnutls_handle, #f, NULL, 0 ))) \
78 { \
79 ERR( "failed to load %s\n", #f ); \
80 goto fail; \
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)
88 #undef LOAD_FUNCPTR
90 if ((ret = pgnutls_global_init()) != GNUTLS_E_SUCCESS)
92 pgnutls_perror( ret );
93 goto fail;
96 if (TRACE_ON( bcrypt ))
98 pgnutls_global_set_log_level( 4 );
99 pgnutls_global_set_log_function( gnutls_log );
102 return TRUE;
104 fail:
105 wine_dlclose( libgnutls_handle, NULL, 0 );
106 libgnutls_handle = NULL;
107 return FALSE;
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);
123 *ppAlgList=NULL;
124 *pAlgCount=0;
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')
131 struct object
133 ULONG magic;
136 enum alg_id
138 ALG_ID_MD5,
139 ALG_ID_RNG,
140 ALG_ID_SHA1,
141 ALG_ID_SHA256,
142 ALG_ID_SHA384,
143 ALG_ID_SHA512
146 #define MAX_HASH_OUTPUT_BYTES 64
147 #define MAX_HASH_BLOCK_BITS 1024
149 static const struct {
150 ULONG object_length;
151 ULONG hash_length;
152 ULONG block_bits;
153 const WCHAR *alg_name;
154 } alg_props[] = {
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 }
163 struct algorithm
165 struct object hdr;
166 enum alg_id id;
167 BOOL hmac;
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);
177 if (!algorithm)
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;
188 if (!buffer)
189 return STATUS_INVALID_PARAMETER;
191 if (flags & ~supported_flags)
192 FIXME("unsupported flags %08x\n", flags & ~supported_flags);
194 if (algorithm)
195 FIXME("ignoring selected algorithm\n");
197 /* When zero bytes are requested the function returns success too. */
198 if (!count)
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;
214 enum alg_id alg_id;
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;
233 else
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;
246 alg->id = alg_id;
247 alg->hmac = flags & BCRYPT_ALG_HANDLE_HMAC_FLAG;
249 *handle = alg;
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);
268 if (!enabled)
269 return STATUS_INVALID_PARAMETER;
271 *enabled = FALSE;
272 return STATUS_SUCCESS;
275 struct hash_impl
277 union
279 MD5_CTX md5;
280 SHA_CTX sha1;
281 SHA256_CTX sha256;
282 SHA512_CTX sha512;
283 } u;
286 static NTSTATUS hash_init( struct hash_impl *hash, enum alg_id alg_id )
288 switch (alg_id)
290 case ALG_ID_MD5:
291 MD5Init( &hash->u.md5 );
292 break;
294 case ALG_ID_SHA1:
295 A_SHAInit( &hash->u.sha1 );
296 break;
298 case ALG_ID_SHA256:
299 sha256_init( &hash->u.sha256 );
300 break;
302 case ALG_ID_SHA384:
303 sha384_init( &hash->u.sha512 );
304 break;
306 case ALG_ID_SHA512:
307 sha512_init( &hash->u.sha512 );
308 break;
310 default:
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 )
320 switch (alg_id)
322 case ALG_ID_MD5:
323 MD5Update( &hash->u.md5, input, size );
324 break;
326 case ALG_ID_SHA1:
327 A_SHAUpdate( &hash->u.sha1, input, size );
328 break;
330 case ALG_ID_SHA256:
331 sha256_update( &hash->u.sha256, input, size );
332 break;
334 case ALG_ID_SHA384:
335 sha384_update( &hash->u.sha512, input, size );
336 break;
338 case ALG_ID_SHA512:
339 sha512_update( &hash->u.sha512, input, size );
340 break;
342 default:
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 )
352 switch (alg_id)
354 case ALG_ID_MD5:
355 MD5Final( &hash->u.md5 );
356 memcpy( output, hash->u.md5.digest, 16 );
357 break;
359 case ALG_ID_SHA1:
360 A_SHAFinal( &hash->u.sha1, (ULONG *)output );
361 break;
363 case ALG_ID_SHA256:
364 sha256_finalize( &hash->u.sha256, output );
365 break;
367 case ALG_ID_SHA384:
368 sha384_finalize( &hash->u.sha512, output );
369 break;
371 case ALG_ID_SHA512:
372 sha512_finalize( &hash->u.sha512, output );
373 break;
375 default:
376 ERR( "unhandled id %u\n", alg_id );
377 return STATUS_NOT_IMPLEMENTED;
379 return STATUS_SUCCESS;
382 struct hash
384 struct object hdr;
385 enum alg_id alg_id;
386 BOOL hmac;
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;
400 if (buf)
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;
412 if(buf)
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;
422 if(buf)
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 )
432 NTSTATUS status;
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) );
437 return status;
440 static NTSTATUS get_hash_property( enum alg_id id, const WCHAR *prop, UCHAR *buf, ULONG size, ULONG *ret_size )
442 NTSTATUS status;
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) );
447 return status;
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)
461 case MAGIC_ALG:
463 const struct algorithm *alg = (const struct algorithm *)object;
464 return get_alg_property( alg->id, prop, buffer, count, res );
466 case MAGIC_HASH:
468 const struct hash *hash = (const struct hash *)object;
469 return get_hash_property( hash->alg_id, prop, buffer, count, res );
471 default:
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};
482 struct hash *hash;
483 int block_bytes;
484 NTSTATUS status;
485 int i;
487 TRACE( "%p, %p, %p, %u, %p, %u, %08x - stub\n", algorithm, handle, object, objectlen,
488 secret, secretlen, flags );
489 if (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;
518 else
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 );
527 end:
528 if (status != STATUS_SUCCESS)
530 HeapFree( GetProcessHeap(), 0, hash );
531 return status;
534 *handle = 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;
586 NTSTATUS status;
587 int hash_length;
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;
594 if (!hash->hmac)
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 )
606 NTSTATUS status;
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)
615 return status;
618 status = BCryptHashData( handle, input, inputlen, 0 );
619 if (status != STATUS_SUCCESS)
621 BCryptDestroyHash( handle );
622 return status;
625 status = BCryptFinishHash( handle, output, outputlen, 0 );
626 if (status != STATUS_SUCCESS)
628 BCryptDestroyHash( handle );
629 return status;
632 return BCryptDestroyHash( handle );
635 BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
637 switch (reason)
639 case DLL_PROCESS_ATTACH:
640 instance = hinst;
641 DisableThreadLibraryCalls( hinst );
642 #if defined(HAVE_GNUTLS_HASH) && !defined(HAVE_COMMONCRYPTO_COMMONDIGEST_H)
643 gnutls_initialize();
644 #endif
645 break;
647 case DLL_PROCESS_DETACH:
648 if (reserved) break;
649 #if defined(HAVE_GNUTLS_HASH) && !defined(HAVE_COMMONCRYPTO_COMMONDIGEST_H)
650 gnutls_uninitialize();
651 #endif
652 break;
654 return TRUE;