33c3af8e2e436db3527e9ac052cba5ff3eec184b
[reactos.git] / reactos / dll / win32 / bcrypt / bcrypt_main.c
1 /*
2 * Copyright 2009 Henri Verbeet for CodeWeavers
3 *
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.
8 *
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.
13 *
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
17 *
18 */
19
20 #include <wine/config.h>
21
22 #include <ntstatus.h>
23 #define WIN32_NO_STATUS
24 #include <windef.h>
25 #include <winbase.h>
26 #include <ntsecapi.h>
27 #include <bcrypt.h>
28
29 #include <wine/debug.h>
30 #include <wine/unicode.h>
31
32 WINE_DEFAULT_DEBUG_CHANNEL(bcrypt);
33
34 static HINSTANCE instance;
35
36 #if defined(HAVE_GNUTLS_HASH) && !defined(HAVE_COMMONCRYPTO_COMMONDIGEST_H)
37 WINE_DECLARE_DEBUG_CHANNEL(winediag);
38
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);
49 #undef MAKE_FUNCPTR
50
51 static void gnutls_log( int level, const char *msg )
52 {
53 TRACE( "<%d> %s", level, msg );
54 }
55
56 static BOOL gnutls_initialize(void)
57 {
58 int ret;
59
60 if (!(libgnutls_handle = wine_dlopen( SONAME_LIBGNUTLS, RTLD_NOW, NULL, 0 )))
61 {
62 ERR_(winediag)( "failed to load libgnutls, no support for crypto hashes\n" );
63 return FALSE;
64 }
65
66 #define LOAD_FUNCPTR(f) \
67 if (!(p##f = wine_dlsym( libgnutls_handle, #f, NULL, 0 ))) \
68 { \
69 ERR( "failed to load %s\n", #f ); \
70 goto fail; \
71 }
72
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)
81 #undef LOAD_FUNCPTR
82
83 if ((ret = pgnutls_global_init()) != GNUTLS_E_SUCCESS)
84 {
85 pgnutls_perror( ret );
86 goto fail;
87 }
88
89 if (TRACE_ON( bcrypt ))
90 {
91 pgnutls_global_set_log_level( 4 );
92 pgnutls_global_set_log_function( gnutls_log );
93 }
94
95 return TRUE;
96
97 fail:
98 wine_dlclose( libgnutls_handle, NULL, 0 );
99 libgnutls_handle = NULL;
100 return FALSE;
101 }
102
103 static void gnutls_uninitialize(void)
104 {
105 pgnutls_global_deinit();
106 wine_dlclose( libgnutls_handle, NULL, 0 );
107 libgnutls_handle = NULL;
108 }
109 #endif /* HAVE_GNUTLS_HASH && !HAVE_COMMONCRYPTO_COMMONDIGEST_H */
110
111 NTSTATUS WINAPI BCryptEnumAlgorithms(ULONG dwAlgOperations, ULONG *pAlgCount,
112 BCRYPT_ALGORITHM_IDENTIFIER **ppAlgList, ULONG dwFlags)
113 {
114 FIXME("%08x, %p, %p, %08x - stub\n", dwAlgOperations, pAlgCount, ppAlgList, dwFlags);
115
116 *ppAlgList=NULL;
117 *pAlgCount=0;
118
119 return STATUS_NOT_IMPLEMENTED;
120 }
121
122 NTSTATUS WINAPI BCryptGenRandom(BCRYPT_ALG_HANDLE algorithm, UCHAR *buffer, ULONG count, ULONG flags)
123 {
124 const DWORD supported_flags = BCRYPT_USE_SYSTEM_PREFERRED_RNG;
125 TRACE("%p, %p, %u, %08x - semi-stub\n", algorithm, buffer, count, flags);
126
127 if (!algorithm)
128 {
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.
131 */
132 if (!(flags & BCRYPT_USE_SYSTEM_PREFERRED_RNG))
133 return STATUS_INVALID_HANDLE;
134 }
135 if (!buffer)
136 return STATUS_INVALID_PARAMETER;
137
138 if (flags & ~supported_flags)
139 FIXME("unsupported flags %08x\n", flags & ~supported_flags);
140
141 if (algorithm)
142 FIXME("ignoring selected algorithm\n");
143
144 /* When zero bytes are requested the function returns success too. */
145 if (!count)
146 return STATUS_SUCCESS;
147
148 if (flags & BCRYPT_USE_SYSTEM_PREFERRED_RNG)
149 {
150 if (RtlGenRandom(buffer, count))
151 return STATUS_SUCCESS;
152 }
153
154 FIXME("called with unsupported parameters, returning error\n");
155 return STATUS_NOT_IMPLEMENTED;
156 }
157
158 #define MAGIC_ALG (('A' << 24) | ('L' << 16) | ('G' << 8) | '0')
159 #define MAGIC_HASH (('H' << 24) | ('A' << 16) | ('S' << 8) | 'H')
160 struct object
161 {
162 ULONG magic;
163 };
164
165 enum alg_id
166 {
167 ALG_ID_SHA1,
168 ALG_ID_SHA256,
169 ALG_ID_SHA384,
170 ALG_ID_SHA512
171 };
172
173 static const struct {
174 ULONG hash_length;
175 const WCHAR *alg_name;
176 } alg_props[] = {
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 }
181 };
182
183 struct algorithm
184 {
185 struct object hdr;
186 enum alg_id id;
187 };
188
189 NTSTATUS WINAPI BCryptOpenAlgorithmProvider( BCRYPT_ALG_HANDLE *handle, LPCWSTR id, LPCWSTR implementation, DWORD flags )
190 {
191 struct algorithm *alg;
192 enum alg_id alg_id;
193
194 TRACE( "%p, %s, %s, %08x\n", handle, wine_dbgstr_w(id), wine_dbgstr_w(implementation), flags );
195
196 if (!handle || !id) return STATUS_INVALID_PARAMETER;
197 if (flags)
198 {
199 FIXME( "unimplemented flags %08x\n", flags );
200 return STATUS_NOT_IMPLEMENTED;
201 }
202
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;
207 else
208 {
209 FIXME( "algorithm %s not supported\n", debugstr_w(id) );
210 return STATUS_NOT_IMPLEMENTED;
211 }
212 if (implementation && strcmpW( implementation, MS_PRIMITIVE_PROVIDER ))
213 {
214 FIXME( "implementation %s not supported\n", debugstr_w(implementation) );
215 return STATUS_NOT_IMPLEMENTED;
216 }
217
218 if (!(alg = HeapAlloc( GetProcessHeap(), 0, sizeof(*alg) ))) return STATUS_NO_MEMORY;
219 alg->hdr.magic = MAGIC_ALG;
220 alg->id = alg_id;
221
222 *handle = alg;
223 return STATUS_SUCCESS;
224 }
225
226 NTSTATUS WINAPI BCryptCloseAlgorithmProvider( BCRYPT_ALG_HANDLE handle, DWORD flags )
227 {
228 struct algorithm *alg = handle;
229
230 TRACE( "%p, %08x\n", handle, flags );
231
232 if (!alg || alg->hdr.magic != MAGIC_ALG) return STATUS_INVALID_HANDLE;
233 HeapFree( GetProcessHeap(), 0, alg );
234 return STATUS_SUCCESS;
235 }
236
237 NTSTATUS WINAPI BCryptGetFipsAlgorithmMode(BOOLEAN *enabled)
238 {
239 FIXME("%p - semi-stub\n", enabled);
240
241 if (!enabled)
242 return STATUS_INVALID_PARAMETER;
243
244 *enabled = FALSE;
245 return STATUS_SUCCESS;
246 }
247
248 #ifdef HAVE_COMMONCRYPTO_COMMONDIGEST_H
249 struct hash
250 {
251 struct object hdr;
252 enum alg_id alg_id;
253 union
254 {
255 CC_SHA1_CTX sha1_ctx;
256 CC_SHA256_CTX sha256_ctx;
257 CC_SHA512_CTX sha512_ctx;
258 } u;
259 };
260
261 static NTSTATUS hash_init( struct hash *hash )
262 {
263 switch (hash->alg_id)
264 {
265 case ALG_ID_SHA1:
266 CC_SHA1_Init( &hash->u.sha1_ctx );
267 break;
268
269 case ALG_ID_SHA256:
270 CC_SHA256_Init( &hash->u.sha256_ctx );
271 break;
272
273 case ALG_ID_SHA384:
274 CC_SHA384_Init( &hash->u.sha512_ctx );
275 break;
276
277 case ALG_ID_SHA512:
278 CC_SHA512_Init( &hash->u.sha512_ctx );
279 break;
280
281 default:
282 ERR( "unhandled id %u\n", hash->alg_id );
283 return STATUS_NOT_IMPLEMENTED;
284 }
285 return STATUS_SUCCESS;
286 }
287
288 static NTSTATUS hash_update( struct hash *hash, UCHAR *input, ULONG size )
289 {
290 switch (hash->alg_id)
291 {
292 case ALG_ID_SHA1:
293 CC_SHA1_Update( &hash->u.sha1_ctx, input, size );
294 break;
295
296 case ALG_ID_SHA256:
297 CC_SHA256_Update( &hash->u.sha256_ctx, input, size );
298 break;
299
300 case ALG_ID_SHA384:
301 CC_SHA384_Update( &hash->u.sha512_ctx, input, size );
302 break;
303
304 case ALG_ID_SHA512:
305 CC_SHA512_Update( &hash->u.sha512_ctx, input, size );
306 break;
307
308 default:
309 ERR( "unhandled id %u\n", hash->alg_id );
310 return STATUS_NOT_IMPLEMENTED;
311 }
312 return STATUS_SUCCESS;
313 }
314
315 static NTSTATUS hash_finish( struct hash *hash, UCHAR *output, ULONG size )
316 {
317 switch (hash->alg_id)
318 {
319 case ALG_ID_SHA1:
320 CC_SHA1_Final( output, &hash->u.sha1_ctx );
321 break;
322
323 case ALG_ID_SHA256:
324 CC_SHA256_Final( output, &hash->u.sha256_ctx );
325 break;
326
327 case ALG_ID_SHA384:
328 CC_SHA384_Final( output, &hash->u.sha512_ctx );
329 break;
330
331 case ALG_ID_SHA512:
332 CC_SHA512_Final( output, &hash->u.sha512_ctx );
333 break;
334
335 default:
336 ERR( "unhandled id %u\n", hash->alg_id );
337 break;
338 }
339 return STATUS_SUCCESS;
340 }
341 #elif defined(HAVE_GNUTLS_HASH)
342 struct hash
343 {
344 struct object hdr;
345 enum alg_id alg_id;
346 gnutls_hash_hd_t handle;
347 };
348
349 static NTSTATUS hash_init( struct hash *hash )
350 {
351 gnutls_digest_algorithm_t alg;
352
353 if (!libgnutls_handle) return STATUS_INTERNAL_ERROR;
354
355 switch (hash->alg_id)
356 {
357 case ALG_ID_SHA1:
358 alg = GNUTLS_DIG_SHA1;
359 break;
360
361 case ALG_ID_SHA256:
362 alg = GNUTLS_DIG_SHA256;
363 break;
364
365 case ALG_ID_SHA384:
366 alg = GNUTLS_DIG_SHA384;
367 break;
368
369 case ALG_ID_SHA512:
370 alg = GNUTLS_DIG_SHA512;
371 break;
372
373 default:
374 ERR( "unhandled id %u\n", hash->alg_id );
375 return STATUS_NOT_IMPLEMENTED;
376 }
377
378 if (pgnutls_hash_init( &hash->handle, alg )) return STATUS_INTERNAL_ERROR;
379 return STATUS_SUCCESS;
380 }
381
382 static NTSTATUS hash_update( struct hash *hash, UCHAR *input, ULONG size )
383 {
384 if (pgnutls_hash( hash->handle, input, size )) return STATUS_INTERNAL_ERROR;
385 return STATUS_SUCCESS;
386 }
387
388 static NTSTATUS hash_finish( struct hash *hash, UCHAR *output, ULONG size )
389 {
390 pgnutls_hash_deinit( hash->handle, output );
391 return STATUS_SUCCESS;
392 }
393 #else
394 struct hash
395 {
396 struct object hdr;
397 enum alg_id alg_id;
398 };
399
400 static NTSTATUS hash_init( struct hash *hash )
401 {
402 ERR( "support for hashes not available at build time\n" );
403 return STATUS_NOT_IMPLEMENTED;
404 }
405
406 static NTSTATUS hash_update( struct hash *hash, UCHAR *input, ULONG size )
407 {
408 ERR( "support for hashes not available at build time\n" );
409 return STATUS_NOT_IMPLEMENTED;
410 }
411
412 static NTSTATUS hash_finish( struct hash *hash, UCHAR *output, ULONG size )
413 {
414 ERR( "support for hashes not available at build time\n" );
415 return STATUS_NOT_IMPLEMENTED;
416 }
417 #endif
418
419 #define OBJECT_LENGTH_SHA1 278
420 #define OBJECT_LENGTH_SHA256 286
421 #define OBJECT_LENGTH_SHA384 382
422 #define OBJECT_LENGTH_SHA512 382
423
424 static NTSTATUS generic_alg_property( enum alg_id id, const WCHAR *prop, UCHAR *buf, ULONG size, ULONG *ret_size )
425 {
426 if (!strcmpW( prop, BCRYPT_HASH_LENGTH ))
427 {
428 *ret_size = sizeof(ULONG);
429 if (size < sizeof(ULONG))
430 return STATUS_BUFFER_TOO_SMALL;
431 if(buf)
432 *(ULONG*)buf = alg_props[id].hash_length;
433 return STATUS_SUCCESS;
434 }
435
436 if (!strcmpW( prop, BCRYPT_ALGORITHM_NAME ))
437 {
438 *ret_size = (strlenW(alg_props[id].alg_name)+1)*sizeof(WCHAR);
439 if (size < *ret_size)
440 return STATUS_BUFFER_TOO_SMALL;
441 if(buf)
442 memcpy(buf, alg_props[id].alg_name, *ret_size);
443 return STATUS_SUCCESS;
444 }
445
446 return STATUS_NOT_IMPLEMENTED;
447 }
448
449 static NTSTATUS get_alg_property( enum alg_id id, const WCHAR *prop, UCHAR *buf, ULONG size, ULONG *ret_size )
450 {
451 NTSTATUS status;
452 ULONG value;
453
454 status = generic_alg_property( id, prop, buf, size, ret_size );
455 if (status != STATUS_NOT_IMPLEMENTED)
456 return status;
457
458 switch (id)
459 {
460 case ALG_ID_SHA1:
461 if (!strcmpW( prop, BCRYPT_OBJECT_LENGTH ))
462 {
463 value = OBJECT_LENGTH_SHA1;
464 break;
465 }
466 FIXME( "unsupported sha1 algorithm property %s\n", debugstr_w(prop) );
467 return STATUS_NOT_IMPLEMENTED;
468
469 case ALG_ID_SHA256:
470 if (!strcmpW( prop, BCRYPT_OBJECT_LENGTH ))
471 {
472 value = OBJECT_LENGTH_SHA256;
473 break;
474 }
475 FIXME( "unsupported sha256 algorithm property %s\n", debugstr_w(prop) );
476 return STATUS_NOT_IMPLEMENTED;
477
478 case ALG_ID_SHA384:
479 if (!strcmpW( prop, BCRYPT_OBJECT_LENGTH ))
480 {
481 value = OBJECT_LENGTH_SHA384;
482 break;
483 }
484 FIXME( "unsupported sha384 algorithm property %s\n", debugstr_w(prop) );
485 return STATUS_NOT_IMPLEMENTED;
486
487 case ALG_ID_SHA512:
488 if (!strcmpW( prop, BCRYPT_OBJECT_LENGTH ))
489 {
490 value = OBJECT_LENGTH_SHA512;
491 break;
492 }
493 FIXME( "unsupported sha512 algorithm property %s\n", debugstr_w(prop) );
494 return STATUS_NOT_IMPLEMENTED;
495
496 default:
497 FIXME( "unsupported algorithm %u\n", id );
498 return STATUS_NOT_IMPLEMENTED;
499 }
500
501 if (size < sizeof(ULONG))
502 {
503 *ret_size = sizeof(ULONG);
504 return STATUS_BUFFER_TOO_SMALL;
505 }
506 if (buf) *(ULONG *)buf = value;
507 *ret_size = sizeof(ULONG);
508
509 return STATUS_SUCCESS;
510 }
511
512 static NTSTATUS get_hash_property( enum alg_id id, const WCHAR *prop, UCHAR *buf, ULONG size, ULONG *ret_size )
513 {
514 NTSTATUS status;
515
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) );
519 return status;
520 }
521
522 NTSTATUS WINAPI BCryptGetProperty( BCRYPT_HANDLE handle, LPCWSTR prop, UCHAR *buffer, ULONG count, ULONG *res, ULONG flags )
523 {
524 struct object *object = handle;
525
526 TRACE( "%p, %s, %p, %u, %p, %08x\n", handle, wine_dbgstr_w(prop), buffer, count, res, flags );
527
528 if (!object) return STATUS_INVALID_HANDLE;
529 if (!prop || !res) return STATUS_INVALID_PARAMETER;
530
531 switch (object->magic)
532 {
533 case MAGIC_ALG:
534 {
535 const struct algorithm *alg = (const struct algorithm *)object;
536 return get_alg_property( alg->id, prop, buffer, count, res );
537 }
538 case MAGIC_HASH:
539 {
540 const struct hash *hash = (const struct hash *)object;
541 return get_hash_property( hash->alg_id, prop, buffer, count, res );
542 }
543 default:
544 WARN( "unknown magic %08x\n", object->magic );
545 return STATUS_INVALID_HANDLE;
546 }
547 }
548
549 NTSTATUS WINAPI BCryptCreateHash( BCRYPT_ALG_HANDLE algorithm, BCRYPT_HASH_HANDLE *handle, UCHAR *object, ULONG objectlen,
550 UCHAR *secret, ULONG secretlen, ULONG flags )
551 {
552 struct algorithm *alg = algorithm;
553 struct hash *hash;
554 NTSTATUS status;
555
556 TRACE( "%p, %p, %p, %u, %p, %u, %08x - stub\n", algorithm, handle, object, objectlen,
557 secret, secretlen, flags );
558 if (flags)
559 {
560 FIXME( "unimplemented flags %08x\n", flags );
561 return STATUS_NOT_IMPLEMENTED;
562 }
563
564 if (!alg || alg->hdr.magic != MAGIC_ALG) return STATUS_INVALID_HANDLE;
565 if (object) FIXME( "ignoring object buffer\n" );
566
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)
571 {
572 HeapFree( GetProcessHeap(), 0, hash );
573 return status;
574 }
575
576 *handle = hash;
577 return STATUS_SUCCESS;
578 }
579
580 NTSTATUS WINAPI BCryptDestroyHash( BCRYPT_HASH_HANDLE handle )
581 {
582 struct hash *hash = handle;
583
584 TRACE( "%p\n", handle );
585
586 if (!hash || hash->hdr.magic != MAGIC_HASH) return STATUS_INVALID_HANDLE;
587 HeapFree( GetProcessHeap(), 0, hash );
588 return STATUS_SUCCESS;
589 }
590
591 NTSTATUS WINAPI BCryptHashData( BCRYPT_HASH_HANDLE handle, UCHAR *input, ULONG size, ULONG flags )
592 {
593 struct hash *hash = handle;
594
595 TRACE( "%p, %p, %u, %08x\n", handle, input, size, flags );
596
597 if (!hash || hash->hdr.magic != MAGIC_HASH) return STATUS_INVALID_HANDLE;
598 if (!input) return STATUS_INVALID_PARAMETER;
599
600 return hash_update( hash, input, size );
601 }
602
603 NTSTATUS WINAPI BCryptFinishHash( BCRYPT_HASH_HANDLE handle, UCHAR *output, ULONG size, ULONG flags )
604 {
605 struct hash *hash = handle;
606
607 TRACE( "%p, %p, %u, %08x\n", handle, output, size, flags );
608
609 if (!hash || hash->hdr.magic != MAGIC_HASH) return STATUS_INVALID_HANDLE;
610 if (!output) return STATUS_INVALID_PARAMETER;
611
612 return hash_finish( hash, output, size );
613 }
614
615 BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
616 {
617 switch (reason)
618 {
619 case DLL_PROCESS_ATTACH:
620 instance = hinst;
621 DisableThreadLibraryCalls( hinst );
622 #if defined(HAVE_GNUTLS_HASH) && !defined(HAVE_COMMONCRYPTO_COMMONDIGEST_H)
623 gnutls_initialize();
624 #endif
625 break;
626
627 case DLL_PROCESS_DETACH:
628 if (reserved) break;
629 #if defined(HAVE_GNUTLS_HASH) && !defined(HAVE_COMMONCRYPTO_COMMONDIGEST_H)
630 gnutls_uninitialize();
631 #endif
632 break;
633 }
634 return TRUE;
635 }