| /* |
| * Copyright 2009 Henri Verbeet for CodeWeavers |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
| * |
| */ |
| |
| #include "config.h" |
| |
| #include <stdarg.h> |
| #ifdef HAVE_COMMONCRYPTO_COMMONDIGEST_H |
| #include <CommonCrypto/CommonDigest.h> |
| #endif |
| |
| #include "ntstatus.h" |
| #define WIN32_NO_STATUS |
| #include "windef.h" |
| #include "winbase.h" |
| #include "ntsecapi.h" |
| #include "bcrypt.h" |
| |
| #include "wine/debug.h" |
| #include "wine/unicode.h" |
| |
| WINE_DEFAULT_DEBUG_CHANNEL(bcrypt); |
| |
| NTSTATUS WINAPI BCryptEnumAlgorithms(ULONG dwAlgOperations, ULONG *pAlgCount, |
| BCRYPT_ALGORITHM_IDENTIFIER **ppAlgList, ULONG dwFlags) |
| { |
| FIXME("%08x, %p, %p, %08x - stub\n", dwAlgOperations, pAlgCount, ppAlgList, dwFlags); |
| |
| *ppAlgList=NULL; |
| *pAlgCount=0; |
| |
| return STATUS_NOT_IMPLEMENTED; |
| } |
| |
| NTSTATUS WINAPI BCryptGenRandom(BCRYPT_ALG_HANDLE algorithm, UCHAR *buffer, ULONG count, ULONG flags) |
| { |
| const DWORD supported_flags = BCRYPT_USE_SYSTEM_PREFERRED_RNG; |
| TRACE("%p, %p, %u, %08x - semi-stub\n", algorithm, buffer, count, flags); |
| |
| if (!algorithm) |
| { |
| /* It's valid to call without an algorithm if BCRYPT_USE_SYSTEM_PREFERRED_RNG |
| * is set. In this case the preferred system RNG is used. |
| */ |
| if (!(flags & BCRYPT_USE_SYSTEM_PREFERRED_RNG)) |
| return STATUS_INVALID_HANDLE; |
| } |
| if (!buffer) |
| return STATUS_INVALID_PARAMETER; |
| |
| if (flags & ~supported_flags) |
| FIXME("unsupported flags %08x\n", flags & ~supported_flags); |
| |
| if (algorithm) |
| FIXME("ignoring selected algorithm\n"); |
| |
| /* When zero bytes are requested the function returns success too. */ |
| if (!count) |
| return STATUS_SUCCESS; |
| |
| if (flags & BCRYPT_USE_SYSTEM_PREFERRED_RNG) |
| { |
| if (RtlGenRandom(buffer, count)) |
| return STATUS_SUCCESS; |
| } |
| |
| FIXME("called with unsupported parameters, returning error\n"); |
| return STATUS_NOT_IMPLEMENTED; |
| } |
| |
| #define MAGIC_ALG (('A' << 24) | ('L' << 16) | ('G' << 8) | '0') |
| #define MAGIC_HASH (('H' << 24) | ('A' << 16) | ('S' << 8) | 'H') |
| struct object |
| { |
| ULONG magic; |
| }; |
| |
| enum alg_id |
| { |
| ALG_ID_SHA1 = 1, |
| ALG_ID_SHA256 = 2, |
| ALG_ID_SHA384 = 3, |
| ALG_ID_SHA512 = 4 |
| }; |
| |
| struct algorithm |
| { |
| struct object hdr; |
| enum alg_id id; |
| }; |
| |
| NTSTATUS WINAPI BCryptOpenAlgorithmProvider( BCRYPT_ALG_HANDLE *handle, LPCWSTR id, LPCWSTR implementation, DWORD flags ) |
| { |
| struct algorithm *alg; |
| enum alg_id alg_id; |
| |
| TRACE( "%p, %s, %s, %08x\n", handle, wine_dbgstr_w(id), wine_dbgstr_w(implementation), flags ); |
| |
| if (!handle || !id) return STATUS_INVALID_PARAMETER; |
| if (flags) |
| { |
| FIXME( "unimplemented flags %08x\n", flags ); |
| return STATUS_NOT_IMPLEMENTED; |
| } |
| |
| if (!strcmpW( id, BCRYPT_SHA1_ALGORITHM )) alg_id = ALG_ID_SHA1; |
| else if (!strcmpW( id, BCRYPT_SHA256_ALGORITHM )) alg_id = ALG_ID_SHA256; |
| else if (!strcmpW( id, BCRYPT_SHA384_ALGORITHM )) alg_id = ALG_ID_SHA384; |
| else if (!strcmpW( id, BCRYPT_SHA512_ALGORITHM )) alg_id = ALG_ID_SHA512; |
| else |
| { |
| FIXME( "algorithm %s not supported\n", debugstr_w(id) ); |
| return STATUS_NOT_IMPLEMENTED; |
| } |
| if (!implementation || strcmpW( implementation, MS_PRIMITIVE_PROVIDER )) |
| { |
| FIXME( "implementation %s not supported\n", debugstr_w(implementation) ); |
| return STATUS_NOT_IMPLEMENTED; |
| } |
| |
| if (!(alg = HeapAlloc( GetProcessHeap(), 0, sizeof(*alg) ))) return STATUS_NO_MEMORY; |
| alg->hdr.magic = MAGIC_ALG; |
| alg->id = alg_id; |
| |
| *handle = alg; |
| return STATUS_SUCCESS; |
| } |
| |
| NTSTATUS WINAPI BCryptCloseAlgorithmProvider( BCRYPT_ALG_HANDLE handle, DWORD flags ) |
| { |
| struct algorithm *alg = handle; |
| |
| TRACE( "%p, %08x\n", handle, flags ); |
| |
| if (!alg || alg->hdr.magic != MAGIC_ALG) return STATUS_INVALID_HANDLE; |
| HeapFree( GetProcessHeap(), 0, alg ); |
| return STATUS_SUCCESS; |
| } |
| |
| NTSTATUS WINAPI BCryptGetFipsAlgorithmMode(BOOLEAN *enabled) |
| { |
| FIXME("%p - semi-stub\n", enabled); |
| |
| if (!enabled) |
| return STATUS_INVALID_PARAMETER; |
| |
| *enabled = FALSE; |
| return STATUS_SUCCESS; |
| } |
| |
| #ifdef HAVE_COMMONCRYPTO_COMMONDIGEST_H |
| struct hash |
| { |
| struct object hdr; |
| enum alg_id alg_id; |
| union |
| { |
| CC_SHA1_CTX sha1_ctx; |
| CC_SHA256_CTX sha256_ctx; |
| CC_SHA512_CTX sha512_ctx; |
| } u; |
| }; |
| |
| static NTSTATUS hash_init( struct hash *hash ) |
| { |
| switch (hash->alg_id) |
| { |
| case ALG_ID_SHA1: |
| CC_SHA1_Init( &hash->u.sha1_ctx ); |
| break; |
| |
| case ALG_ID_SHA256: |
| CC_SHA256_Init( &hash->u.sha256_ctx ); |
| break; |
| |
| case ALG_ID_SHA384: |
| CC_SHA384_Init( &hash->u.sha512_ctx ); |
| break; |
| |
| case ALG_ID_SHA512: |
| CC_SHA512_Init( &hash->u.sha512_ctx ); |
| break; |
| |
| default: |
| ERR( "unhandled id %u\n", hash->alg_id ); |
| return STATUS_NOT_IMPLEMENTED; |
| } |
| return STATUS_SUCCESS; |
| } |
| |
| static void hash_update( struct hash *hash, UCHAR *input, ULONG size ) |
| { |
| switch (hash->alg_id) |
| { |
| case ALG_ID_SHA1: |
| CC_SHA1_Update( &hash->u.sha1_ctx, input, size ); |
| break; |
| |
| case ALG_ID_SHA256: |
| CC_SHA256_Update( &hash->u.sha256_ctx, input, size ); |
| break; |
| |
| case ALG_ID_SHA384: |
| CC_SHA384_Update( &hash->u.sha512_ctx, input, size ); |
| break; |
| |
| case ALG_ID_SHA512: |
| CC_SHA512_Update( &hash->u.sha512_ctx, input, size ); |
| break; |
| |
| default: |
| ERR( "unhandled id %u\n", hash->alg_id ); |
| break; |
| } |
| } |
| |
| static NTSTATUS hash_finish( struct hash *hash, UCHAR *output, ULONG size ) |
| { |
| switch (hash->alg_id) |
| { |
| case ALG_ID_SHA1: |
| CC_SHA1_Final( output, &hash->u.sha1_ctx ); |
| break; |
| |
| case ALG_ID_SHA256: |
| CC_SHA256_Final( output, &hash->u.sha256_ctx ); |
| break; |
| |
| case ALG_ID_SHA384: |
| CC_SHA384_Final( output, &hash->u.sha512_ctx ); |
| break; |
| |
| case ALG_ID_SHA512: |
| CC_SHA512_Final( output, &hash->u.sha512_ctx ); |
| break; |
| |
| default: |
| ERR( "unhandled id %u\n", hash->alg_id ); |
| break; |
| } |
| return STATUS_SUCCESS; |
| } |
| #else |
| struct hash |
| { |
| struct object hdr; |
| enum alg_id alg_id; |
| }; |
| |
| static NTSTATUS hash_init( struct hash *hash ) |
| { |
| ERR( "support for hashes not available at build time\n" ); |
| return STATUS_NOT_IMPLEMENTED; |
| } |
| |
| static void hash_update( struct hash *hash, UCHAR *input, ULONG size ) |
| { |
| ERR( "support for hashes not available at build time\n" ); |
| } |
| |
| static NTSTATUS hash_finish( struct hash *hash, UCHAR *output, ULONG size ) |
| { |
| ERR( "support for hashes not available at build time\n" ); |
| return STATUS_NOT_IMPLEMENTED; |
| } |
| #endif |
| |
| #define OBJECT_LENGTH_SHA1 278 |
| #define OBJECT_LENGTH_SHA256 286 |
| #define OBJECT_LENGTH_SHA384 382 |
| #define OBJECT_LENGTH_SHA512 382 |
| |
| #define HASH_DIGEST_LENGTH_SHA1 20 |
| #define HASH_DIGEST_LENGTH_SHA256 32 |
| #define HASH_DIGEST_LENGTH_SHA384 48 |
| #define HASH_DIGEST_LENGTH_SHA512 64 |
| |
| static NTSTATUS get_alg_property( enum alg_id id, const WCHAR *prop, UCHAR *buf, ULONG size, ULONG *ret_size ) |
| { |
| ULONG value; |
| |
| switch (id) |
| { |
| case ALG_ID_SHA1: |
| if (!strcmpW( prop, BCRYPT_OBJECT_LENGTH )) |
| { |
| value = OBJECT_LENGTH_SHA1; |
| break; |
| } |
| FIXME( "unsupported sha1 algorithm property %s\n", debugstr_w(prop) ); |
| return STATUS_NOT_IMPLEMENTED; |
| |
| case ALG_ID_SHA256: |
| if (!strcmpW( prop, BCRYPT_OBJECT_LENGTH )) |
| { |
| value = OBJECT_LENGTH_SHA256; |
| break; |
| } |
| FIXME( "unsupported sha256 algorithm property %s\n", debugstr_w(prop) ); |
| return STATUS_NOT_IMPLEMENTED; |
| |
| case ALG_ID_SHA384: |
| if (!strcmpW( prop, BCRYPT_OBJECT_LENGTH )) |
| { |
| value = OBJECT_LENGTH_SHA384; |
| break; |
| } |
| FIXME( "unsupported sha384 algorithm property %s\n", debugstr_w(prop) ); |
| return STATUS_NOT_IMPLEMENTED; |
| |
| case ALG_ID_SHA512: |
| if (!strcmpW( prop, BCRYPT_OBJECT_LENGTH )) |
| { |
| value = OBJECT_LENGTH_SHA512; |
| break; |
| } |
| FIXME( "unsupported sha512 algorithm property %s\n", debugstr_w(prop) ); |
| return STATUS_NOT_IMPLEMENTED; |
| |
| default: |
| FIXME( "unsupported algorithm %u\n", id ); |
| return STATUS_NOT_IMPLEMENTED; |
| } |
| |
| if (size < sizeof(ULONG)) |
| { |
| *ret_size = sizeof(ULONG); |
| return STATUS_BUFFER_TOO_SMALL; |
| } |
| if (buf) *(ULONG *)buf = value; |
| *ret_size = sizeof(ULONG); |
| |
| return STATUS_SUCCESS; |
| } |
| |
| static NTSTATUS get_hash_property( enum alg_id id, const WCHAR *prop, UCHAR *buf, ULONG size, ULONG *ret_size ) |
| { |
| ULONG value; |
| |
| switch (id) |
| { |
| case ALG_ID_SHA1: |
| if (!strcmpW( prop, BCRYPT_HASH_LENGTH )) |
| { |
| value = HASH_DIGEST_LENGTH_SHA1; |
| break; |
| } |
| FIXME( "unsupported sha1 hash property %s\n", debugstr_w(prop) ); |
| return STATUS_NOT_IMPLEMENTED; |
| |
| case ALG_ID_SHA256: |
| if (!strcmpW( prop, BCRYPT_HASH_LENGTH )) |
| { |
| value = HASH_DIGEST_LENGTH_SHA256; |
| break; |
| } |
| FIXME( "unsupported sha256 hash property %s\n", debugstr_w(prop) ); |
| return STATUS_NOT_IMPLEMENTED; |
| |
| case ALG_ID_SHA384: |
| if (!strcmpW( prop, BCRYPT_HASH_LENGTH )) |
| { |
| value = HASH_DIGEST_LENGTH_SHA384; |
| break; |
| } |
| FIXME( "unsupported sha384 hash property %s\n", debugstr_w(prop) ); |
| return STATUS_NOT_IMPLEMENTED; |
| |
| case ALG_ID_SHA512: |
| if (!strcmpW( prop, BCRYPT_HASH_LENGTH )) |
| { |
| value = HASH_DIGEST_LENGTH_SHA512; |
| break; |
| } |
| FIXME( "unsupported sha512 hash property %s\n", debugstr_w(prop) ); |
| return STATUS_NOT_IMPLEMENTED; |
| |
| default: |
| FIXME( "unsupported hash %u\n", id ); |
| return STATUS_NOT_IMPLEMENTED; |
| } |
| |
| if (size < sizeof(ULONG)) |
| { |
| *ret_size = sizeof(ULONG); |
| return STATUS_BUFFER_TOO_SMALL; |
| } |
| if (buf) *(ULONG *)buf = value; |
| *ret_size = sizeof(ULONG); |
| |
| return STATUS_SUCCESS; |
| } |
| |
| NTSTATUS WINAPI BCryptGetProperty( BCRYPT_HANDLE handle, LPCWSTR prop, UCHAR *buffer, ULONG count, ULONG *res, ULONG flags ) |
| { |
| struct object *object = handle; |
| |
| TRACE( "%p, %s, %p, %u, %p, %08x\n", handle, wine_dbgstr_w(prop), buffer, count, res, flags ); |
| |
| if (!object) return STATUS_INVALID_HANDLE; |
| if (!prop || !res) return STATUS_INVALID_PARAMETER; |
| |
| switch (object->magic) |
| { |
| case MAGIC_ALG: |
| { |
| const struct algorithm *alg = (const struct algorithm *)object; |
| return get_alg_property( alg->id, prop, buffer, count, res ); |
| } |
| case MAGIC_HASH: |
| { |
| const struct hash *hash = (const struct hash *)object; |
| return get_hash_property( hash->alg_id, prop, buffer, count, res ); |
| } |
| default: |
| WARN( "unknown magic %08x", object->magic ); |
| return STATUS_INVALID_HANDLE; |
| } |
| } |
| |
| NTSTATUS WINAPI BCryptCreateHash( BCRYPT_ALG_HANDLE algorithm, BCRYPT_HASH_HANDLE *handle, UCHAR *object, ULONG objectlen, |
| UCHAR *secret, ULONG secretlen, ULONG flags ) |
| { |
| struct algorithm *alg = algorithm; |
| struct hash *hash; |
| NTSTATUS status; |
| |
| TRACE( "%p, %p, %p, %u, %p, %u, %08x - stub\n", algorithm, handle, object, objectlen, |
| secret, secretlen, flags ); |
| if (flags) |
| { |
| FIXME( "unimplemented flags %08x\n", flags ); |
| return STATUS_NOT_IMPLEMENTED; |
| } |
| |
| if (!alg || alg->hdr.magic != MAGIC_ALG) return STATUS_INVALID_HANDLE; |
| if (object) FIXME( "ignoring object buffer\n" ); |
| |
| if (!(hash = HeapAlloc( GetProcessHeap(), 0, sizeof(*hash) ))) return STATUS_NO_MEMORY; |
| hash->hdr.magic = MAGIC_HASH; |
| hash->alg_id = alg->id; |
| if ((status = hash_init( hash )) != STATUS_SUCCESS) |
| { |
| HeapFree( GetProcessHeap(), 0, hash ); |
| return status; |
| } |
| |
| *handle = hash; |
| return STATUS_SUCCESS; |
| } |
| |
| NTSTATUS WINAPI BCryptDestroyHash( BCRYPT_HASH_HANDLE handle ) |
| { |
| struct hash *hash = handle; |
| |
| TRACE( "%p\n", handle ); |
| |
| if (!hash || hash->hdr.magic != MAGIC_HASH) return STATUS_INVALID_HANDLE; |
| HeapFree( GetProcessHeap(), 0, hash ); |
| return STATUS_SUCCESS; |
| } |
| |
| NTSTATUS WINAPI BCryptHashData( BCRYPT_HASH_HANDLE handle, UCHAR *input, ULONG size, ULONG flags ) |
| { |
| struct hash *hash = handle; |
| |
| TRACE( "%p, %p, %u, %08x\n", handle, input, size, flags ); |
| |
| if (!hash || hash->hdr.magic != MAGIC_HASH) return STATUS_INVALID_HANDLE; |
| if (!input) return STATUS_INVALID_PARAMETER; |
| |
| hash_update( hash, input, size ); |
| return STATUS_SUCCESS; |
| } |
| |
| NTSTATUS WINAPI BCryptFinishHash( BCRYPT_HASH_HANDLE handle, UCHAR *output, ULONG size, ULONG flags ) |
| { |
| struct hash *hash = handle; |
| |
| TRACE( "%p, %p, %u, %08x\n", handle, output, size, flags ); |
| |
| if (!hash || hash->hdr.magic != MAGIC_HASH) return STATUS_INVALID_HANDLE; |
| if (!output) return STATUS_INVALID_PARAMETER; |
| |
| return hash_finish( hash, output, size ); |
| } |