Commit f4d6df89 authored by Hans Leidekker's avatar Hans Leidekker Committed by Alexandre Julliard

bcrypt: Avoid recreating cipher handles when the initialization vector doesn't change.

parent 5c708c85
...@@ -163,6 +163,8 @@ struct key_symmetric ...@@ -163,6 +163,8 @@ struct key_symmetric
enum mode_id mode; enum mode_id mode;
ULONG block_size; ULONG block_size;
gnutls_cipher_hd_t handle; gnutls_cipher_hd_t handle;
UCHAR *vector;
ULONG vector_len;
UCHAR *secret; UCHAR *secret;
ULONG secret_len; ULONG secret_len;
}; };
...@@ -192,6 +194,8 @@ struct key_symmetric ...@@ -192,6 +194,8 @@ struct key_symmetric
ULONG block_size; ULONG block_size;
CCCryptorRef ref_encrypt; CCCryptorRef ref_encrypt;
CCCryptorRef ref_decrypt; CCCryptorRef ref_decrypt;
UCHAR *vector;
ULONG vector_len;
UCHAR *secret; UCHAR *secret;
ULONG secret_len; ULONG secret_len;
}; };
...@@ -234,7 +238,7 @@ NTSTATUS get_alg_property( const struct algorithm *, const WCHAR *, UCHAR *, ULO ...@@ -234,7 +238,7 @@ NTSTATUS get_alg_property( const struct algorithm *, const WCHAR *, UCHAR *, ULO
NTSTATUS key_set_property( struct key *, const WCHAR *, UCHAR *, ULONG, ULONG ) DECLSPEC_HIDDEN; NTSTATUS key_set_property( struct key *, const WCHAR *, UCHAR *, ULONG, ULONG ) DECLSPEC_HIDDEN;
NTSTATUS key_symmetric_init( struct key *, struct algorithm *, const UCHAR *, ULONG ) DECLSPEC_HIDDEN; NTSTATUS key_symmetric_init( struct key *, struct algorithm *, const UCHAR *, ULONG ) DECLSPEC_HIDDEN;
NTSTATUS key_symmetric_set_params( struct key *, UCHAR *, ULONG ) DECLSPEC_HIDDEN; NTSTATUS key_symmetric_set_vector( struct key *, UCHAR *, ULONG ) DECLSPEC_HIDDEN;
NTSTATUS key_symmetric_set_auth_data( struct key *, UCHAR *, ULONG ) DECLSPEC_HIDDEN; NTSTATUS key_symmetric_set_auth_data( struct key *, UCHAR *, ULONG ) DECLSPEC_HIDDEN;
NTSTATUS key_symmetric_encrypt( struct key *, const UCHAR *, ULONG, UCHAR *, ULONG ) DECLSPEC_HIDDEN; NTSTATUS key_symmetric_encrypt( struct key *, const UCHAR *, ULONG, UCHAR *, ULONG ) DECLSPEC_HIDDEN;
NTSTATUS key_symmetric_decrypt( struct key *, const UCHAR *, ULONG, UCHAR *, ULONG ) DECLSPEC_HIDDEN; NTSTATUS key_symmetric_decrypt( struct key *, const UCHAR *, ULONG, UCHAR *, ULONG ) DECLSPEC_HIDDEN;
...@@ -248,6 +252,9 @@ BOOL key_is_symmetric( struct key * ) DECLSPEC_HIDDEN; ...@@ -248,6 +252,9 @@ BOOL key_is_symmetric( struct key * ) DECLSPEC_HIDDEN;
NTSTATUS key_export_ecc( struct key *, UCHAR *, ULONG, ULONG * ) DECLSPEC_HIDDEN; NTSTATUS key_export_ecc( struct key *, UCHAR *, ULONG, ULONG * ) DECLSPEC_HIDDEN;
NTSTATUS key_import_ecc( struct key *, UCHAR *, ULONG ) DECLSPEC_HIDDEN; NTSTATUS key_import_ecc( struct key *, UCHAR *, ULONG ) DECLSPEC_HIDDEN;
BOOL is_zero_vector( const UCHAR *, ULONG ) DECLSPEC_HIDDEN;
BOOL is_equal_vector( const UCHAR *, ULONG, const UCHAR *, ULONG ) DECLSPEC_HIDDEN;
BOOL gnutls_initialize(void) DECLSPEC_HIDDEN; BOOL gnutls_initialize(void) DECLSPEC_HIDDEN;
void gnutls_uninitialize(void) DECLSPEC_HIDDEN; void gnutls_uninitialize(void) DECLSPEC_HIDDEN;
......
...@@ -831,6 +831,21 @@ BOOL key_is_symmetric( struct key *key ) ...@@ -831,6 +831,21 @@ BOOL key_is_symmetric( struct key *key )
return builtin_algorithms[key->alg_id].class == BCRYPT_CIPHER_INTERFACE; return builtin_algorithms[key->alg_id].class == BCRYPT_CIPHER_INTERFACE;
} }
BOOL is_zero_vector( const UCHAR *vector, ULONG len )
{
ULONG i;
if (!vector) return FALSE;
for (i = 0; i < len; i++) if (vector[i]) return FALSE;
return TRUE;
}
BOOL is_equal_vector( const UCHAR *vector, ULONG len, const UCHAR *vector2, ULONG len2 )
{
if (!vector && !vector2) return TRUE;
if (len != len2) return FALSE;
return !memcmp( vector, vector2, len );
}
static NTSTATUS key_import( BCRYPT_ALG_HANDLE algorithm, const WCHAR *type, BCRYPT_KEY_HANDLE *key, UCHAR *object, static NTSTATUS key_import( BCRYPT_ALG_HANDLE algorithm, const WCHAR *type, BCRYPT_KEY_HANDLE *key, UCHAR *object,
ULONG object_len, UCHAR *input, ULONG input_len ) ULONG object_len, UCHAR *input, ULONG input_len )
{ {
...@@ -965,7 +980,7 @@ static NTSTATUS key_encrypt( struct key *key, UCHAR *input, ULONG input_len, vo ...@@ -965,7 +980,7 @@ static NTSTATUS key_encrypt( struct key *key, UCHAR *input, ULONG input_len, vo
if (auth_info->dwFlags & BCRYPT_AUTH_MODE_CHAIN_CALLS_FLAG) if (auth_info->dwFlags & BCRYPT_AUTH_MODE_CHAIN_CALLS_FLAG)
FIXME( "call chaining not implemented\n" ); FIXME( "call chaining not implemented\n" );
if ((status = key_symmetric_set_params( key, auth_info->pbNonce, auth_info->cbNonce ))) if ((status = key_symmetric_set_vector( key, auth_info->pbNonce, auth_info->cbNonce )))
return status; return status;
*ret_len = input_len; *ret_len = input_len;
...@@ -980,7 +995,6 @@ static NTSTATUS key_encrypt( struct key *key, UCHAR *input, ULONG input_len, vo ...@@ -980,7 +995,6 @@ static NTSTATUS key_encrypt( struct key *key, UCHAR *input, ULONG input_len, vo
return key_symmetric_get_tag( key, auth_info->pbTag, auth_info->cbTag ); return key_symmetric_get_tag( key, auth_info->pbTag, auth_info->cbTag );
} }
if ((status = key_symmetric_set_params( key, iv, iv_len ))) return status;
*ret_len = input_len; *ret_len = input_len;
if (flags & BCRYPT_BLOCK_PADDING) if (flags & BCRYPT_BLOCK_PADDING)
...@@ -991,6 +1005,7 @@ static NTSTATUS key_encrypt( struct key *key, UCHAR *input, ULONG input_len, vo ...@@ -991,6 +1005,7 @@ static NTSTATUS key_encrypt( struct key *key, UCHAR *input, ULONG input_len, vo
if (!output) return STATUS_SUCCESS; if (!output) return STATUS_SUCCESS;
if (output_len < *ret_len) return STATUS_BUFFER_TOO_SMALL; if (output_len < *ret_len) return STATUS_BUFFER_TOO_SMALL;
if (key->u.s.mode == MODE_ID_ECB && iv) return STATUS_INVALID_PARAMETER; if (key->u.s.mode == MODE_ID_ECB && iv) return STATUS_INVALID_PARAMETER;
if ((status = key_symmetric_set_vector( key, iv, iv_len ))) return status;
src = input; src = input;
dst = output; dst = output;
...@@ -998,7 +1013,7 @@ static NTSTATUS key_encrypt( struct key *key, UCHAR *input, ULONG input_len, vo ...@@ -998,7 +1013,7 @@ static NTSTATUS key_encrypt( struct key *key, UCHAR *input, ULONG input_len, vo
{ {
if ((status = key_symmetric_encrypt( key, src, key->u.s.block_size, dst, key->u.s.block_size ))) if ((status = key_symmetric_encrypt( key, src, key->u.s.block_size, dst, key->u.s.block_size )))
return status; return status;
if (key->u.s.mode == MODE_ID_ECB && (status = key_symmetric_set_params( key, NULL, 0 ))) return status; if (key->u.s.mode == MODE_ID_ECB && (status = key_symmetric_set_vector( key, NULL, 0 ))) return status;
bytes_left -= key->u.s.block_size; bytes_left -= key->u.s.block_size;
src += key->u.s.block_size; src += key->u.s.block_size;
dst += key->u.s.block_size; dst += key->u.s.block_size;
...@@ -1033,7 +1048,7 @@ static NTSTATUS key_decrypt( struct key *key, UCHAR *input, ULONG input_len, voi ...@@ -1033,7 +1048,7 @@ static NTSTATUS key_decrypt( struct key *key, UCHAR *input, ULONG input_len, voi
if (!auth_info->pbTag) return STATUS_INVALID_PARAMETER; if (!auth_info->pbTag) return STATUS_INVALID_PARAMETER;
if (auth_info->cbTag < 12 || auth_info->cbTag > 16) return STATUS_INVALID_PARAMETER; if (auth_info->cbTag < 12 || auth_info->cbTag > 16) return STATUS_INVALID_PARAMETER;
if ((status = key_symmetric_set_params( key, auth_info->pbNonce, auth_info->cbNonce ))) if ((status = key_symmetric_set_vector( key, auth_info->pbNonce, auth_info->cbNonce )))
return status; return status;
*ret_len = input_len; *ret_len = input_len;
...@@ -1051,8 +1066,6 @@ static NTSTATUS key_decrypt( struct key *key, UCHAR *input, ULONG input_len, voi ...@@ -1051,8 +1066,6 @@ static NTSTATUS key_decrypt( struct key *key, UCHAR *input, ULONG input_len, voi
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
if ((status = key_symmetric_set_params( key, iv, iv_len ))) return status;
*ret_len = input_len; *ret_len = input_len;
if (input_len & (key->u.s.block_size - 1)) return STATUS_INVALID_BUFFER_SIZE; if (input_len & (key->u.s.block_size - 1)) return STATUS_INVALID_BUFFER_SIZE;
...@@ -1066,6 +1079,7 @@ static NTSTATUS key_decrypt( struct key *key, UCHAR *input, ULONG input_len, voi ...@@ -1066,6 +1079,7 @@ static NTSTATUS key_decrypt( struct key *key, UCHAR *input, ULONG input_len, voi
else if (output_len < *ret_len) return STATUS_BUFFER_TOO_SMALL; else if (output_len < *ret_len) return STATUS_BUFFER_TOO_SMALL;
if (key->u.s.mode == MODE_ID_ECB && iv) return STATUS_INVALID_PARAMETER; if (key->u.s.mode == MODE_ID_ECB && iv) return STATUS_INVALID_PARAMETER;
if ((status = key_symmetric_set_vector( key, iv, iv_len ))) return status;
src = input; src = input;
dst = output; dst = output;
...@@ -1073,7 +1087,7 @@ static NTSTATUS key_decrypt( struct key *key, UCHAR *input, ULONG input_len, voi ...@@ -1073,7 +1087,7 @@ static NTSTATUS key_decrypt( struct key *key, UCHAR *input, ULONG input_len, voi
{ {
if ((status = key_symmetric_decrypt( key, src, key->u.s.block_size, dst, key->u.s.block_size ))) if ((status = key_symmetric_decrypt( key, src, key->u.s.block_size, dst, key->u.s.block_size )))
return status; return status;
if (key->u.s.mode == MODE_ID_ECB && (status = key_symmetric_set_params( key, NULL, 0 ))) return status; if (key->u.s.mode == MODE_ID_ECB && (status = key_symmetric_set_vector( key, NULL, 0 ))) return status;
bytes_left -= key->u.s.block_size; bytes_left -= key->u.s.block_size;
src += key->u.s.block_size; src += key->u.s.block_size;
dst += key->u.s.block_size; dst += key->u.s.block_size;
......
...@@ -441,6 +441,8 @@ NTSTATUS key_symmetric_init( struct key *key, struct algorithm *alg, const UCHAR ...@@ -441,6 +441,8 @@ NTSTATUS key_symmetric_init( struct key *key, struct algorithm *alg, const UCHAR
key->alg_id = alg->id; key->alg_id = alg->id;
key->u.s.mode = alg->mode; key->u.s.mode = alg->mode;
key->u.s.handle = 0; /* initialized on first use */ key->u.s.handle = 0; /* initialized on first use */
key->u.s.vector = NULL;
key->u.s.vector_len = 0;
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
...@@ -475,30 +477,45 @@ static gnutls_cipher_algorithm_t get_gnutls_cipher( const struct key *key ) ...@@ -475,30 +477,45 @@ static gnutls_cipher_algorithm_t get_gnutls_cipher( const struct key *key )
} }
} }
NTSTATUS key_symmetric_set_params( struct key *key, UCHAR *iv, ULONG iv_len ) NTSTATUS key_symmetric_set_vector( struct key *key, UCHAR *vector, ULONG vector_len )
{ {
gnutls_cipher_algorithm_t cipher; if (key->u.s.handle && (!is_zero_vector( vector, vector_len ) ||
gnutls_datum_t secret, vector; !is_equal_vector( key->u.s.vector, key->u.s.vector_len, vector, vector_len )))
int ret;
if (key->u.s.handle)
{ {
TRACE( "invalidating cipher handle\n" );
pgnutls_cipher_deinit( key->u.s.handle ); pgnutls_cipher_deinit( key->u.s.handle );
key->u.s.handle = NULL; key->u.s.handle = NULL;
} }
if ((cipher = get_gnutls_cipher( key )) == GNUTLS_CIPHER_UNKNOWN) heap_free( key->u.s.vector );
return STATUS_NOT_SUPPORTED; key->u.s.vector = NULL;
key->u.s.vector_len = 0;
if (vector)
{
if (!(key->u.s.vector = heap_alloc( vector_len ))) return STATUS_NO_MEMORY;
memcpy( key->u.s.vector, vector, vector_len );
key->u.s.vector_len = vector_len;
}
return STATUS_SUCCESS;
}
static NTSTATUS init_cipher_handle( struct key *key )
{
gnutls_cipher_algorithm_t cipher;
gnutls_datum_t secret, vector;
int ret;
if (key->u.s.handle) return STATUS_SUCCESS;
if ((cipher = get_gnutls_cipher( key )) == GNUTLS_CIPHER_UNKNOWN) return STATUS_NOT_SUPPORTED;
secret.data = key->u.s.secret; secret.data = key->u.s.secret;
secret.size = key->u.s.secret_len; secret.size = key->u.s.secret_len;
if (iv)
{
vector.data = iv;
vector.size = iv_len;
}
if ((ret = pgnutls_cipher_init( &key->u.s.handle, cipher, &secret, iv ? &vector : NULL ))) vector.data = key->u.s.vector;
vector.size = key->u.s.vector_len;
if ((ret = pgnutls_cipher_init( &key->u.s.handle, cipher, &secret, key->u.s.vector ? &vector : NULL )))
{ {
pgnutls_perror( ret ); pgnutls_perror( ret );
return STATUS_INTERNAL_ERROR; return STATUS_INTERNAL_ERROR;
...@@ -509,8 +526,12 @@ NTSTATUS key_symmetric_set_params( struct key *key, UCHAR *iv, ULONG iv_len ) ...@@ -509,8 +526,12 @@ NTSTATUS key_symmetric_set_params( struct key *key, UCHAR *iv, ULONG iv_len )
NTSTATUS key_symmetric_set_auth_data( struct key *key, UCHAR *auth_data, ULONG len ) NTSTATUS key_symmetric_set_auth_data( struct key *key, UCHAR *auth_data, ULONG len )
{ {
NTSTATUS status;
int ret; int ret;
if (!auth_data) return STATUS_SUCCESS; if (!auth_data) return STATUS_SUCCESS;
if ((status = init_cipher_handle( key ))) return status;
if ((ret = pgnutls_cipher_add_auth( key->u.s.handle, auth_data, len ))) if ((ret = pgnutls_cipher_add_auth( key->u.s.handle, auth_data, len )))
{ {
pgnutls_perror( ret ); pgnutls_perror( ret );
...@@ -521,7 +542,11 @@ NTSTATUS key_symmetric_set_auth_data( struct key *key, UCHAR *auth_data, ULONG l ...@@ -521,7 +542,11 @@ NTSTATUS key_symmetric_set_auth_data( struct key *key, UCHAR *auth_data, ULONG l
NTSTATUS key_symmetric_encrypt( struct key *key, const UCHAR *input, ULONG input_len, UCHAR *output, ULONG output_len ) NTSTATUS key_symmetric_encrypt( struct key *key, const UCHAR *input, ULONG input_len, UCHAR *output, ULONG output_len )
{ {
NTSTATUS status;
int ret; int ret;
if ((status = init_cipher_handle( key ))) return status;
if ((ret = pgnutls_cipher_encrypt2( key->u.s.handle, input, input_len, output, output_len ))) if ((ret = pgnutls_cipher_encrypt2( key->u.s.handle, input, input_len, output, output_len )))
{ {
pgnutls_perror( ret ); pgnutls_perror( ret );
...@@ -532,7 +557,11 @@ NTSTATUS key_symmetric_encrypt( struct key *key, const UCHAR *input, ULONG input ...@@ -532,7 +557,11 @@ NTSTATUS key_symmetric_encrypt( struct key *key, const UCHAR *input, ULONG input
NTSTATUS key_symmetric_decrypt( struct key *key, const UCHAR *input, ULONG input_len, UCHAR *output, ULONG output_len ) NTSTATUS key_symmetric_decrypt( struct key *key, const UCHAR *input, ULONG input_len, UCHAR *output, ULONG output_len )
{ {
NTSTATUS status;
int ret; int ret;
if ((status = init_cipher_handle( key ))) return status;
if ((ret = pgnutls_cipher_decrypt2( key->u.s.handle, input, input_len, output, output_len ))) if ((ret = pgnutls_cipher_decrypt2( key->u.s.handle, input, input_len, output, output_len )))
{ {
pgnutls_perror( ret ); pgnutls_perror( ret );
...@@ -543,7 +572,11 @@ NTSTATUS key_symmetric_decrypt( struct key *key, const UCHAR *input, ULONG input ...@@ -543,7 +572,11 @@ NTSTATUS key_symmetric_decrypt( struct key *key, const UCHAR *input, ULONG input
NTSTATUS key_symmetric_get_tag( struct key *key, UCHAR *tag, ULONG len ) NTSTATUS key_symmetric_get_tag( struct key *key, UCHAR *tag, ULONG len )
{ {
NTSTATUS status;
int ret; int ret;
if ((status = init_cipher_handle( key ))) return status;
if ((ret = pgnutls_cipher_tag( key->u.s.handle, tag, len ))) if ((ret = pgnutls_cipher_tag( key->u.s.handle, tag, len )))
{ {
pgnutls_perror( ret ); pgnutls_perror( ret );
...@@ -1128,6 +1161,7 @@ NTSTATUS key_destroy( struct key *key ) ...@@ -1128,6 +1161,7 @@ NTSTATUS key_destroy( struct key *key )
if (key_is_symmetric( key )) if (key_is_symmetric( key ))
{ {
if (key->u.s.handle) pgnutls_cipher_deinit( key->u.s.handle ); if (key->u.s.handle) pgnutls_cipher_deinit( key->u.s.handle );
heap_free( key->u.s.vector );
heap_free( key->u.s.secret ); heap_free( key->u.s.secret );
} }
else else
......
...@@ -106,6 +106,8 @@ NTSTATUS key_symmetric_init( struct key *key, struct algorithm *alg, const UCHAR ...@@ -106,6 +106,8 @@ NTSTATUS key_symmetric_init( struct key *key, struct algorithm *alg, const UCHAR
key->u.s.mode = alg->mode; key->u.s.mode = alg->mode;
key->u.s.ref_encrypt = NULL; /* initialized on first use */ key->u.s.ref_encrypt = NULL; /* initialized on first use */
key->u.s.ref_decrypt = NULL; key->u.s.ref_decrypt = NULL;
key->u.s.vector = NULL;
key->u.s.vector_len = 0;
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
...@@ -122,32 +124,50 @@ static CCMode get_cryptor_mode( struct key *key ) ...@@ -122,32 +124,50 @@ static CCMode get_cryptor_mode( struct key *key )
} }
} }
NTSTATUS key_symmetric_set_params( struct key *key, UCHAR *iv, ULONG iv_len ) NTSTATUS key_symmetric_set_vector( struct key *key, UCHAR *vector, ULONG vector_len )
{ {
CCCryptorStatus status; if (key->u.s.ref_encrypt && (!is_zero_vector( vector, vector_len ) ||
CCMode mode; !is_equal_vector( key->u.s.vector, key->u.s.vector_len, vector, vector_len )))
if (!(mode = get_cryptor_mode( key ))) return STATUS_NOT_SUPPORTED;
if (key->u.s.ref_encrypt)
{ {
TRACE( "invalidating cryptor handles\n" );
CCCryptorRelease( key->u.s.ref_encrypt ); CCCryptorRelease( key->u.s.ref_encrypt );
key->u.s.ref_encrypt = NULL; key->u.s.ref_encrypt = NULL;
}
if (key->u.s.ref_decrypt)
{
CCCryptorRelease( key->u.s.ref_decrypt ); CCCryptorRelease( key->u.s.ref_decrypt );
key->u.s.ref_decrypt = NULL; key->u.s.ref_decrypt = NULL;
} }
if ((status = CCCryptorCreateWithMode( kCCEncrypt, mode, kCCAlgorithmAES128, ccNoPadding, iv, key->u.s.secret, heap_free( key->u.s.vector );
key->u.s.secret_len, NULL, 0, 0, 0, &key->u.s.ref_encrypt )) != kCCSuccess) key->u.s.vector = NULL;
key->u.s.vector_len = 0;
if (vector)
{
if (!(key->u.s.vector = heap_alloc( vector_len ))) return STATUS_NO_MEMORY;
memcpy( key->u.s.vector, vector, vector_len );
key->u.s.vector_len = vector_len;
}
return STATUS_SUCCESS;
}
static NTSTATUS init_cryptor_handles( struct key *key )
{
CCCryptorStatus status;
CCMode mode;
if (key->u.s.ref_encrypt) return STATUS_SUCCESS;
if (!(mode = get_cryptor_mode( key ))) return STATUS_NOT_SUPPORTED;
if ((status = CCCryptorCreateWithMode( kCCEncrypt, mode, kCCAlgorithmAES128, ccNoPadding, key->u.s.vector,
key->u.s.secret, key->u.s.secret_len, NULL, 0, 0, 0,
&key->u.s.ref_encrypt )) != kCCSuccess)
{ {
WARN( "CCCryptorCreateWithMode failed %d\n", status ); WARN( "CCCryptorCreateWithMode failed %d\n", status );
return STATUS_INTERNAL_ERROR; return STATUS_INTERNAL_ERROR;
} }
if ((status = CCCryptorCreateWithMode( kCCDecrypt, mode, kCCAlgorithmAES128, ccNoPadding, iv, key->u.s.secret, if ((status = CCCryptorCreateWithMode( kCCDecrypt, mode, kCCAlgorithmAES128, ccNoPadding, key->u.s.vector,
key->u.s.secret_len, NULL, 0, 0, 0, &key->u.s.ref_decrypt )) != kCCSuccess) key->u.s.secret, key->u.s.secret_len, NULL, 0, 0, 0,
&key->u.s.ref_decrypt )) != kCCSuccess)
{ {
WARN( "CCCryptorCreateWithMode failed %d\n", status ); WARN( "CCCryptorCreateWithMode failed %d\n", status );
CCCryptorRelease( key->u.s.ref_encrypt ); CCCryptorRelease( key->u.s.ref_encrypt );
...@@ -167,6 +187,10 @@ NTSTATUS key_symmetric_set_auth_data( struct key *key, UCHAR *auth_data, ULONG l ...@@ -167,6 +187,10 @@ NTSTATUS key_symmetric_set_auth_data( struct key *key, UCHAR *auth_data, ULONG l
NTSTATUS key_symmetric_encrypt( struct key *key, const UCHAR *input, ULONG input_len, UCHAR *output, ULONG output_len ) NTSTATUS key_symmetric_encrypt( struct key *key, const UCHAR *input, ULONG input_len, UCHAR *output, ULONG output_len )
{ {
CCCryptorStatus status; CCCryptorStatus status;
NTSTATUS ret;
if ((ret = init_cryptor_handles( key ))) return ret;
if ((status = CCCryptorUpdate( key->u.s.ref_encrypt, input, input_len, output, output_len, NULL )) != kCCSuccess) if ((status = CCCryptorUpdate( key->u.s.ref_encrypt, input, input_len, output, output_len, NULL )) != kCCSuccess)
{ {
WARN( "CCCryptorUpdate failed %d\n", status ); WARN( "CCCryptorUpdate failed %d\n", status );
...@@ -178,6 +202,10 @@ NTSTATUS key_symmetric_encrypt( struct key *key, const UCHAR *input, ULONG input ...@@ -178,6 +202,10 @@ NTSTATUS key_symmetric_encrypt( struct key *key, const UCHAR *input, ULONG input
NTSTATUS key_symmetric_decrypt( struct key *key, const UCHAR *input, ULONG input_len, UCHAR *output, ULONG output_len ) NTSTATUS key_symmetric_decrypt( struct key *key, const UCHAR *input, ULONG input_len, UCHAR *output, ULONG output_len )
{ {
CCCryptorStatus status; CCCryptorStatus status;
NTSTATUS ret;
if ((ret = init_cryptor_handles( key ))) return ret;
if ((status = CCCryptorUpdate( key->u.s.ref_decrypt, input, input_len, output, output_len, NULL )) != kCCSuccess) if ((status = CCCryptorUpdate( key->u.s.ref_decrypt, input, input_len, output, output_len, NULL )) != kCCSuccess)
{ {
WARN( "CCCryptorUpdate failed %d\n", status ); WARN( "CCCryptorUpdate failed %d\n", status );
...@@ -235,6 +263,7 @@ NTSTATUS key_destroy( struct key *key ) ...@@ -235,6 +263,7 @@ NTSTATUS key_destroy( struct key *key )
{ {
if (key->u.s.ref_encrypt) CCCryptorRelease( key->u.s.ref_encrypt ); if (key->u.s.ref_encrypt) CCCryptorRelease( key->u.s.ref_encrypt );
if (key->u.s.ref_decrypt) CCCryptorRelease( key->u.s.ref_decrypt ); if (key->u.s.ref_decrypt) CCCryptorRelease( key->u.s.ref_decrypt );
heap_free( key->u.s.vector );
heap_free( key->u.s.secret ); heap_free( key->u.s.secret );
heap_free( key ); heap_free( key );
return STATUS_SUCCESS; return STATUS_SUCCESS;
......
...@@ -2128,6 +2128,74 @@ static void test_BCryptEnumAlgorithms(void) ...@@ -2128,6 +2128,74 @@ static void test_BCryptEnumAlgorithms(void)
pBCryptFreeBuffer( list ); pBCryptFreeBuffer( list );
} }
static void test_aes_vector(void)
{
static const UCHAR secret[] = {0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10};
static const UCHAR expect[] = {0xb0,0xcb,0xf5,0x80,0xd4,0xe3,0x55,0x23,0x6e,0x19,0x5b,0xdb,0xfe,0xe0,0x6c,0xd3};
static const UCHAR expect2[] = {0x06,0x0c,0x81,0xab,0xd4,0x28,0x80,0x42,0xce,0x30,0x56,0x17,0x15,0x00,0x9e,0xc1};
static const UCHAR expect3[] = {0x3e,0x99,0xbf,0x02,0xf5,0xd3,0xb8,0x81,0x91,0x4d,0x93,0xea,0xd4,0x92,0x93,0x46};
static UCHAR iv[16], input[] = {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p'};
UCHAR output[16];
BCRYPT_ALG_HANDLE alg;
BCRYPT_KEY_HANDLE key;
UCHAR data[sizeof(BCRYPT_KEY_DATA_BLOB_HEADER) + sizeof(secret)];
BCRYPT_KEY_DATA_BLOB_HEADER *blob = (BCRYPT_KEY_DATA_BLOB_HEADER *)data;
ULONG size;
NTSTATUS ret;
ret = pBCryptOpenAlgorithmProvider(&alg, BCRYPT_AES_ALGORITHM, NULL, 0);
ok(!ret, "got %08x\n", ret);
size = sizeof(BCRYPT_CHAIN_MODE_CBC);
ret = pBCryptSetProperty(alg, BCRYPT_CHAINING_MODE, (UCHAR *)BCRYPT_CHAIN_MODE_CBC, size, 0);
ok(!ret, "got %08x\n", ret);
blob->dwMagic = BCRYPT_KEY_DATA_BLOB_MAGIC;
blob->dwVersion = BCRYPT_KEY_DATA_BLOB_VERSION1;
blob->cbKeyData = sizeof(secret);
memcpy(data + sizeof(*blob), secret, sizeof(secret));
size = sizeof(BCRYPT_KEY_DATA_BLOB_HEADER) + sizeof(secret);
ret = pBCryptImportKey(alg, NULL, BCRYPT_KEY_DATA_BLOB, &key, NULL, 0, data, size, 0);
ok(!ret || broken(ret == STATUS_INVALID_PARAMETER) /* vista */, "got %08x\n", ret);
if (ret == STATUS_INVALID_PARAMETER)
{
win_skip("broken BCryptImportKey\n");
pBCryptCloseAlgorithmProvider(alg, 0);
return;
}
/* zero initialization vector */
size = 0;
memset(output, 0, sizeof(output));
ret = pBCryptEncrypt(key, input, sizeof(input), NULL, iv, sizeof(iv), output, sizeof(output), &size, 0);
ok(!ret, "got %08x\n", ret);
ok(size == 16, "got %u\n", size);
ok(!memcmp(output, expect, sizeof(expect)), "wrong cipher text\n");
/* same initialization vector */
size = 0;
memset(output, 0, sizeof(output));
ret = pBCryptEncrypt(key, input, sizeof(input), NULL, iv, sizeof(iv), output, sizeof(output), &size, 0);
ok(!ret, "got %08x\n", ret);
ok(size == 16, "got %u\n", size);
ok(!memcmp(output, expect2, sizeof(expect2)), "wrong cipher text\n");
/* different initialization vector */
iv[0] = 0x1;
size = 0;
memset(output, 0, sizeof(output));
ret = pBCryptEncrypt(key, input, sizeof(input), NULL, iv, sizeof(iv), output, sizeof(output), &size, 0);
ok(!ret, "got %08x\n", ret);
ok(size == 16, "got %u\n", size);
todo_wine ok(!memcmp(output, expect3, sizeof(expect3)), "wrong cipher text\n");
ret = pBCryptDestroyKey(key);
ok(!ret, "got %08x\n", ret);
ret = pBCryptCloseAlgorithmProvider(alg, 0);
ok(!ret, "got %08x\n", ret);
}
START_TEST(bcrypt) START_TEST(bcrypt)
{ {
HMODULE module; HMODULE module;
...@@ -2186,6 +2254,7 @@ START_TEST(bcrypt) ...@@ -2186,6 +2254,7 @@ START_TEST(bcrypt)
test_BCryptEnumContextFunctions(); test_BCryptEnumContextFunctions();
test_BCryptSignHash(); test_BCryptSignHash();
test_BCryptEnumAlgorithms(); test_BCryptEnumAlgorithms();
test_aes_vector();
FreeLibrary(module); FreeLibrary(module);
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment