SKETCH OF HOW RESEARCH MIGHT CONTINUE AND RESULTS BE PRESENTED

FVE_DATUM

The FVE_DATUM structure (formally _FVE_DATUM) is the most basic of fixed-size headers in the packaging of arbitrary BitLocker data. Each datum is wrapped with descriptions of such things as its type and purpose. For instance, the raw bytes of an encryption key may be packaged with indications of which algorithm to use and of what it’s intended to encrypt. The whole datum is a fixed-size header and some variable-size continuation. The header is the wrapping. The continuation is the raw datum. Different types of datum have different fixed-size headers, but all begin the same way: the FVE_DATUM is the fixed-size header that is common to all the type-specific headers.

Documentation Status

No documentation of the FVE_DATUM structure is known from Microsoft, but the name is Microsoft’s. This is knowable from public symbol files for the user-mode FVEAPI.DLL, many of whose internal routines are written in C++ such that types of arguments survive in decorated names.

For some types of datum, the variable-size continuation beyond the fixed-size header is a sequence of nested data, each in this form of a fixed-size header and variable-size continuation. Most types of datum do not allow such nesting and the continuation is then known as the data segment. This term data segment is inferred from the name of the internal routine FveDatumGetDataSegment which FVEVOL, FVEAPI and even the boot manager pick up from a library.

Layout

The FVE_DATUM structure is eight bytes:

Offset Size Description
0x00 word total size in bytes
0x02 word role
0x04 word type
0x06 word bit flags

The size at offset 0x00 is that of the fixed-size header, which may itself be larger than the FVE_DATUM, and of any variable-size continuation whether this be a single data segment or a sequence of nested data.

Type

What follows the eight bytes of the FVE_DATUM depends on the type at offset 0x04. For many types, the FVE_DATUM is the start of a larger fixed-size header. For most types, the header is followed immediately by the data segment. For five types, the header is followed by nested data.

For the following table of defined types, each Description is Microsoft’s name for the corresponding type-specific header, if known from public symbol files, but is otherwise inferred from the names of internal variables that are addressed from a table of datum properties.

Type Description Size of Header Nested Data Versions
0x0000 Erased 0x08 no 6.0 and higher
0x0001 FVE_DATUM_KEY 0x0C no 6.0 and higher
0x0002 FVE_DATUM_UNICODE 0x08 no 6.0 and higher
0x0003 Stretch Key 0x1C yes 6.0 and higher
0x0004 Use Key 0x0C yes 6.0 and higher
0x0005 FVE_DATUM_AESCCM_ENC 0x24 no 6.0 and higher
0x0006 TPM Enc Blob 0x0C no 6.0 and higher
0x0007 FVE_DATUM_VALIDATION_INFO 0x08 no 6.0 and higher
0x0008 FVE_DATUM_VMK_INFO 0x24 yes 6.0 and higher
0x0009 FVE_DATUM_EXTERNAL_INFO 0x20 yes 6.0 and higher
0x000A Update 0x2C yes 6.0 and higher
0x000B Error 0x34 no 6.0 and higher
0x000C FVE_DATUM_ASYM_ENC_BLOB 0x08 no 6.1 and higher
0x000D FVE_DATUM_EXPORTED_PUBLIC_KEY 0x08 no 6.1 and higher
0x000E FVE_DATUM_PUBLIC_KEY_INFO 0x08 no 6.1 and higher
0x000F Virtualization Info 0x18 no 6.1 and higher
0x0010 Simple 0x0C no 6.1 and higher
0x0011 Simple 0x0C no 6.1 and higher
0x0012 Concat Hash Key 0x1C no 6.1 and higher
0x0013 Simple 0x0C no 6.1 and higher
0x0014 Simple Large 0x10 no 6.3 and higher
0x0015 Backup Info 0x1C no 1903 and higher

Three types are all described just as Simple and another just as Simple Large. None of these are known ever to be created with a data segment. The Simple of the description is just that the type-specific header continues beyond the FVE_DATUM with just one four-byte member, growing to eight bytes for Simple Large. In the only known use of Simple Large, the eight-byte member is specifically an iteration count for key stretching.

Role

If the type at offset 0x04 tells how to interpret what follows the FVE_DATUM, then the role at offset 0x02 tells what the datum is for. The role is not a sub-type. The type and role are independent. This seems safe to infer from such internal (library) routines as FveDatumNestedGetNext which can search a sequence of nested data for all that have a particular combination of type and role, or all that have a specified type (whatever the role), but also for all that have a specified role (whatever the type).

