/* 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 ); }
/* De- or encrypts a block of data * Returns 1 if successful or -1 on error */ int libqcow_encryption_crypt( libqcow_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 initialization_vector[ 16 ]; static char *function = "libqcow_encryption_crypt"; size_t 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 != LIBQCOW_ENCYPTION_CRYPT_MODE_DECRYPT ) && ( mode != LIBQCOW_ENCYPTION_CRYPT_MODE_ENCRYPT ) ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE, "%s: unsupported mode.", function ); return( -1 ); } if( ( input_data_size % 512 ) != 0 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS, "%s: invalid input data size value of bounds.", function ); return( -1 ); } if( output_data_size < input_data_size ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS, "%s: invalid output data size value of bounds.", function ); return( -1 ); } while( data_index < input_data_size ) { 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 ); } byte_stream_copy_from_uint64_little_endian( initialization_vector, block_key ); if( mode == LIBQCOW_ENCYPTION_CRYPT_MODE_ENCRYPT ) { if( libcaes_crypt_cbc( context->encryption_context, LIBCAES_CRYPT_MODE_ENCRYPT, initialization_vector, 16, &( input_data[ data_index ] ), 512, &( output_data[ data_index ] ), 512, 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( libcaes_crypt_cbc( context->decryption_context, LIBCAES_CRYPT_MODE_DECRYPT, initialization_vector, 16, &( input_data[ data_index ] ), 512, &( output_data[ data_index ] ), 512, 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 ); } } data_index += 512; block_key += 1; } return( 1 ); }