From: Bruno Jesus <00cpxxx@gmail.com> Subject: [PATCH 6/7] bcrypt: Implement AES encryption Message-Id: <20161207010621.23230-6-00cpxxx@gmail.com> Date: Tue, 6 Dec 2016 23:06:20 -0200 In-Reply-To: <20161207010621.23230-1-00cpxxx@gmail.com> References: <20161207010621.23230-1-00cpxxx@gmail.com> From: Hans Leidekker Signed-off-by: Bruno Jesus <00cpxxx@gmail.com> --- dlls/bcrypt/bcrypt_main.c | 126 ++++++++++++++++++++++++++++++++++++++++++++- dlls/bcrypt/tests/bcrypt.c | 6 +-- 2 files changed, 126 insertions(+), 6 deletions(-) diff --git a/dlls/bcrypt/bcrypt_main.c b/dlls/bcrypt/bcrypt_main.c index 21df85d..8649b79 100644 --- a/dlls/bcrypt/bcrypt_main.c +++ b/dlls/bcrypt/bcrypt_main.c @@ -52,6 +52,7 @@ static void *libgnutls_handle; MAKE_FUNCPTR(gnutls_cipher_init); MAKE_FUNCPTR(gnutls_cipher_deinit); MAKE_FUNCPTR(gnutls_global_deinit); +MAKE_FUNCPTR(gnutls_cipher_encrypt2); MAKE_FUNCPTR(gnutls_global_init); MAKE_FUNCPTR(gnutls_global_set_log_function); MAKE_FUNCPTR(gnutls_global_set_log_level); @@ -89,6 +90,7 @@ static BOOL gnutls_initialize(void) LOAD_FUNCPTR(gnutls_cipher_init); LOAD_FUNCPTR(gnutls_cipher_deinit); LOAD_FUNCPTR(gnutls_global_deinit) + LOAD_FUNCPTR(gnutls_cipher_encrypt2); LOAD_FUNCPTR(gnutls_global_init) LOAD_FUNCPTR(gnutls_global_set_log_function) LOAD_FUNCPTR(gnutls_global_set_log_level) @@ -595,6 +597,66 @@ static NTSTATUS key_destroy( struct key *key ) HeapFree( GetProcessHeap(), 0, key ); return STATUS_SUCCESS; } + +static gnutls_cipher_algorithm_t get_gnutls_cipher( const struct key *key ) +{ + switch (key->alg_id) + { + case ALG_ID_AES: + FIXME( "handle block size and chaining mode\n" ); + return GNUTLS_CIPHER_AES_128_CBC; + + default: + FIXME( "algorithm %u not supported\n", key->alg_id ); + return GNUTLS_CIPHER_UNKNOWN; + } +} + +static NTSTATUS key_set_params( struct key *key, UCHAR *iv, ULONG iv_len ) +{ + gnutls_cipher_algorithm_t cipher; + gnutls_datum_t secret, vector; + int ret; + + if (key->handle) + { + pgnutls_cipher_deinit( key->handle ); + key->handle = NULL; + } + + if ((cipher = get_gnutls_cipher( key )) == GNUTLS_CIPHER_UNKNOWN) + return STATUS_NOT_SUPPORTED; + + secret.data = key->secret; + secret.size = key->secret_len; + if (iv) + { + vector.data = iv; + vector.size = iv_len; + } + + if ((ret = pgnutls_cipher_init( &key->handle, cipher, &secret, iv ? &vector : NULL ))) + { + pgnutls_perror( ret ); + return STATUS_INTERNAL_ERROR; + } + + return STATUS_SUCCESS; +} + +static NTSTATUS key_encrypt( struct key *key, const UCHAR *input, ULONG input_len, UCHAR *output, + ULONG output_len ) +{ + int ret; + + if ((ret = pgnutls_cipher_encrypt2( key->handle, input, input_len, output, output_len ))) + { + pgnutls_perror( ret ); + return STATUS_INTERNAL_ERROR; + } + + return STATUS_SUCCESS; +} #else struct hash { @@ -655,6 +717,19 @@ static NTSTATUS key_destroy( struct key *key ) ERR( "support for keys not available at build time\n" ); return STATUS_NOT_IMPLEMENTED; } + +static NTSTATUS key_set_params( struct key *key, UCHAR *iv, ULONG iv_len ) +{ + ERR( "support for keys not available at build time\n" ); + return STATUS_NOT_IMPLEMENTED; +} + +static NTSTATUS key_encrypt( struct key *key, const UCHAR *input, ULONG input_len, UCHAR *output, + ULONG output_len ) +{ + ERR( "support for keys not available at build time\n" ); + return STATUS_NOT_IMPLEMENTED; +} #endif #define OBJECT_LENGTH_AES 618 /* FIXME: This is the 32 bits value */ @@ -851,9 +926,56 @@ NTSTATUS WINAPI BCryptEncrypt( BCRYPT_KEY_HANDLE handle, UCHAR *input, ULONG inp void *padding, UCHAR *iv, ULONG iv_len, UCHAR *output, ULONG output_len, ULONG *ret_len, ULONG flags ) { - FIXME( "%p, %p, %u, %p, %p, %u, %p, %u, %p, %08x\n", handle, input, input_len, + struct key *key = handle; + ULONG bytes_left = input_len; + UCHAR *buf, *src, *dst; + NTSTATUS status; + + TRACE( "%p, %p, %u, %p, %p, %u, %p, %u, %p, %08x\n", handle, input, input_len, padding, iv, iv_len, output, output_len, ret_len, flags ); - return STATUS_NOT_IMPLEMENTED; + + if (!key || key->hdr.magic != MAGIC_KEY) return STATUS_INVALID_HANDLE; + if (padding) + { + FIXME( "padding info not implemented\n" ); + return STATUS_NOT_IMPLEMENTED; + } + if (flags & ~BCRYPT_BLOCK_PADDING) + { + FIXME( "flags %08x not implemented\n", flags ); + return STATUS_NOT_IMPLEMENTED; + } + + if ((status = key_set_params( key, iv, iv_len ))) return status; + + *ret_len = input_len; + if (input_len & (key->block_size - 1)) + { + if (!(flags & BCRYPT_BLOCK_PADDING)) return STATUS_INVALID_BUFFER_SIZE; + *ret_len = (input_len + key->block_size - 1) & ~(key->block_size - 1); + } + if (!output) return STATUS_SUCCESS; + if (output_len < *ret_len) return STATUS_BUFFER_TOO_SMALL; + + src = input; + dst = output; + while (bytes_left >= key->block_size) + { + if ((status = key_encrypt( key, src, key->block_size, dst, key->block_size ))) return status; + bytes_left -= key->block_size; + src += key->block_size; + dst += key->block_size; + } + if (bytes_left) + { + if (!(buf = HeapAlloc( GetProcessHeap(), 0, key->block_size ))) return STATUS_NO_MEMORY; + memcpy( buf, src, bytes_left ); + memset( buf + bytes_left, key->block_size - bytes_left, key->block_size - bytes_left ); + status = key_encrypt( key, buf, key->block_size, dst, key->block_size ); + HeapFree( GetProcessHeap(), 0, buf ); + } + + return status; } NTSTATUS WINAPI BCryptDecrypt( BCRYPT_KEY_HANDLE handle, UCHAR *input, ULONG input_len, diff --git a/dlls/bcrypt/tests/bcrypt.c b/dlls/bcrypt/tests/bcrypt.c index 723b58e..4d25523 100644 --- a/dlls/bcrypt/tests/bcrypt.c +++ b/dlls/bcrypt/tests/bcrypt.c @@ -862,7 +862,6 @@ static void test_BCryptGenerateSymmetricKey(void) sizeof(BCRYPT_CHAIN_MODE_CBC), 0); todo_wine ok(ret == STATUS_SUCCESS, "got %08x\n", ret); -todo_wine { size = 0xdeadbeef; ret = pBCryptEncrypt(key, NULL, 0, NULL, NULL, 0, NULL, 0, &size, 0); ok(ret == STATUS_SUCCESS, "got %08x\n", ret); @@ -883,7 +882,7 @@ todo_wine { ok(!memcmp(ciphertext, expected, sizeof(expected)), "wrong data\n"); for (i = 0; i < 16; i++) ok(ciphertext[i] == expected[i], "%u: %02x != %02x\n", i, ciphertext[i], expected[i]); - +todo_wine { size = 0xdeadbeef; ret = pBCryptDecrypt(key, NULL, 0, NULL, NULL, 0, NULL, 0, &size, 0); ok(ret == STATUS_SUCCESS, "got %08x\n", ret); @@ -943,7 +942,6 @@ static void test_BCryptEncrypt(void) ok(ret == STATUS_SUCCESS, "got %08x\n", ret); /* input size is a multiple of block size */ -todo_wine { size = 0; memcpy(ivbuf, iv, sizeof(iv)); ret = pBCryptEncrypt(key, data, 16, NULL, ivbuf, 16, NULL, 0, &size, 0); @@ -991,7 +989,7 @@ todo_wine { ret = pBCryptEncrypt(key, data, 17, NULL, ivbuf, 16, ciphertext, 31, &size, BCRYPT_BLOCK_PADDING); ok(ret == STATUS_BUFFER_TOO_SMALL, "got %08x\n", ret); ok(size == 32, "got %u\n", size); -} + ret = pBCryptDestroyKey(key); ok(ret == STATUS_SUCCESS, "got %08x\n", ret); HeapFree(GetProcessHeap(), 0, buf); -- 2.9.3