Much less evidence is published by Microsoft for any classification of roles than of the type. That the member is thought of by Microsoft as a role, rather than a purpose or some other category, is here taken from some sort of white paper Addressing a Commercial Grade Operating System Security Functional Requirement Set with Windows Vista and Server 2008 that Microsoft published in 2008 but which has all but disappeared from the Internet. (The link is long stale.) In a relatively small section headed “Full volume encryption”, this paper names several structures consistently with public symbol files. It therefore comes with some assurance that all its names that seem to have been taken from the programming actually have been. As well as naming several structures whose names are not known from public symbol files (but which might otherwise be guessed with confidence), it names a constant, FVE_ROLE_VMK_CACHE, and describes its use closely enough for deducing that it is intended for this member of the FVE_DATUM (and that its value is 5).

Role Description Versions
0x0000 none specified (default) 6.0 and higher
0x0001    
0x0002 for an FVE_DATUM_VMK_INFO in a dataset 6.0 and higher
0x0003 for an FVE_DATUM_AESCCM_ENC in a dataset,
data segment is encrypted FVE_DATUM_KEY
whose decrypted data segment is the FVEK
6.0 and higher
0x0004 for an FVE_DATUM_VALIDATION_INFO in a dataset 6.0 and higher
0x0005 for an FVE_DATUM_KEY in a dataset,
data segment is the cached VMK
6.0 and higher
0x0006 for an FVE_DATUM_EXTERNAL_INFO in a dataset 6.0 and higher
0x0007 for an FVE_DATUM_UNICODE in a dataset,
data segment is description
6.0 and higher
0x0008 for an Update datum (type 0x000A) in a dataset 6.0 and higher
0x0009 for an FVE_DATUM_PUBLIC_KEY_INFO in a dataset,
data segment is FVE_DEVICE_LOCKOUT_STATE
6.2 and higher
0x000A for an Error datum (type 0x000B) in a dataset 6.0 and higher
0x000B for an FVE_DATUM_AESCCM_ENC in a dataset,
data segment is encrypted FVE_DATUM_KEY
whose decrypted data segment is the AMK
6.1 and higher
0x000C for an FVE_DATUM_EXPORTED_PUBLIC_KEY nested in an FVE_DATUM_VMK_INFO 6.1 and higher
0x000D for an FVE_DATUM_EXPORTED_PUBLIC_KEY nested in an FVE_DATUM_VMK_INFO 6.1 and higher
0x000E for an FVE_DATUM_AESCCM_ENC in a dataset,
data segment is encrypted FVE_DATUM_UNICODE
whose decrypted data segment is the identification field
6.1 and higher
0x000F for Virtualization Info (type 0x000F) in a dataset 6.1 and higher
0x0010    
0x0011 for an FVE_DATUM_VALIDATION_INFO in a dataset 6.3 and higher
0x0012 for an FVE_DATUM_AESCCM_ENC nested in a stretch key (type 3),
data segment is encrypted FVE_DATUM_KEY
whose decrypted data segment is password to stretch
6.3 and higher
0x0013 for an FVE_DATUM_AESCCM_ENC nested in a stretch key (type 3) 6.3 and higher
0x0014 for an FVE_DATUM_UNICODE nested in a stretch key (type 3),
data segment names algorithm for stretching key
6.3 and higher
0x0015 for an FVE_DATUM_KEY nested in a stretch key (type 3),
data segment is salt for stretching key
6.3 and higher

Flags

The only known original use for the word at offset 0x06 is that the 0x0001 bit is set in an FVE_DATUM that is contained in some larger structure such as a dataset or as a nested datum. Internally, this bit’s being set marks the datum as one that is not to be individually freed from memory. Only rarely would this not apply to the typical datum in the typical circumstances of much typical analysis, e.g., of a datum in a dataset that is in turn in an information sectors that persists on disk.

For this original purpose, the flags word looks to be intended for all types of datum. As BitLocker has evolved, some need seems to have developed for type-specific bit flags but without space being easily made in the corresponding type-specific extension of the header beyond the FVE_DATUM. Remember that all these headers can pass between components at run-time and can persist on disk, and therefore have non-trivial constraints for compatibility. Inevitably, the space for bit flags in the non-specific header has ended up being used for type-specific bits. For instance, a datum for what’s called the clear key (when BitLocker is suspended) can have the 0x0004 bit set in these flags to signify that the high byte of the flags is the suspend count. By now, most bits in this flags word have some such type-specific interpretation. More study is required.