/* -*- coding: utf-8 -*- */ /* -*- mode: c -*- */ /* * Dislocker -- enables to read/write on BitLocker encrypted partitions under * Linux * Copyright (C) 2012-2013 Romain Coltel, Hervé Schauer Consultants * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, * USA. */ #ifndef DATUM_HEADER_H #define DATUM_HEADER_H #include "dislocker/common.h" #include "dislocker/metadata/metadata.h" #include "dislocker/metadata/extended_info.h" #include "dislocker/metadata/guid.h" #include "dislocker/ntfs/clock.h" #include "dislocker/ntfs/encoding.h" #include "dislocker/encryption/encommon.h" #include #ifndef static_assert #define static_assert(x, s) extern int static_assertion[2*!!(x)-1] #endif /** * Here stand datums' value types stuff */ #define NB_DATUMS_VALUE_TYPES 20 enum value_types { /* 0 */ DATUMS_VALUE_ERASED = 0x0000, /* 1 */ DATUMS_VALUE_KEY, /* 2 */ DATUMS_VALUE_UNICODE, /* 3 */ DATUMS_VALUE_STRETCH_KEY, /* 4 */ DATUMS_VALUE_USE_KEY, /* 5 */ DATUMS_VALUE_AES_CCM, /* 6 */ DATUMS_VALUE_TPM_ENCODED, /* 7 */ DATUMS_VALUE_VALIDATION, /* 8 */ DATUMS_VALUE_VMK, /* 9 */ DATUMS_VALUE_EXTERNAL_KEY, /* 10 */ DATUMS_VALUE_UPDATE, /* 11 */ DATUMS_VALUE_ERROR, /* Below is only available on Windows Seven */ /* 12 */ DATUMS_VALUE_ASYM_ENC, /* 13 */ DATUMS_VALUE_EXPORTED_KEY, /* 14 */ DATUMS_VALUE_PUBLIC_KEY, /* 15 */ DATUMS_VALUE_VIRTUALIZATION_INFO, /* 16 */ DATUMS_VALUE_SIMPLE_1, /* 17 */ DATUMS_VALUE_SIMPLE_2, /* 18 */ DATUMS_VALUE_CONCAT_HASH_KEY, /* 19 */ DATUMS_VALUE_SIMPLE_3 }; typedef uint16_t dis_datums_value_type_t; /* Here are some specifics entry types (second field of the safe header) */ #define NB_DATUMS_ENTRY_TYPES 12 enum entry_types { DATUMS_ENTRY_UNKNOWN1 = 0x0000, DATUMS_ENTRY_UNKNOWN2, DATUMS_ENTRY_VMK, DATUMS_ENTRY_FVEK, DATUMS_ENTRY_UNKNOWN3, DATUMS_ENTRY_UNKNOWN4, DATUMS_ENTRY_STARTUP_KEY, DATUMS_ENTRY_ENCTIME_INFORMATION, DATUMS_ENTRY_UNKNOWN7, DATUMS_ENTRY_UNKNOWN8, DATUMS_ENTRY_UNKNOWN9, DATUMS_ENTRY_UNKNOWN10, DATUMS_ENTRY_FVEK_2 }; typedef uint16_t dis_datums_entry_type_t; /** * This is the minimal header a datum has */ #pragma pack (1) typedef struct _header_safe { uint16_t datum_size; dis_datums_entry_type_t entry_type; dis_datums_value_type_t value_type; uint16_t error_status; } datum_header_safe_t; static_assert( sizeof(struct _header_safe) == 8, "Datum header structure's size isn't equal to 8" ); /** * Used if the datum header is not implemented yet, according to the datum type */ typedef struct _datum_generic { datum_header_safe_t header; // uint8_t* payload; } datum_generic_type_t; /** * Here are datum headers, according to their datum type */ /* Datum type = 0 */ typedef struct _datum_erased { datum_header_safe_t header; } datum_erased_t; /* Datum type = 1 */ typedef struct _datum_key { datum_header_safe_t header; cipher_t algo; uint16_t padd; } datum_key_t; /* Datum type = 2 */ typedef struct _datum_unicode { datum_header_safe_t header; } datum_unicode_t; /* Datum type = 3 */ typedef struct _datum_stretch_key { datum_header_safe_t header; cipher_t algo; uint16_t padd; uint8_t salt[16]; } datum_stretch_key_t; /* Datum type = 4 */ typedef struct _datum_use_key { datum_header_safe_t header; cipher_t algo; uint16_t padd; } datum_use_key_t; /* Datum type = 5 */ typedef struct _datum_aes_ccm { datum_header_safe_t header; uint8_t nonce[12]; uint8_t mac[16]; } datum_aes_ccm_t; /* Datum type = 6 */ typedef struct _datum_tpm_enc { datum_header_safe_t header; uint32_t unknown; // See properties below, the header size of this datum is 0xc => header + int32 (int32 possibly divided into more members) } datum_tpm_enc_t; /* Datum type = 8 */ typedef struct _datum_vmk { datum_header_safe_t header; guid_t guid; uint8_t nonce[12]; } datum_vmk_t; /* Datum type = 9 */ typedef struct _datum_external { datum_header_safe_t header; guid_t guid; ntfs_time_t timestamp; } datum_external_t; /* Datum type = 15 */ typedef struct _datum_virtualization { datum_header_safe_t header; uint64_t ntfs_boot_sectors; uint64_t nb_bytes; /* * Below is a structure added to this virtualization structure in Windows 8 * The header is still 0x18 in size, which means xinfo is a payload */ extended_info_t xinfo; } datum_virtualization_t; #pragma pack () /** * A hardcoded table defining some properties for each datum */ typedef struct _datum_value_types_properties { /* * The header size of the datum, this is including the datum_header_safe_t * structure which is beginning each one of them */ uint16_t size_header; /* * A flag which tells us if the datum has one or more nested datum * 0 = No nested datum * 1 = One or more nested datum */ uint8_t has_nested_datum; /* Always equal to 0, maybe for padding */ uint8_t zero; } value_types_properties_t; static const value_types_properties_t datum_value_types_prop[] = { { 8, 0, 0 }, // ERASED { 0xc, 0, 0 }, // KEY { 8, 0, 0 }, // UNICODE { 0x1c, 1, 0 }, // STRETCH { 0xc, 1, 0 }, // USE KEY { 0x24, 0, 0 }, // AES CCM { 0xc, 0, 0 }, // TPM ENCODED { 8, 0, 0 }, // VALIDATION { 0x24, 1, 0 }, // VMK { 0x20, 1, 0 }, // EXTERNAL KEY { 0x2c, 1, 0 }, // UPDATE { 0x34, 0, 0 }, // ERROR /* These ones below were added for Seven */ { 8, 0, 0 }, // ASYM ENC { 8, 0, 0 }, // EXPORTED KEY { 8, 0, 0 }, // PUBLIC KEY { 0x18, 0, 0 }, // VIRTUALIZATION INFO { 0xc, 0, 0 }, // SIMPLE { 0xc, 0, 0 }, // SIMPLE { 0x1c, 0, 0 }, // CONCAT HASH KEY { 0xc, 0, 0 } // SIMPLE }; /* * Here are prototypes of functions dealing with data */ char* cipherstr(cipher_t enc); char* datumvaluetypestr(dis_datums_value_type_t value_type); int get_header_safe(void* data, datum_header_safe_t* header); int get_payload_safe(void* data, void** payload, size_t* size_payload); void print_one_datum(DIS_LOGS level, void* datum); void print_header(DIS_LOGS level, datum_header_safe_t* header); void print_datum_generic(DIS_LOGS level, void* vdatum); void print_datum_erased(DIS_LOGS level, void* vdatum); void print_datum_key(DIS_LOGS level, void* vdatum); void print_datum_unicode(DIS_LOGS level, void* vdatum); void print_datum_stretch_key(DIS_LOGS level, void* vdatum); void print_datum_use_key(DIS_LOGS level, void* vdatum); void print_datum_aes_ccm(DIS_LOGS level, void* vdatum); void print_datum_tpmenc(DIS_LOGS level, void* vdatum); void print_datum_vmk(DIS_LOGS level, void* vdatum); void print_datum_external(DIS_LOGS level, void* vdatum); void print_datum_virtualization(DIS_LOGS level, void* vdatum); void print_nonce(DIS_LOGS level, uint8_t* nonce); void print_mac(DIS_LOGS level, uint8_t* mac); int get_next_datum( dis_metadata_t dis_metadata, dis_datums_entry_type_t entry_type, dis_datums_value_type_t value_type, void* datum_begin, void** datum_result ); int get_nested_datum(void* datum, void** datum_nested); int get_nested_datumvaluetype(void* datum, dis_datums_value_type_t value_type, void** datum_nested); int datum_value_type_must_be(void* datum, dis_datums_value_type_t value_type); int dis_metadata_has_clear_key(dis_metadata_t dis_meta, void** vmk_datum); typedef void(*print_datum_f)(DIS_LOGS, void*); static const print_datum_f print_datum_tab[NB_DATUMS_VALUE_TYPES] = { print_datum_erased, print_datum_key, print_datum_unicode, print_datum_stretch_key, print_datum_use_key, print_datum_aes_ccm, print_datum_tpmenc, print_datum_generic, print_datum_vmk, print_datum_external, print_datum_generic, print_datum_generic, print_datum_generic, print_datum_generic, print_datum_generic, print_datum_virtualization, print_datum_generic, print_datum_generic, print_datum_generic, print_datum_generic, }; #ifdef _HAVE_RUBY #include "dislocker/ruby.h" void Init_datum(VALUE rb_cDislockerMetadata); VALUE rb_cDislockerMetadataDatum_new(VALUE klass, VALUE datum); #endif #endif // DATUM_HEADER_H