Files

370 lines
8.5 KiB
C

/* -*- 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 <assert.h>
#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