/* De- or encrypts a block of data * Returns 1 if successful or -1 on error */ int libbde_encryption_crypt( libbde_encryption_context_t *context, int mode, const uint8_t *input_data, size_t input_data_size, uint8_t *output_data, size_t output_data_size, uint64_t block_key, libcerror_error_t **error ) { uint8_t block_key_data[ 16 ]; uint8_t initialization_vector[ 16 ]; uint8_t sector_key_data[ 32 ]; static char *function = "libbde_encryption_crypt"; size_t data_index = 0; size_t sector_key_data_index = 0; if( context == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, "%s: invalid context.", function ); return( -1 ); } if( ( mode != LIBBDE_ENCRYPTION_CRYPT_MODE_DECRYPT ) && ( mode != LIBBDE_ENCRYPTION_CRYPT_MODE_ENCRYPT ) ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE, "%s: unsupported mode.", function ); return( -1 ); } if( memory_set( initialization_vector, 0, 16 ) == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_MEMORY, LIBCERROR_MEMORY_ERROR_SET_FAILED, "%s: unable to clear initialization vector.", function ); return( -1 ); } if( memory_set( block_key_data, 0, 16 ) == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_MEMORY, LIBCERROR_MEMORY_ERROR_SET_FAILED, "%s: unable to clear block key data.", function ); return( -1 ); } if( memory_set( sector_key_data, 0, 32 ) == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_MEMORY, LIBCERROR_MEMORY_ERROR_SET_FAILED, "%s: unable to clear sector key data.", function ); return( -1 ); } if( ( context->method == LIBBDE_ENCRYPTION_METHOD_AES_128_CBC ) || ( context->method == LIBBDE_ENCRYPTION_METHOD_AES_128_CBC_DIFFUSER ) || ( context->method == LIBBDE_ENCRYPTION_METHOD_AES_256_CBC ) || ( context->method == LIBBDE_ENCRYPTION_METHOD_AES_256_CBC_DIFFUSER ) ) { byte_stream_copy_from_uint64_little_endian( block_key_data, block_key ); /* The block key for the initialization vector is encrypted * with the FVEK */ if( libcaes_crypt_ecb( context->fvek_encryption_context, LIBCAES_CRYPT_MODE_ENCRYPT, block_key_data, 16, initialization_vector, 16, error ) != 1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ENCRYPTION, LIBCERROR_ENCRYPTION_ERROR_GENERIC, "%s: unable to encrypt initialization vector.", function ); return( -1 ); } if( ( context->method == LIBBDE_ENCRYPTION_METHOD_AES_128_CBC_DIFFUSER ) || ( context->method == LIBBDE_ENCRYPTION_METHOD_AES_256_CBC_DIFFUSER ) ) { /* The block key for the sector key data is encrypted * with the TWEAK key */ if( libcaes_crypt_ecb( context->tweak_encryption_context, LIBCAES_CRYPT_MODE_ENCRYPT, block_key_data, 16, sector_key_data, 16, error ) != 1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ENCRYPTION, LIBCERROR_ENCRYPTION_ERROR_GENERIC, "%s: unable to encrypt sector key data.", function ); return( -1 ); } /* Set the last byte to contain 0x80 (128) */ block_key_data[ 15 ] = 0x80; if( libcaes_crypt_ecb( context->tweak_encryption_context, LIBCAES_CRYPT_MODE_ENCRYPT, block_key_data, 16, &( sector_key_data[ 16 ] ), 16, error ) != 1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ENCRYPTION, LIBCERROR_ENCRYPTION_ERROR_GENERIC, "%s: unable to encrypt sector key data.", function ); return( -1 ); } } } else if( ( context->method == LIBBDE_ENCRYPTION_METHOD_AES_128_XTS ) || ( context->method == LIBBDE_ENCRYPTION_METHOD_AES_256_XTS ) ) { byte_stream_copy_from_uint64_little_endian( initialization_vector, block_key ); /* TODO: implement */ } #if defined( HAVE_DEBUG_OUTPUT ) if( libcnotify_verbose != 0 ) { libcnotify_printf( "%s: initialization vector:\n", function ); libcnotify_print_data( initialization_vector, 16, 0 ); } #endif if( mode == LIBBDE_ENCRYPTION_CRYPT_MODE_ENCRYPT ) { /* TODO safe guard input data ? */ if( ( context->method == LIBBDE_ENCRYPTION_METHOD_AES_128_CBC_DIFFUSER ) || ( context->method == LIBBDE_ENCRYPTION_METHOD_AES_256_CBC_DIFFUSER ) ) { sector_key_data_index = 0; for( data_index = 0; data_index < input_data_size; data_index++ ) { output_data[ data_index ] ^= sector_key_data[ sector_key_data_index ]; sector_key_data_index++; if( sector_key_data_index >= 32 ) { sector_key_data_index -= 32; } } if( libbde_diffuser_encrypt( output_data, output_data_size, error ) != 1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ENCRYPTION, LIBCERROR_ENCRYPTION_ERROR_ENCRYPT_FAILED, "%s: unable to encrypt data using Diffuser.", function ); return( -1 ); } } if( ( context->method == LIBBDE_ENCRYPTION_METHOD_AES_128_CBC ) || ( context->method == LIBBDE_ENCRYPTION_METHOD_AES_128_CBC_DIFFUSER ) || ( context->method == LIBBDE_ENCRYPTION_METHOD_AES_256_CBC ) || ( context->method == LIBBDE_ENCRYPTION_METHOD_AES_256_CBC_DIFFUSER ) ) { if( libcaes_crypt_cbc( context->fvek_encryption_context, LIBCAES_CRYPT_MODE_ENCRYPT, initialization_vector, 16, input_data, input_data_size, output_data, output_data_size, error ) != 1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ENCRYPTION, LIBCERROR_ENCRYPTION_ERROR_GENERIC, "%s: unable to AES-CBC encrypt output data.", function ); return( -1 ); } } else if( ( context->method == LIBBDE_ENCRYPTION_METHOD_AES_128_XTS ) || ( context->method == LIBBDE_ENCRYPTION_METHOD_AES_256_XTS ) ) { if( libcaes_crypt_xts( context->fvek_decryption_tweaked_context, LIBCAES_CRYPT_MODE_ENCRYPT, initialization_vector, 16, input_data, input_data_size, output_data, output_data_size, error ) != 1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ENCRYPTION, LIBCERROR_ENCRYPTION_ERROR_GENERIC, "%s: unable to AES-XTS decrypt output data.", function ); return( -1 ); } } } else { if( ( context->method == LIBBDE_ENCRYPTION_METHOD_AES_128_CBC ) || ( context->method == LIBBDE_ENCRYPTION_METHOD_AES_128_CBC_DIFFUSER ) || ( context->method == LIBBDE_ENCRYPTION_METHOD_AES_256_CBC ) || ( context->method == LIBBDE_ENCRYPTION_METHOD_AES_256_CBC_DIFFUSER ) ) { if( libcaes_crypt_cbc( context->fvek_decryption_context, LIBCAES_CRYPT_MODE_DECRYPT, initialization_vector, 16, input_data, input_data_size, output_data, output_data_size, error ) != 1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ENCRYPTION, LIBCERROR_ENCRYPTION_ERROR_GENERIC, "%s: unable to AES-CBC decrypt output data.", function ); return( -1 ); } } else if( ( context->method == LIBBDE_ENCRYPTION_METHOD_AES_128_XTS ) || ( context->method == LIBBDE_ENCRYPTION_METHOD_AES_256_XTS ) ) { if( libcaes_crypt_xts( context->fvek_decryption_tweaked_context, LIBCAES_CRYPT_MODE_DECRYPT, initialization_vector, 16, input_data, input_data_size, output_data, output_data_size, error ) != 1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ENCRYPTION, LIBCERROR_ENCRYPTION_ERROR_GENERIC, "%s: unable to AES-XTS decrypt output data.", function ); return( -1 ); } } if( ( context->method == LIBBDE_ENCRYPTION_METHOD_AES_128_CBC_DIFFUSER ) || ( context->method == LIBBDE_ENCRYPTION_METHOD_AES_256_CBC_DIFFUSER ) ) { if( libbde_diffuser_decrypt( output_data, output_data_size, error ) != 1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ENCRYPTION, LIBCERROR_ENCRYPTION_ERROR_DECRYPT_FAILED, "%s: unable to decrypt data using Diffuser.", function ); return( -1 ); } sector_key_data_index = 0; for( data_index = 0; data_index < input_data_size; data_index++ ) { output_data[ data_index ] ^= sector_key_data[ sector_key_data_index ]; sector_key_data_index++; if( sector_key_data_index >= 32 ) { sector_key_data_index -= 32; } } } } return( 1 ); }
/* Unwrap data using AES Key Wrap (RFC3394) * Returns 1 if successful or -1 on error */ int libfvde_encryption_aes_key_unwrap( const uint8_t *key, size_t key_bit_size, const uint8_t *wrapped_data, size_t wrapped_data_size, uint8_t *unwrapped_data, size_t unwrapped_data_size, libcerror_error_t **error ) { uint8_t block_data[ 16 ]; uint8_t vector_data[ 8 ]; libcaes_context_t *aes_context = NULL; uint8_t *initialization_vector = NULL; static char *function = "libfvde_encryption_aes_key_unwrap"; size_t block_offset = 0; size_t number_of_blocks = 0; size_t block_index = 0; int8_t round_index = 0; if( key == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, "%s: invalid AES key.", function); return( -1 ); } if( ( key_bit_size != 128 ) && ( key_bit_size != 192 ) && ( key_bit_size != 256 ) ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS, "%s: invalid AES key length value out of bounds.", function); return( -1 ); } if( wrapped_data == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, "%s: invalid wrapped data.", function); return( -1 ); } if( wrapped_data_size > (size_t) SSIZE_MAX ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM, "%s: invalid wrapped data size value exceeds maximum.", function ); return( -1 ); } if( wrapped_data_size <= 8 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL, "%s: invalid wrapped data size value too small.", function); return( -1 ); } if( ( wrapped_data_size % 8 ) != 0 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS, "%s: invalid wrapped data size value not a multitude of 8.", function); return( -1 ); } if( unwrapped_data == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, "%s: invalid unwrapped data.", function); return( -1 ); } if( unwrapped_data_size > (size_t) SSIZE_MAX ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM, "%s: invalid unwrapped data size value exceeds maximum.", function ); return( -1 ); } if( unwrapped_data_size < wrapped_data_size ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL, "%s: invalid unwrapped data size value too small.", function); return( -1 ); } if( libcaes_context_initialize( &aes_context, error ) != 1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED, "%s: unable to initialize AES context.", function ); goto on_error; } if( libcaes_crypt_set_key( aes_context, LIBCAES_CRYPT_MODE_DECRYPT, key, key_bit_size, error ) != 1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_SET_FAILED, "%s: unable to set key in AES context.", function ); goto on_error; } if( memory_copy( unwrapped_data, wrapped_data, wrapped_data_size ) == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_MEMORY, LIBCERROR_MEMORY_ERROR_COPY_FAILED, "%s: unable to copy wrapped data.", function ); goto on_error; } number_of_blocks = wrapped_data_size / 8; #if defined( HAVE_DEBUG_OUTPUT ) if( libcnotify_verbose != 0 ) { libcnotify_printf( "%s: number of blocks: %" PRIzd "\n", function, number_of_blocks ); libcnotify_printf( "%s: wrapped data:\n", function ); libcnotify_print_data( wrapped_data, wrapped_data_size, 0 ); } #endif /* TODO make this code more readable */ initialization_vector = unwrapped_data; for( round_index = 5; round_index >= 0; round_index-- ) { for( block_index = number_of_blocks - 1; block_index > 0; block_index-- ) { block_offset = block_index * 8; byte_stream_copy_from_uint64_big_endian( vector_data, (uint64_t) ( round_index * ( number_of_blocks - 1 ) + block_index ) ); vector_data[ 0 ] ^= initialization_vector[ 0 ]; vector_data[ 1 ] ^= initialization_vector[ 1 ]; vector_data[ 2 ] ^= initialization_vector[ 2 ]; vector_data[ 3 ] ^= initialization_vector[ 3 ]; vector_data[ 4 ] ^= initialization_vector[ 4 ]; vector_data[ 5 ] ^= initialization_vector[ 5 ]; vector_data[ 6 ] ^= initialization_vector[ 6 ]; vector_data[ 7 ] ^= initialization_vector[ 7 ]; if( memory_copy( &( block_data[ 0 ] ), vector_data, 8 ) == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_MEMORY, LIBCERROR_MEMORY_ERROR_COPY_FAILED, "%s: unable to copy vector data to block data.", function ); goto on_error; } if( memory_copy( &( block_data[ 8 ] ), &( unwrapped_data[ block_offset ] ), 8 ) == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_MEMORY, LIBCERROR_MEMORY_ERROR_COPY_FAILED, "%s: unable to copy unwrapped data to block data.", function ); goto on_error; } if( libcaes_crypt_ecb( aes_context, LIBCAES_CRYPT_MODE_DECRYPT, block_data, 16, block_data, 16, error ) != 1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ENCRYPTION, LIBCERROR_ENCRYPTION_ERROR_DECRYPT_FAILED, "%s: unable to decrypt block data.", function ); goto on_error; } if( memory_copy( initialization_vector, &( block_data[ 0 ] ), 8 ) == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_MEMORY, LIBCERROR_MEMORY_ERROR_COPY_FAILED, "%s: unable to decrypted block data to initialization vector.", function ); goto on_error; } if( memory_copy( &( unwrapped_data[ block_offset ] ), &( block_data[ 8 ] ), 8 ) == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_MEMORY, LIBCERROR_MEMORY_ERROR_COPY_FAILED, "%s: unable to copy decrypted block data to unwrapped data.", function ); goto on_error; } } } if( libcaes_context_free( &aes_context, error ) != 1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED, "%s: unable to free AES context.", function ); goto on_error; } #if defined( HAVE_DEBUG_OUTPUT ) if( libcnotify_verbose != 0 ) { libcnotify_printf( "%s: unwrapped data:\n", function ); libcnotify_print_data( unwrapped_data, wrapped_data_size, 0 ); } #endif return( 1 ); on_error: if( aes_context != NULL ) { libcaes_context_free( &aes_context, NULL); } return( -1 ); }
/* De- or encrypts a block of data using AES-XTS (XEX-based tweaked-codebook mode with ciphertext stealing) * Returns 1 if successful or -1 on error */ int libcaes_crypt_xts( libcaes_tweaked_context_t *context, int mode, const uint8_t *tweak_value, size_t tweak_value_size, const uint8_t *input_data, size_t input_data_size, uint8_t *output_data, size_t output_data_size, libcerror_error_t **error ) { uint8_t encrypted_tweak_value[ 16 ]; uint8_t encrypted_tweak_value_copy[ 16 ]; libcaes_internal_tweaked_context_t *internal_context = NULL; static char *function = "libcaes_crypt_xts"; size_t data_offset = 0; size_t remaining_data_size = 0; uint8_t block_index = 0; uint8_t byte_value = 0; uint8_t carry_bit = 0; if( context == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, "%s: invalid context.", function ); return( -1 ); } internal_context = (libcaes_internal_tweaked_context_t *) context; if( ( mode != LIBCAES_CRYPT_MODE_DECRYPT ) && ( mode != LIBCAES_CRYPT_MODE_ENCRYPT ) ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE, "%s: unsupported mode.", function ); return( -1 ); } if( tweak_value == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, "%s: invalid tweak value.", function ); return( -1 ); } if( tweak_value_size != 16 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS, "%s: invalid tweak value size value out of bounds.", function ); return( -1 ); } if( input_data == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, "%s: invalid input data.", function ); return( -1 ); } if( input_data_size < 16 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL, "%s: invalid input data size value too small.", function ); return( -1 ); } if( input_data_size > (size_t) SSIZE_MAX ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM, "%s: invalid input data size value exceeds maximum.", function ); return( -1 ); } if( output_data == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, "%s: invalid output data.", function ); return( -1 ); } if( output_data_size > (size_t) SSIZE_MAX ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM, "%s: invalid output data size value exceeds maximum.", function ); return( -1 ); } if( output_data_size < input_data_size ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS, "%s: invalid ouput data size smaller than input data size.", function ); return( -1 ); } if( libcaes_crypt_ecb( internal_context->tweak_context, LIBCAES_CRYPT_MODE_ENCRYPT, tweak_value, 16, encrypted_tweak_value, 16, error ) != 1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ENCRYPTION, LIBCERROR_ENCRYPTION_ERROR_GENERIC, "%s: unable to encrypt tweak value.", function ); goto on_error; } if( memory_copy( output_data, input_data, input_data_size ) == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_MEMORY, LIBCERROR_MEMORY_ERROR_COPY_FAILED, "%s: unable to copy input data to output data.", function ); return( -1 ); } remaining_data_size = input_data_size; while( ( data_offset + 16 ) <= input_data_size ) { if( ( remaining_data_size < 32 ) && ( remaining_data_size != 16 ) ) { /* If the input data size is not a multitude of 16 the remaining data needs to be handled differently */ if( mode == LIBCAES_CRYPT_MODE_DECRYPT ) { if( memory_copy( encrypted_tweak_value_copy, encrypted_tweak_value, 16 ) == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_MEMORY, LIBCERROR_MEMORY_ERROR_COPY_FAILED, "%s: unable to copy encrypted tweak value.", function ); goto on_error; } /* Update the encrypted tweak value for the next 16-byte block */ carry_bit = 0; for( block_index = 0; block_index < 16; block_index++ ) { byte_value = ( encrypted_tweak_value[ block_index ] << 1 ) | carry_bit; carry_bit = encrypted_tweak_value[ block_index ] >> 7; encrypted_tweak_value[ block_index ] = byte_value; } if( carry_bit > 0 ) { encrypted_tweak_value[ 0 ] ^= 0x87; } } } #if defined( LIBCAES_UNFOLLED_LOOPS ) output_data[ data_offset++ ] ^= encrypted_tweak_value[ 0 ]; output_data[ data_offset++ ] ^= encrypted_tweak_value[ 1 ]; output_data[ data_offset++ ] ^= encrypted_tweak_value[ 2 ]; output_data[ data_offset++ ] ^= encrypted_tweak_value[ 3 ]; output_data[ data_offset++ ] ^= encrypted_tweak_value[ 4 ]; output_data[ data_offset++ ] ^= encrypted_tweak_value[ 5 ]; output_data[ data_offset++ ] ^= encrypted_tweak_value[ 6 ]; output_data[ data_offset++ ] ^= encrypted_tweak_value[ 7 ]; output_data[ data_offset++ ] ^= encrypted_tweak_value[ 8 ]; output_data[ data_offset++ ] ^= encrypted_tweak_value[ 9 ]; output_data[ data_offset++ ] ^= encrypted_tweak_value[ 10 ]; output_data[ data_offset++ ] ^= encrypted_tweak_value[ 11 ]; output_data[ data_offset++ ] ^= encrypted_tweak_value[ 12 ]; output_data[ data_offset++ ] ^= encrypted_tweak_value[ 13 ]; output_data[ data_offset++ ] ^= encrypted_tweak_value[ 14 ]; output_data[ data_offset++ ] ^= encrypted_tweak_value[ 15 ]; #else for( block_index = 0; block_index < 16; block_index++ ) { output_data[ data_offset++ ] ^= encrypted_tweak_value[ block_index ]; } #endif data_offset -= 16; if( libcaes_crypt_ecb( internal_context->main_context, mode, &( output_data[ data_offset ] ), 16, &( output_data[ data_offset ] ), 16, error ) != 1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ENCRYPTION, LIBCERROR_ENCRYPTION_ERROR_GENERIC, "%s: unable to de/encrypt data.", function ); goto on_error; } #if defined( LIBCAES_UNFOLLED_LOOPS ) output_data[ data_offset++ ] ^= encrypted_tweak_value[ 0 ]; output_data[ data_offset++ ] ^= encrypted_tweak_value[ 1 ]; output_data[ data_offset++ ] ^= encrypted_tweak_value[ 2 ]; output_data[ data_offset++ ] ^= encrypted_tweak_value[ 3 ]; output_data[ data_offset++ ] ^= encrypted_tweak_value[ 4 ]; output_data[ data_offset++ ] ^= encrypted_tweak_value[ 5 ]; output_data[ data_offset++ ] ^= encrypted_tweak_value[ 6 ]; output_data[ data_offset++ ] ^= encrypted_tweak_value[ 7 ]; output_data[ data_offset++ ] ^= encrypted_tweak_value[ 8 ]; output_data[ data_offset++ ] ^= encrypted_tweak_value[ 9 ]; output_data[ data_offset++ ] ^= encrypted_tweak_value[ 10 ]; output_data[ data_offset++ ] ^= encrypted_tweak_value[ 11 ]; output_data[ data_offset++ ] ^= encrypted_tweak_value[ 12 ]; output_data[ data_offset++ ] ^= encrypted_tweak_value[ 13 ]; output_data[ data_offset++ ] ^= encrypted_tweak_value[ 14 ]; output_data[ data_offset++ ] ^= encrypted_tweak_value[ 15 ]; #else for( block_index = 0; block_index < 16; block_index++ ) { output_data[ data_offset++ ] ^= encrypted_tweak_value[ block_index ]; } #endif remaining_data_size -= 16; /* Update the encrypted tweak value for the next 16-byte block */ carry_bit = 0; for( block_index = 0; block_index < 16; block_index++ ) { byte_value = ( encrypted_tweak_value[ block_index ] << 1 ) | carry_bit; carry_bit = encrypted_tweak_value[ block_index ] >> 7; encrypted_tweak_value[ block_index ] = byte_value; } if( carry_bit > 0 ) { encrypted_tweak_value[ 0 ] ^= 0x87; } } /* Any remaining data needs to be handled differently */ if( remaining_data_size > 0 ) { if( mode == LIBCAES_CRYPT_MODE_DECRYPT ) { if( memory_copy( encrypted_tweak_value, encrypted_tweak_value_copy, 16 ) == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_MEMORY, LIBCERROR_MEMORY_ERROR_COPY_FAILED, "%s: unable to copy encrypted tweak value.", function ); goto on_error; } if( memory_set( encrypted_tweak_value_copy, 0, 16 ) == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_MEMORY, LIBCERROR_MEMORY_ERROR_SET_FAILED, "%s: unable to clear encrypted tweak value copy.", function ); goto on_error; } } /* Swap the data of the last 16-byte block with the remaining data */ data_offset -= 16; if( memory_copy( &( output_data[ data_offset + 16 ] ), &( output_data[ data_offset ] ), remaining_data_size ) == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_MEMORY, LIBCERROR_MEMORY_ERROR_COPY_FAILED, "%s: unable to copy remaining output data.", function ); goto on_error; } if( memory_copy( &( output_data[ data_offset ] ), &( input_data[ data_offset + 16 ] ), remaining_data_size ) == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_MEMORY, LIBCERROR_MEMORY_ERROR_COPY_FAILED, "%s: unable to copy input data to block data.", function ); goto on_error; } #if defined( LIBCAES_UNFOLLED_LOOPS ) output_data[ data_offset++ ] ^= encrypted_tweak_value[ 0 ]; output_data[ data_offset++ ] ^= encrypted_tweak_value[ 1 ]; output_data[ data_offset++ ] ^= encrypted_tweak_value[ 2 ]; output_data[ data_offset++ ] ^= encrypted_tweak_value[ 3 ]; output_data[ data_offset++ ] ^= encrypted_tweak_value[ 4 ]; output_data[ data_offset++ ] ^= encrypted_tweak_value[ 5 ]; output_data[ data_offset++ ] ^= encrypted_tweak_value[ 6 ]; output_data[ data_offset++ ] ^= encrypted_tweak_value[ 7 ]; output_data[ data_offset++ ] ^= encrypted_tweak_value[ 8 ]; output_data[ data_offset++ ] ^= encrypted_tweak_value[ 9 ]; output_data[ data_offset++ ] ^= encrypted_tweak_value[ 10 ]; output_data[ data_offset++ ] ^= encrypted_tweak_value[ 11 ]; output_data[ data_offset++ ] ^= encrypted_tweak_value[ 12 ]; output_data[ data_offset++ ] ^= encrypted_tweak_value[ 13 ]; output_data[ data_offset++ ] ^= encrypted_tweak_value[ 14 ]; output_data[ data_offset++ ] ^= encrypted_tweak_value[ 15 ]; #else for( block_index = 0; block_index < 16; block_index++ ) { output_data[ data_offset++ ] ^= encrypted_tweak_value[ block_index ]; } #endif data_offset -= 16; if( libcaes_crypt_ecb( internal_context->main_context, mode, &( output_data[ data_offset ] ), 16, &( output_data[ data_offset ] ), 16, error ) != 1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ENCRYPTION, LIBCERROR_ENCRYPTION_ERROR_GENERIC, "%s: unable to de/encrypt data.", function ); goto on_error; } #if defined( LIBCAES_UNFOLLED_LOOPS ) output_data[ data_offset++ ] ^= encrypted_tweak_value[ 0 ]; output_data[ data_offset++ ] ^= encrypted_tweak_value[ 1 ]; output_data[ data_offset++ ] ^= encrypted_tweak_value[ 2 ]; output_data[ data_offset++ ] ^= encrypted_tweak_value[ 3 ]; output_data[ data_offset++ ] ^= encrypted_tweak_value[ 4 ]; output_data[ data_offset++ ] ^= encrypted_tweak_value[ 5 ]; output_data[ data_offset++ ] ^= encrypted_tweak_value[ 6 ]; output_data[ data_offset++ ] ^= encrypted_tweak_value[ 7 ]; output_data[ data_offset++ ] ^= encrypted_tweak_value[ 8 ]; output_data[ data_offset++ ] ^= encrypted_tweak_value[ 9 ]; output_data[ data_offset++ ] ^= encrypted_tweak_value[ 10 ]; output_data[ data_offset++ ] ^= encrypted_tweak_value[ 11 ]; output_data[ data_offset++ ] ^= encrypted_tweak_value[ 12 ]; output_data[ data_offset++ ] ^= encrypted_tweak_value[ 13 ]; output_data[ data_offset++ ] ^= encrypted_tweak_value[ 14 ]; output_data[ data_offset++ ] ^= encrypted_tweak_value[ 15 ]; #else for( block_index = 0; block_index < 16; block_index++ ) { output_data[ data_offset++ ] ^= encrypted_tweak_value[ block_index ]; } #endif } if( memory_set( encrypted_tweak_value, 0, 16 ) == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_MEMORY, LIBCERROR_MEMORY_ERROR_SET_FAILED, "%s: unable to clear encrypted tweak value.", function ); goto on_error; } return( 1 ); on_error: memory_set( encrypted_tweak_value_copy, 0, 16 ); memory_set( encrypted_tweak_value, 0, 16 ); return( -1 ); }