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_COMMONCRYPTOR_H
25 #include <CommonCrypto/CommonCryptor.h>
26 #elif defined(SONAME_LIBGNUTLS)
27 #include <gnutls/gnutls.h>
28 #include <gnutls/crypto.h>
32 #define WIN32_NO_STATUS
38 #include "bcrypt_internal.h"
40 #include "wine/debug.h"
41 #include "wine/library.h"
42 #include "wine/unicode.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(bcrypt
);
46 static HINSTANCE instance
;
48 #if defined(HAVE_GNUTLS_CIPHER_INIT) && !defined(HAVE_COMMONCRYPTO_COMMONCRYPTOR_H)
49 WINE_DECLARE_DEBUG_CHANNEL(winediag
);
51 static void *libgnutls_handle
;
52 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
53 MAKE_FUNCPTR(gnutls_cipher_decrypt2
);
54 MAKE_FUNCPTR(gnutls_cipher_deinit
);
55 MAKE_FUNCPTR(gnutls_cipher_encrypt2
);
56 MAKE_FUNCPTR(gnutls_cipher_init
);
57 MAKE_FUNCPTR(gnutls_global_deinit
);
58 MAKE_FUNCPTR(gnutls_global_init
);
59 MAKE_FUNCPTR(gnutls_global_set_log_function
);
60 MAKE_FUNCPTR(gnutls_global_set_log_level
);
61 MAKE_FUNCPTR(gnutls_perror
);
64 static void gnutls_log( int level
, const char *msg
)
66 TRACE( "<%d> %s", level
, msg
);
69 static BOOL
gnutls_initialize(void)
73 if (!(libgnutls_handle
= wine_dlopen( SONAME_LIBGNUTLS
, RTLD_NOW
, NULL
, 0 )))
75 ERR_(winediag
)( "failed to load libgnutls, no support for encryption\n" );
79 #define LOAD_FUNCPTR(f) \
80 if (!(p##f = wine_dlsym( libgnutls_handle, #f, NULL, 0 ))) \
82 ERR( "failed to load %s\n", #f ); \
86 LOAD_FUNCPTR(gnutls_cipher_decrypt2
)
87 LOAD_FUNCPTR(gnutls_cipher_deinit
)
88 LOAD_FUNCPTR(gnutls_cipher_encrypt2
)
89 LOAD_FUNCPTR(gnutls_cipher_init
)
90 LOAD_FUNCPTR(gnutls_global_deinit
)
91 LOAD_FUNCPTR(gnutls_global_init
)
92 LOAD_FUNCPTR(gnutls_global_set_log_function
)
93 LOAD_FUNCPTR(gnutls_global_set_log_level
)
94 LOAD_FUNCPTR(gnutls_perror
)
97 if ((ret
= pgnutls_global_init()) != GNUTLS_E_SUCCESS
)
99 pgnutls_perror( ret
);
103 if (TRACE_ON( bcrypt
))
105 pgnutls_global_set_log_level( 4 );
106 pgnutls_global_set_log_function( gnutls_log
);
112 wine_dlclose( libgnutls_handle
, NULL
, 0 );
113 libgnutls_handle
= NULL
;
117 static void gnutls_uninitialize(void)
119 pgnutls_global_deinit();
120 wine_dlclose( libgnutls_handle
, NULL
, 0 );
121 libgnutls_handle
= NULL
;
123 #endif /* HAVE_GNUTLS_CIPHER_INIT && !HAVE_COMMONCRYPTO_COMMONCRYPTOR_H */
125 NTSTATUS WINAPI
BCryptAddContextFunction(ULONG table
, LPCWSTR context
, ULONG iface
, LPCWSTR function
, ULONG pos
)
127 FIXME("%08x, %s, %08x, %s, %u: stub\n", table
, debugstr_w(context
), iface
, debugstr_w(function
), pos
);
128 return STATUS_SUCCESS
;
131 NTSTATUS WINAPI
BCryptAddContextFunctionProvider(ULONG table
, LPCWSTR context
, ULONG iface
, LPCWSTR function
, LPCWSTR provider
, ULONG pos
)
133 FIXME("%08x, %s, %08x, %s, %s, %u: stub\n", table
, debugstr_w(context
), iface
, debugstr_w(function
), debugstr_w(provider
), pos
);
134 return STATUS_SUCCESS
;
137 NTSTATUS WINAPI
BCryptRemoveContextFunction(ULONG table
, LPCWSTR context
, ULONG iface
, LPCWSTR function
)
139 FIXME("%08x, %s, %08x, %s: stub\n", table
, debugstr_w(context
), iface
, debugstr_w(function
));
140 return STATUS_NOT_IMPLEMENTED
;
143 NTSTATUS WINAPI
BCryptRemoveContextFunctionProvider(ULONG table
, LPCWSTR context
, ULONG iface
, LPCWSTR function
, LPCWSTR provider
)
145 FIXME("%08x, %s, %08x, %s, %s: stub\n", table
, debugstr_w(context
), iface
, debugstr_w(function
), debugstr_w(provider
));
146 return STATUS_NOT_IMPLEMENTED
;
149 NTSTATUS WINAPI
BCryptRegisterProvider(LPCWSTR provider
, ULONG flags
, PCRYPT_PROVIDER_REG reg
)
151 FIXME("%s, %08x, %p: stub\n", debugstr_w(provider
), flags
, reg
);
152 return STATUS_SUCCESS
;
155 NTSTATUS WINAPI
BCryptUnregisterProvider(LPCWSTR provider
)
157 FIXME("%s: stub\n", debugstr_w(provider
));
158 return STATUS_NOT_IMPLEMENTED
;
161 NTSTATUS WINAPI
BCryptEnumAlgorithms(ULONG dwAlgOperations
, ULONG
*pAlgCount
,
162 BCRYPT_ALGORITHM_IDENTIFIER
**ppAlgList
, ULONG dwFlags
)
164 FIXME("%08x, %p, %p, %08x - stub\n", dwAlgOperations
, pAlgCount
, ppAlgList
, dwFlags
);
169 return STATUS_NOT_IMPLEMENTED
;
172 #define MAGIC_ALG (('A' << 24) | ('L' << 16) | ('G' << 8) | '0')
173 #define MAGIC_HASH (('H' << 24) | ('A' << 16) | ('S' << 8) | 'H')
174 #define MAGIC_KEY (('K' << 24) | ('E' << 16) | ('Y' << 8) | '0')
193 #define MAX_HASH_OUTPUT_BYTES 64
194 #define MAX_HASH_BLOCK_BITS 1024
196 static const struct {
200 const WCHAR
*alg_name
;
202 /* ALG_ID_AES */ { 654, 0, 0, BCRYPT_AES_ALGORITHM
},
203 /* ALG_ID_MD2 */ { 270, 16, 128, BCRYPT_MD2_ALGORITHM
},
204 /* ALG_ID_MD4 */ { 270, 16, 512, BCRYPT_MD4_ALGORITHM
},
205 /* ALG_ID_MD5 */ { 274, 16, 512, BCRYPT_MD5_ALGORITHM
},
206 /* ALG_ID_RNG */ { 0, 0, 0, BCRYPT_RNG_ALGORITHM
},
207 /* ALG_ID_SHA1 */ { 278, 20, 512, BCRYPT_SHA1_ALGORITHM
},
208 /* ALG_ID_SHA256 */ { 286, 32, 512, BCRYPT_SHA256_ALGORITHM
},
209 /* ALG_ID_SHA384 */ { 382, 48, 1024, BCRYPT_SHA384_ALGORITHM
},
210 /* ALG_ID_SHA512 */ { 382, 64, 1024, BCRYPT_SHA512_ALGORITHM
}
220 NTSTATUS WINAPI
BCryptGenRandom(BCRYPT_ALG_HANDLE handle
, UCHAR
*buffer
, ULONG count
, ULONG flags
)
222 const DWORD supported_flags
= BCRYPT_USE_SYSTEM_PREFERRED_RNG
;
223 struct algorithm
*algorithm
= handle
;
225 TRACE("%p, %p, %u, %08x - semi-stub\n", handle
, buffer
, count
, flags
);
229 /* It's valid to call without an algorithm if BCRYPT_USE_SYSTEM_PREFERRED_RNG
230 * is set. In this case the preferred system RNG is used.
232 if (!(flags
& BCRYPT_USE_SYSTEM_PREFERRED_RNG
))
233 return STATUS_INVALID_HANDLE
;
235 else if (algorithm
->hdr
.magic
!= MAGIC_ALG
|| algorithm
->id
!= ALG_ID_RNG
)
236 return STATUS_INVALID_HANDLE
;
239 return STATUS_INVALID_PARAMETER
;
241 if (flags
& ~supported_flags
)
242 FIXME("unsupported flags %08x\n", flags
& ~supported_flags
);
245 FIXME("ignoring selected algorithm\n");
247 /* When zero bytes are requested the function returns success too. */
249 return STATUS_SUCCESS
;
251 if (algorithm
|| (flags
& BCRYPT_USE_SYSTEM_PREFERRED_RNG
))
253 if (RtlGenRandom(buffer
, count
))
254 return STATUS_SUCCESS
;
257 FIXME("called with unsupported parameters, returning error\n");
258 return STATUS_NOT_IMPLEMENTED
;
261 NTSTATUS WINAPI
BCryptOpenAlgorithmProvider( BCRYPT_ALG_HANDLE
*handle
, LPCWSTR id
, LPCWSTR implementation
, DWORD flags
)
263 const DWORD supported_flags
= BCRYPT_ALG_HANDLE_HMAC_FLAG
;
264 struct algorithm
*alg
;
267 TRACE( "%p, %s, %s, %08x\n", handle
, wine_dbgstr_w(id
), wine_dbgstr_w(implementation
), flags
);
269 if (!handle
|| !id
) return STATUS_INVALID_PARAMETER
;
270 if (flags
& ~supported_flags
)
272 FIXME( "unsupported flags %08x\n", flags
& ~supported_flags
);
273 return STATUS_NOT_IMPLEMENTED
;
276 if (!strcmpW( id
, BCRYPT_AES_ALGORITHM
)) alg_id
= ALG_ID_AES
;
277 else if (!strcmpW( id
, BCRYPT_MD2_ALGORITHM
)) alg_id
= ALG_ID_MD2
;
278 else if (!strcmpW( id
, BCRYPT_MD4_ALGORITHM
)) alg_id
= ALG_ID_MD4
;
279 else if (!strcmpW( id
, BCRYPT_MD5_ALGORITHM
)) alg_id
= ALG_ID_MD5
;
280 else if (!strcmpW( id
, BCRYPT_RNG_ALGORITHM
)) alg_id
= ALG_ID_RNG
;
281 else if (!strcmpW( id
, BCRYPT_SHA1_ALGORITHM
)) alg_id
= ALG_ID_SHA1
;
282 else if (!strcmpW( id
, BCRYPT_SHA256_ALGORITHM
)) alg_id
= ALG_ID_SHA256
;
283 else if (!strcmpW( id
, BCRYPT_SHA384_ALGORITHM
)) alg_id
= ALG_ID_SHA384
;
284 else if (!strcmpW( id
, BCRYPT_SHA512_ALGORITHM
)) alg_id
= ALG_ID_SHA512
;
287 FIXME( "algorithm %s not supported\n", debugstr_w(id
) );
288 return STATUS_NOT_IMPLEMENTED
;
290 if (implementation
&& strcmpW( implementation
, MS_PRIMITIVE_PROVIDER
))
292 FIXME( "implementation %s not supported\n", debugstr_w(implementation
) );
293 return STATUS_NOT_IMPLEMENTED
;
296 if (!(alg
= HeapAlloc( GetProcessHeap(), 0, sizeof(*alg
) ))) return STATUS_NO_MEMORY
;
297 alg
->hdr
.magic
= MAGIC_ALG
;
299 alg
->hmac
= flags
& BCRYPT_ALG_HANDLE_HMAC_FLAG
;
302 return STATUS_SUCCESS
;
305 NTSTATUS WINAPI
BCryptCloseAlgorithmProvider( BCRYPT_ALG_HANDLE handle
, DWORD flags
)
307 struct algorithm
*alg
= handle
;
309 TRACE( "%p, %08x\n", handle
, flags
);
311 if (!alg
|| alg
->hdr
.magic
!= MAGIC_ALG
) return STATUS_INVALID_HANDLE
;
312 HeapFree( GetProcessHeap(), 0, alg
);
313 return STATUS_SUCCESS
;
316 NTSTATUS WINAPI
BCryptGetFipsAlgorithmMode(BOOLEAN
*enabled
)
318 FIXME("%p - semi-stub\n", enabled
);
321 return STATUS_INVALID_PARAMETER
;
324 return STATUS_SUCCESS
;
340 static NTSTATUS
hash_init( struct hash_impl
*hash
, enum alg_id alg_id
)
345 md2_init( &hash
->u
.md2
);
349 MD4Init( &hash
->u
.md4
);
353 MD5Init( &hash
->u
.md5
);
357 A_SHAInit( &hash
->u
.sha1
);
361 sha256_init( &hash
->u
.sha256
);
365 sha384_init( &hash
->u
.sha512
);
369 sha512_init( &hash
->u
.sha512
);
373 ERR( "unhandled id %u\n", alg_id
);
374 return STATUS_NOT_IMPLEMENTED
;
376 return STATUS_SUCCESS
;
379 static NTSTATUS
hash_update( struct hash_impl
*hash
, enum alg_id alg_id
,
380 UCHAR
*input
, ULONG size
)
385 md2_update( &hash
->u
.md2
, input
, size
);
389 MD4Update( &hash
->u
.md4
, input
, size
);
393 MD5Update( &hash
->u
.md5
, input
, size
);
397 A_SHAUpdate( &hash
->u
.sha1
, input
, size
);
401 sha256_update( &hash
->u
.sha256
, input
, size
);
405 sha384_update( &hash
->u
.sha512
, input
, size
);
409 sha512_update( &hash
->u
.sha512
, input
, size
);
413 ERR( "unhandled id %u\n", alg_id
);
414 return STATUS_NOT_IMPLEMENTED
;
416 return STATUS_SUCCESS
;
419 static NTSTATUS
hash_finish( struct hash_impl
*hash
, enum alg_id alg_id
,
420 UCHAR
*output
, ULONG size
)
425 md2_finalize( &hash
->u
.md2
, output
);
429 MD4Final( &hash
->u
.md4
);
430 memcpy( output
, hash
->u
.md4
.digest
, 16 );
434 MD5Final( &hash
->u
.md5
);
435 memcpy( output
, hash
->u
.md5
.digest
, 16 );
439 A_SHAFinal( &hash
->u
.sha1
, (ULONG
*)output
);
443 sha256_finalize( &hash
->u
.sha256
, output
);
447 sha384_finalize( &hash
->u
.sha512
, output
);
451 sha512_finalize( &hash
->u
.sha512
, output
);
455 ERR( "unhandled id %u\n", alg_id
);
456 return STATUS_NOT_IMPLEMENTED
;
458 return STATUS_SUCCESS
;
466 struct hash_impl outer
;
467 struct hash_impl inner
;
470 #define BLOCK_LENGTH_AES 16
472 static NTSTATUS
generic_alg_property( enum alg_id id
, const WCHAR
*prop
, UCHAR
*buf
, ULONG size
, ULONG
*ret_size
)
474 if (!strcmpW( prop
, BCRYPT_OBJECT_LENGTH
))
476 if (!alg_props
[id
].object_length
)
477 return STATUS_NOT_SUPPORTED
;
478 *ret_size
= sizeof(ULONG
);
479 if (size
< sizeof(ULONG
))
480 return STATUS_BUFFER_TOO_SMALL
;
482 *(ULONG
*)buf
= alg_props
[id
].object_length
;
483 return STATUS_SUCCESS
;
486 if (!strcmpW( prop
, BCRYPT_HASH_LENGTH
))
488 if (!alg_props
[id
].hash_length
)
489 return STATUS_NOT_SUPPORTED
;
490 *ret_size
= sizeof(ULONG
);
491 if (size
< sizeof(ULONG
))
492 return STATUS_BUFFER_TOO_SMALL
;
494 *(ULONG
*)buf
= alg_props
[id
].hash_length
;
495 return STATUS_SUCCESS
;
498 if (!strcmpW( prop
, BCRYPT_ALGORITHM_NAME
))
500 *ret_size
= (strlenW(alg_props
[id
].alg_name
)+1)*sizeof(WCHAR
);
501 if (size
< *ret_size
)
502 return STATUS_BUFFER_TOO_SMALL
;
504 memcpy(buf
, alg_props
[id
].alg_name
, *ret_size
);
505 return STATUS_SUCCESS
;
508 return STATUS_NOT_IMPLEMENTED
;
511 static NTSTATUS
get_alg_property( enum alg_id id
, const WCHAR
*prop
, UCHAR
*buf
, ULONG size
, ULONG
*ret_size
)
515 status
= generic_alg_property( id
, prop
, buf
, size
, ret_size
);
516 if (status
!= STATUS_NOT_IMPLEMENTED
)
522 if (!strcmpW( prop
, BCRYPT_BLOCK_LENGTH
))
524 *ret_size
= sizeof(ULONG
);
525 if (size
< sizeof(ULONG
))
526 return STATUS_BUFFER_TOO_SMALL
;
528 *(ULONG
*)buf
= BLOCK_LENGTH_AES
;
529 return STATUS_SUCCESS
;
531 if (!strcmpW( prop
, BCRYPT_CHAINING_MODE
))
533 if (size
>= sizeof(BCRYPT_CHAIN_MODE_CBC
))
535 memcpy(buf
, BCRYPT_CHAIN_MODE_CBC
, sizeof(BCRYPT_CHAIN_MODE_CBC
));
536 *ret_size
= sizeof(BCRYPT_CHAIN_MODE_CBC
) * sizeof(WCHAR
);
537 return STATUS_SUCCESS
;
541 *ret_size
= sizeof(BCRYPT_CHAIN_MODE_CBC
) * sizeof(WCHAR
);
542 return STATUS_BUFFER_TOO_SMALL
;
545 if (!strcmpW( prop
, BCRYPT_KEY_LENGTHS
))
547 BCRYPT_KEY_LENGTHS_STRUCT
*key_lengths
= (void *)buf
;
548 *ret_size
= sizeof(*key_lengths
);
549 if (key_lengths
&& size
< *ret_size
) return STATUS_BUFFER_TOO_SMALL
;
552 key_lengths
->dwMinLength
= 128;
553 key_lengths
->dwMaxLength
= 256;
554 key_lengths
->dwIncrement
= 64;
556 return STATUS_SUCCESS
;
564 FIXME( "unsupported property %s\n", debugstr_w(prop
) );
565 return STATUS_NOT_IMPLEMENTED
;
568 static NTSTATUS
get_hash_property( enum alg_id id
, const WCHAR
*prop
, UCHAR
*buf
, ULONG size
, ULONG
*ret_size
)
572 status
= generic_alg_property( id
, prop
, buf
, size
, ret_size
);
573 if (status
== STATUS_NOT_IMPLEMENTED
)
574 FIXME( "unsupported property %s\n", debugstr_w(prop
) );
578 NTSTATUS WINAPI
BCryptGetProperty( BCRYPT_HANDLE handle
, LPCWSTR prop
, UCHAR
*buffer
, ULONG count
, ULONG
*res
, ULONG flags
)
580 struct object
*object
= handle
;
582 TRACE( "%p, %s, %p, %u, %p, %08x\n", handle
, wine_dbgstr_w(prop
), buffer
, count
, res
, flags
);
584 if (!object
) return STATUS_INVALID_HANDLE
;
585 if (!prop
|| !res
) return STATUS_INVALID_PARAMETER
;
587 switch (object
->magic
)
591 const struct algorithm
*alg
= (const struct algorithm
*)object
;
592 return get_alg_property( alg
->id
, prop
, buffer
, count
, res
);
596 const struct hash
*hash
= (const struct hash
*)object
;
597 return get_hash_property( hash
->alg_id
, prop
, buffer
, count
, res
);
600 WARN( "unknown magic %08x\n", object
->magic
);
601 return STATUS_INVALID_HANDLE
;
605 NTSTATUS WINAPI
BCryptSetProperty( BCRYPT_HANDLE handle
, const WCHAR
*prop
, UCHAR
*value
, ULONG size
, ULONG flags
)
607 FIXME( "%p, %s, %p, %u, %08x\n", handle
, debugstr_w(prop
), value
, size
, flags
);
608 return STATUS_NOT_IMPLEMENTED
;
611 NTSTATUS WINAPI
BCryptCreateHash( BCRYPT_ALG_HANDLE algorithm
, BCRYPT_HASH_HANDLE
*handle
, UCHAR
*object
, ULONG objectlen
,
612 UCHAR
*secret
, ULONG secretlen
, ULONG flags
)
614 struct algorithm
*alg
= algorithm
;
615 UCHAR buffer
[MAX_HASH_BLOCK_BITS
/ 8] = {0};
621 TRACE( "%p, %p, %p, %u, %p, %u, %08x - stub\n", algorithm
, handle
, object
, objectlen
,
622 secret
, secretlen
, flags
);
625 FIXME( "unimplemented flags %08x\n", flags
);
626 return STATUS_NOT_IMPLEMENTED
;
629 if (!alg
|| alg
->hdr
.magic
!= MAGIC_ALG
) return STATUS_INVALID_HANDLE
;
630 if (object
) FIXME( "ignoring object buffer\n" );
632 if (!(hash
= HeapAlloc( GetProcessHeap(), 0, sizeof(*hash
) ))) return STATUS_NO_MEMORY
;
633 hash
->hdr
.magic
= MAGIC_HASH
;
634 hash
->alg_id
= alg
->id
;
635 hash
->hmac
= alg
->hmac
;
637 /* initialize hash */
638 if ((status
= hash_init( &hash
->inner
, hash
->alg_id
))) goto end
;
639 if (!hash
->hmac
) goto end
;
641 /* initialize hmac */
642 if ((status
= hash_init( &hash
->outer
, hash
->alg_id
))) goto end
;
643 block_bytes
= alg_props
[hash
->alg_id
].block_bits
/ 8;
644 if (secretlen
> block_bytes
)
646 struct hash_impl temp
;
647 if ((status
= hash_init( &temp
, hash
->alg_id
))) goto end
;
648 if ((status
= hash_update( &temp
, hash
->alg_id
, secret
, secretlen
))) goto end
;
649 if ((status
= hash_finish( &temp
, hash
->alg_id
, buffer
,
650 alg_props
[hash
->alg_id
].hash_length
))) goto end
;
654 memcpy( buffer
, secret
, secretlen
);
656 for (i
= 0; i
< block_bytes
; i
++) buffer
[i
] ^= 0x5c;
657 if ((status
= hash_update( &hash
->outer
, hash
->alg_id
, buffer
, block_bytes
))) goto end
;
658 for (i
= 0; i
< block_bytes
; i
++) buffer
[i
] ^= (0x5c ^ 0x36);
659 status
= hash_update( &hash
->inner
, hash
->alg_id
, buffer
, block_bytes
);
662 if (status
!= STATUS_SUCCESS
)
664 HeapFree( GetProcessHeap(), 0, hash
);
669 return STATUS_SUCCESS
;
672 NTSTATUS WINAPI
BCryptDuplicateHash( BCRYPT_HASH_HANDLE handle
, BCRYPT_HASH_HANDLE
*handle_copy
,
673 UCHAR
*object
, ULONG objectlen
, ULONG flags
)
675 struct hash
*hash_orig
= handle
;
676 struct hash
*hash_copy
;
678 TRACE( "%p, %p, %p, %u, %u\n", handle
, handle_copy
, object
, objectlen
, flags
);
680 if (!hash_orig
|| hash_orig
->hdr
.magic
!= MAGIC_HASH
) return STATUS_INVALID_HANDLE
;
681 if (!handle_copy
) return STATUS_INVALID_PARAMETER
;
682 if (object
) FIXME( "ignoring object buffer\n" );
684 if (!(hash_copy
= HeapAlloc( GetProcessHeap(), 0, sizeof(*hash_copy
) )))
685 return STATUS_NO_MEMORY
;
687 memcpy( hash_copy
, hash_orig
, sizeof(*hash_orig
) );
689 *handle_copy
= hash_copy
;
690 return STATUS_SUCCESS
;
693 NTSTATUS WINAPI
BCryptDestroyHash( BCRYPT_HASH_HANDLE handle
)
695 struct hash
*hash
= handle
;
697 TRACE( "%p\n", handle
);
699 if (!hash
|| hash
->hdr
.magic
!= MAGIC_HASH
) return STATUS_INVALID_HANDLE
;
700 HeapFree( GetProcessHeap(), 0, hash
);
701 return STATUS_SUCCESS
;
704 NTSTATUS WINAPI
BCryptHashData( BCRYPT_HASH_HANDLE handle
, UCHAR
*input
, ULONG size
, ULONG flags
)
706 struct hash
*hash
= handle
;
708 TRACE( "%p, %p, %u, %08x\n", handle
, input
, size
, flags
);
710 if (!hash
|| hash
->hdr
.magic
!= MAGIC_HASH
) return STATUS_INVALID_HANDLE
;
711 if (!input
) return STATUS_SUCCESS
;
713 return hash_update( &hash
->inner
, hash
->alg_id
, input
, size
);
716 NTSTATUS WINAPI
BCryptFinishHash( BCRYPT_HASH_HANDLE handle
, UCHAR
*output
, ULONG size
, ULONG flags
)
718 UCHAR buffer
[MAX_HASH_OUTPUT_BYTES
];
719 struct hash
*hash
= handle
;
723 TRACE( "%p, %p, %u, %08x\n", handle
, output
, size
, flags
);
725 if (!hash
|| hash
->hdr
.magic
!= MAGIC_HASH
) return STATUS_INVALID_HANDLE
;
726 if (!output
) return STATUS_INVALID_PARAMETER
;
729 return hash_finish( &hash
->inner
, hash
->alg_id
, output
, size
);
731 hash_length
= alg_props
[hash
->alg_id
].hash_length
;
732 if ((status
= hash_finish( &hash
->inner
, hash
->alg_id
, buffer
, hash_length
))) return status
;
733 if ((status
= hash_update( &hash
->outer
, hash
->alg_id
, buffer
, hash_length
))) return status
;
734 return hash_finish( &hash
->outer
, hash
->alg_id
, output
, size
);
737 NTSTATUS WINAPI
BCryptHash( BCRYPT_ALG_HANDLE algorithm
, UCHAR
*secret
, ULONG secretlen
,
738 UCHAR
*input
, ULONG inputlen
, UCHAR
*output
, ULONG outputlen
)
741 BCRYPT_HASH_HANDLE handle
;
743 TRACE( "%p, %p, %u, %p, %u, %p, %u\n", algorithm
, secret
, secretlen
,
744 input
, inputlen
, output
, outputlen
);
746 status
= BCryptCreateHash( algorithm
, &handle
, NULL
, 0, secret
, secretlen
, 0);
747 if (status
!= STATUS_SUCCESS
)
752 status
= BCryptHashData( handle
, input
, inputlen
, 0 );
753 if (status
!= STATUS_SUCCESS
)
755 BCryptDestroyHash( handle
);
759 status
= BCryptFinishHash( handle
, output
, outputlen
, 0 );
760 if (status
!= STATUS_SUCCESS
)
762 BCryptDestroyHash( handle
);
766 return BCryptDestroyHash( handle
);
769 #if defined(HAVE_GNUTLS_CIPHER_INIT) || defined(HAVE_COMMONCRYPTO_COMMONCRYPTOR_H)
770 static ULONG
get_block_size( enum alg_id alg
)
772 ULONG ret
= 0, size
= sizeof(ret
);
773 get_alg_property( alg
, BCRYPT_BLOCK_LENGTH
, (UCHAR
*)&ret
, sizeof(ret
), &size
);
778 #if defined(HAVE_GNUTLS_CIPHER_INIT) && !defined(HAVE_COMMONCRYPTO_COMMONCRYPTOR_H)
784 gnutls_cipher_hd_t handle
;
789 static NTSTATUS
key_init( struct key
*key
, enum alg_id id
, const UCHAR
*secret
, ULONG secret_len
)
793 if (!libgnutls_handle
) return STATUS_INTERNAL_ERROR
;
801 FIXME( "algorithm %u not supported\n", id
);
802 return STATUS_NOT_SUPPORTED
;
805 if (!(key
->block_size
= get_block_size( id
))) return STATUS_INVALID_PARAMETER
;
806 if (!(buffer
= HeapAlloc( GetProcessHeap(), 0, secret_len
))) return STATUS_NO_MEMORY
;
807 memcpy( buffer
, secret
, secret_len
);
810 key
->handle
= 0; /* initialized on first use */
811 key
->secret
= buffer
;
812 key
->secret_len
= secret_len
;
814 return STATUS_SUCCESS
;
817 static gnutls_cipher_algorithm_t
get_gnutls_cipher( const struct key
*key
)
822 FIXME( "handle block size and chaining mode\n" );
823 return GNUTLS_CIPHER_AES_128_CBC
;
826 FIXME( "algorithm %u not supported\n", key
->alg_id
);
827 return GNUTLS_CIPHER_UNKNOWN
;
831 static NTSTATUS
key_set_params( struct key
*key
, UCHAR
*iv
, ULONG iv_len
)
833 gnutls_cipher_algorithm_t cipher
;
834 gnutls_datum_t secret
, vector
;
839 pgnutls_cipher_deinit( key
->handle
);
843 if ((cipher
= get_gnutls_cipher( key
)) == GNUTLS_CIPHER_UNKNOWN
)
844 return STATUS_NOT_SUPPORTED
;
846 secret
.data
= key
->secret
;
847 secret
.size
= key
->secret_len
;
851 vector
.size
= iv_len
;
854 if ((ret
= pgnutls_cipher_init( &key
->handle
, cipher
, &secret
, iv
? &vector
: NULL
)))
856 pgnutls_perror( ret
);
857 return STATUS_INTERNAL_ERROR
;
860 return STATUS_SUCCESS
;
863 static NTSTATUS
key_encrypt( struct key
*key
, const UCHAR
*input
, ULONG input_len
, UCHAR
*output
,
868 if ((ret
= pgnutls_cipher_encrypt2( key
->handle
, input
, input_len
, output
, output_len
)))
870 pgnutls_perror( ret
);
871 return STATUS_INTERNAL_ERROR
;
874 return STATUS_SUCCESS
;
877 static NTSTATUS
key_decrypt( struct key
*key
, const UCHAR
*input
, ULONG input_len
, UCHAR
*output
,
882 if ((ret
= pgnutls_cipher_decrypt2( key
->handle
, input
, input_len
, output
, output_len
)))
884 pgnutls_perror( ret
);
885 return STATUS_INTERNAL_ERROR
;
888 return STATUS_SUCCESS
;
891 static NTSTATUS
key_destroy( struct key
*key
)
893 if (key
->handle
) pgnutls_cipher_deinit( key
->handle
);
894 HeapFree( GetProcessHeap(), 0, key
->secret
);
895 HeapFree( GetProcessHeap(), 0, key
);
896 return STATUS_SUCCESS
;
898 #elif defined(HAVE_COMMONCRYPTO_COMMONCRYPTOR_H)
904 CCCryptorRef ref_encrypt
;
905 CCCryptorRef ref_decrypt
;
910 static NTSTATUS
key_init( struct key
*key
, enum alg_id id
, const UCHAR
*secret
, ULONG secret_len
)
920 FIXME( "algorithm %u not supported\n", id
);
921 return STATUS_NOT_SUPPORTED
;
924 if (!(key
->block_size
= get_block_size( id
))) return STATUS_INVALID_PARAMETER
;
925 if (!(buffer
= HeapAlloc( GetProcessHeap(), 0, secret_len
))) return STATUS_NO_MEMORY
;
926 memcpy( buffer
, secret
, secret_len
);
929 key
->ref_encrypt
= NULL
; /* initialized on first use */
930 key
->ref_decrypt
= NULL
;
931 key
->secret
= buffer
;
932 key
->secret_len
= secret_len
;
934 return STATUS_SUCCESS
;
937 static NTSTATUS
key_set_params( struct key
*key
, UCHAR
*iv
, ULONG iv_len
)
939 CCCryptorStatus status
;
941 if (key
->ref_encrypt
)
943 CCCryptorRelease( key
->ref_encrypt
);
944 key
->ref_encrypt
= NULL
;
946 if (key
->ref_decrypt
)
948 CCCryptorRelease( key
->ref_decrypt
);
949 key
->ref_decrypt
= NULL
;
952 if ((status
= CCCryptorCreateWithMode( kCCEncrypt
, kCCModeCBC
, kCCAlgorithmAES
, ccNoPadding
, iv
,
953 key
->secret
, key
->secret_len
, NULL
, 0, 0, 0, &key
->ref_encrypt
)) != kCCSuccess
)
955 WARN( "CCCryptorCreateWithMode failed %d\n", status
);
956 return STATUS_INTERNAL_ERROR
;
958 if ((status
= CCCryptorCreateWithMode( kCCDecrypt
, kCCModeCBC
, kCCAlgorithmAES
, ccNoPadding
, iv
,
959 key
->secret
, key
->secret_len
, NULL
, 0, 0, 0, &key
->ref_decrypt
)) != kCCSuccess
)
961 WARN( "CCCryptorCreateWithMode failed %d\n", status
);
962 CCCryptorRelease( key
->ref_encrypt
);
963 key
->ref_encrypt
= NULL
;
964 return STATUS_INTERNAL_ERROR
;
967 return STATUS_SUCCESS
;
970 static NTSTATUS
key_encrypt( struct key
*key
, const UCHAR
*input
, ULONG input_len
, UCHAR
*output
,
973 CCCryptorStatus status
;
975 if ((status
= CCCryptorUpdate( key
->ref_encrypt
, input
, input_len
, output
, output_len
, NULL
)) != kCCSuccess
)
977 WARN( "CCCryptorUpdate failed %d\n", status
);
978 return STATUS_INTERNAL_ERROR
;
981 return STATUS_SUCCESS
;
984 static NTSTATUS
key_decrypt( struct key
*key
, const UCHAR
*input
, ULONG input_len
, UCHAR
*output
,
987 CCCryptorStatus status
;
989 if ((status
= CCCryptorUpdate( key
->ref_decrypt
, input
, input_len
, output
, output_len
, NULL
)) != kCCSuccess
)
991 WARN( "CCCryptorUpdate failed %d\n", status
);
992 return STATUS_INTERNAL_ERROR
;
995 return STATUS_SUCCESS
;
998 static NTSTATUS
key_destroy( struct key
*key
)
1000 if (key
->ref_encrypt
) CCCryptorRelease( key
->ref_encrypt
);
1001 if (key
->ref_decrypt
) CCCryptorRelease( key
->ref_decrypt
);
1002 HeapFree( GetProcessHeap(), 0, key
->secret
);
1003 HeapFree( GetProcessHeap(), 0, key
);
1004 return STATUS_SUCCESS
;
1013 static NTSTATUS
key_init( struct key
*key
, enum alg_id id
, const UCHAR
*secret
, ULONG secret_len
)
1015 ERR( "support for keys not available at build time\n" );
1016 return STATUS_NOT_IMPLEMENTED
;
1019 static NTSTATUS
key_set_params( struct key
*key
, UCHAR
*iv
, ULONG iv_len
)
1021 ERR( "support for keys not available at build time\n" );
1022 return STATUS_NOT_IMPLEMENTED
;
1025 static NTSTATUS
key_encrypt( struct key
*key
, const UCHAR
*input
, ULONG input_len
, UCHAR
*output
,
1028 ERR( "support for keys not available at build time\n" );
1029 return STATUS_NOT_IMPLEMENTED
;
1032 static NTSTATUS
key_decrypt( struct key
*key
, const UCHAR
*input
, ULONG input_len
, UCHAR
*output
,
1035 ERR( "support for keys not available at build time\n" );
1036 return STATUS_NOT_IMPLEMENTED
;
1039 static NTSTATUS
key_destroy( struct key
*key
)
1041 ERR( "support for keys not available at build time\n" );
1042 return STATUS_NOT_IMPLEMENTED
;
1046 NTSTATUS WINAPI
BCryptGenerateSymmetricKey( BCRYPT_ALG_HANDLE algorithm
, BCRYPT_KEY_HANDLE
*handle
,
1047 UCHAR
*object
, ULONG object_len
, UCHAR
*secret
, ULONG secret_len
,
1050 struct algorithm
*alg
= algorithm
;
1054 TRACE( "%p, %p, %p, %u, %p, %u, %08x\n", algorithm
, handle
, object
, object_len
, secret
, secret_len
, flags
);
1056 if (!alg
|| alg
->hdr
.magic
!= MAGIC_ALG
) return STATUS_INVALID_HANDLE
;
1057 if (object
) FIXME( "ignoring object buffer\n" );
1059 if (!(key
= HeapAlloc( GetProcessHeap(), 0, sizeof(*key
) ))) return STATUS_NO_MEMORY
;
1060 key
->hdr
.magic
= MAGIC_KEY
;
1062 if ((status
= key_init( key
, alg
->id
, secret
, secret_len
)))
1064 HeapFree( GetProcessHeap(), 0, key
);
1069 return STATUS_SUCCESS
;
1072 NTSTATUS WINAPI
BCryptDestroyKey( BCRYPT_KEY_HANDLE handle
)
1074 struct key
*key
= handle
;
1076 TRACE( "%p\n", handle
);
1078 if (!key
|| key
->hdr
.magic
!= MAGIC_KEY
) return STATUS_INVALID_HANDLE
;
1079 return key_destroy( key
);
1082 NTSTATUS WINAPI
BCryptEncrypt( BCRYPT_KEY_HANDLE handle
, UCHAR
*input
, ULONG input_len
,
1083 void *padding
, UCHAR
*iv
, ULONG iv_len
, UCHAR
*output
,
1084 ULONG output_len
, ULONG
*ret_len
, ULONG flags
)
1086 struct key
*key
= handle
;
1087 ULONG bytes_left
= input_len
;
1088 UCHAR
*buf
, *src
, *dst
;
1091 TRACE( "%p, %p, %u, %p, %p, %u, %p, %u, %p, %08x\n", handle
, input
, input_len
,
1092 padding
, iv
, iv_len
, output
, output_len
, ret_len
, flags
);
1094 if (!key
|| key
->hdr
.magic
!= MAGIC_KEY
) return STATUS_INVALID_HANDLE
;
1097 FIXME( "padding info not implemented\n" );
1098 return STATUS_NOT_IMPLEMENTED
;
1100 if (flags
& ~BCRYPT_BLOCK_PADDING
)
1102 FIXME( "flags %08x not implemented\n", flags
);
1103 return STATUS_NOT_IMPLEMENTED
;
1106 if ((status
= key_set_params( key
, iv
, iv_len
))) return status
;
1108 *ret_len
= input_len
;
1110 if (flags
& BCRYPT_BLOCK_PADDING
)
1111 *ret_len
= (input_len
+ key
->block_size
) & ~(key
->block_size
- 1);
1112 else if (input_len
& (key
->block_size
- 1))
1113 return STATUS_INVALID_BUFFER_SIZE
;
1115 if (!output
) return STATUS_SUCCESS
;
1116 if (output_len
< *ret_len
) return STATUS_BUFFER_TOO_SMALL
;
1120 while (bytes_left
>= key
->block_size
)
1122 if ((status
= key_encrypt( key
, src
, key
->block_size
, dst
, key
->block_size
))) return status
;
1123 bytes_left
-= key
->block_size
;
1124 src
+= key
->block_size
;
1125 dst
+= key
->block_size
;
1128 if (flags
& BCRYPT_BLOCK_PADDING
)
1130 if (!(buf
= HeapAlloc( GetProcessHeap(), 0, key
->block_size
))) return STATUS_NO_MEMORY
;
1131 memcpy( buf
, src
, bytes_left
);
1132 memset( buf
+ bytes_left
, key
->block_size
- bytes_left
, key
->block_size
- bytes_left
);
1133 status
= key_encrypt( key
, buf
, key
->block_size
, dst
, key
->block_size
);
1134 HeapFree( GetProcessHeap(), 0, buf
);
1140 NTSTATUS WINAPI
BCryptDecrypt( BCRYPT_KEY_HANDLE handle
, UCHAR
*input
, ULONG input_len
,
1141 void *padding
, UCHAR
*iv
, ULONG iv_len
, UCHAR
*output
,
1142 ULONG output_len
, ULONG
*ret_len
, ULONG flags
)
1144 struct key
*key
= handle
;
1145 ULONG bytes_left
= input_len
;
1146 UCHAR
*buf
, *src
, *dst
;
1149 TRACE( "%p, %p, %u, %p, %p, %u, %p, %u, %p, %08x\n", handle
, input
, input_len
,
1150 padding
, iv
, iv_len
, output
, output_len
, ret_len
, flags
);
1152 if (!key
|| key
->hdr
.magic
!= MAGIC_KEY
) return STATUS_INVALID_HANDLE
;
1155 FIXME( "padding info not implemented\n" );
1156 return STATUS_NOT_IMPLEMENTED
;
1158 if (flags
& ~BCRYPT_BLOCK_PADDING
)
1160 FIXME( "flags %08x not supported\n", flags
);
1161 return STATUS_NOT_IMPLEMENTED
;
1164 if ((status
= key_set_params( key
, iv
, iv_len
))) return status
;
1166 *ret_len
= input_len
;
1168 if (input_len
& (key
->block_size
- 1)) return STATUS_INVALID_BUFFER_SIZE
;
1169 if (!output
) return STATUS_SUCCESS
;
1170 if (flags
& BCRYPT_BLOCK_PADDING
)
1172 if (output_len
+ key
->block_size
< *ret_len
) return STATUS_BUFFER_TOO_SMALL
;
1173 if (input_len
< key
->block_size
) return STATUS_BUFFER_TOO_SMALL
;
1174 bytes_left
-= key
->block_size
;
1176 else if (output_len
< *ret_len
)
1177 return STATUS_BUFFER_TOO_SMALL
;
1181 while (bytes_left
>= key
->block_size
)
1183 if ((status
= key_decrypt( key
, src
, key
->block_size
, dst
, key
->block_size
))) return status
;
1184 bytes_left
-= key
->block_size
;
1185 src
+= key
->block_size
;
1186 dst
+= key
->block_size
;
1189 if (flags
& BCRYPT_BLOCK_PADDING
)
1191 if (!(buf
= HeapAlloc( GetProcessHeap(), 0, key
->block_size
))) return STATUS_NO_MEMORY
;
1192 status
= key_decrypt( key
, src
, key
->block_size
, buf
, key
->block_size
);
1193 if (!status
&& buf
[ key
->block_size
- 1 ] <= key
->block_size
)
1195 *ret_len
-= buf
[ key
->block_size
- 1 ];
1196 if (output_len
< *ret_len
) status
= STATUS_BUFFER_TOO_SMALL
;
1197 else memcpy( dst
, buf
, key
->block_size
- buf
[ key
->block_size
- 1 ] );
1200 status
= STATUS_UNSUCCESSFUL
; /* FIXME: invalid padding */
1201 HeapFree( GetProcessHeap(), 0, buf
);
1207 BOOL WINAPI
DllMain( HINSTANCE hinst
, DWORD reason
, LPVOID reserved
)
1211 case DLL_PROCESS_ATTACH
:
1213 DisableThreadLibraryCalls( hinst
);
1214 #if defined(HAVE_GNUTLS_CIPHER_INIT) && !defined(HAVE_COMMONCRYPTO_COMMONCRYPTOR_H)
1215 gnutls_initialize();
1219 case DLL_PROCESS_DETACH
:
1220 if (reserved
) break;
1221 #if defined(HAVE_GNUTLS_CIPHER_INIT) && !defined(HAVE_COMMONCRYPTO_COMMONCRYPTOR_H)
1222 gnutls_uninitialize();