LibreCrypt: Open-Source disk encryption for Windows
NOTE: This CDB layout is *_obsolete_; all new volumes should use the latest CDB format.*
OBSOLETE *This format is used by older versions of FreeOTFE, but not by LibreCrypt. LibreCrypt supports only (CDB Format ID 4)
The following table describes the high-level layout of all FreeOTFE (*not *Linux) volume files:
Critical data block:
|
Encrypted partition image |
Color key:
Color | Encryption used |
---|---|
Red items are not encrypted | |
Blue items are encrypted with the user's password, password salt, and user's chosen hash/cypher algorithms | |
Green items are encrypted with the master key and the user's chosen cypher, with IVs generated with the user's chosen sector IV method |
Seem intimidating? Read on, and all will become clear... When broken down into its component parts, the volume structure is reasonably straightforward to understand.
Critical data block | Encrypted partition image |
At the highest level, volume files can be broken down into just two basic parts: A critical data area, and the encrypted partition itself.
Item name | Size (in bits) | Description |
---|---|---|
Critical data block | 4096 | This part of the volume file contains "critical data", including the master en/decryption key used for the encrypted partition image, the method used for generating sector IDs, and a check hash. See below for further breakdown. |
Encrypted partition image | User defined. (max 2^64 bytes; circa 16777216 TB) | This is a literal partition image which represents the volume. This image is encrypted with:
|
_Total size:_ | 4096 + Encrypted partition image size |
Password salt | Encrypted block | Random padding #1 |
Item name | Size (in bits) | Description |
---|---|---|
Password salt | sl (User specified to a max 512) | This data is appended onto the user's password, before it's hashed. The resulting hash may then be used to encrypt/decrypt the "Encrypted block". |
Encrypted block | If bs>0 then: ((4096 - salt length) div bs*)* * bs*_*_ If bs<=0 then: (4096 - salt length) | This block contains the actual key which is used to encrypt/decrypt the encrypted partition image. See below for further breakdown. |
Random padding #1 | ((4096 - sl) % bs) | Random "padding" data. Required to pad out any remaining, unused, bits in the "critical data block"** |
_Total size:_ | 4096 |
Check hash | Volume details block |
As described above, this entire block is encrypted using the user's password, salt, and chosen hash and cypher algorithms.
As this block is encrypted, its length (in bits) must be a multiple of the cypher's blocksize.
Item name | Size (in bits) | Description |
---|---|---|
Check hash | hk | This is the hash of the plaintext version of the "Volume details block". If hk is zero, then this hash will be either truncated to 512 bits, or right-padded with 0 bits up to a maximum of 512 bits |
Volume details | Total size - hk | This stores the details of how to encrypt/decrypt the encrypted partition. |
_Total size:_ | If bs>8 then: ((4096 - sl) / bs*)* * bs*_*_ If bs<=8 then: (4096 - sl) | Note: "/" represents integer division |
Critical data version | Volume flags | Encrypted partition image length | Master key length | Master key | Requested drive letter | Random padding #2 |
Finally, we reach the details that the critical data block was designed to protect:
Item name | Size (in bits) | Description |
---|---|---|
Critical data version | 8 | This is a version ID which identifies the layout of the remainder of the volume details block When this layout format is used, this will always be set to 1. |
Volume flags | 32 | Bitmap flagging various items.
Currently, this only identifies which method is used in generating sector IVs, used in encrypting/decrypting the encrypted partition image. Bit - Description 0 - Use different IVs for each sector 0 = Use NULL IV 1 = Use sector ID (possibly hashed) as IV 1 - Sector ID zero is at the start of the file 0 = Sector ID zero is at the start of the encrypted data 1 = Sector ID zero is at the start of the host volume file 2 - <unused> 3 - Hash sector ID before use 0 = Sector ID used as IV 1 = Hash sector ID before using is as an IV |
Encrypted partition image length | 64 | This stores the length (in bytes) of the encrypted partition image |
Master key length | 32 | This will be set to the length of the master key in bits. Not strictly needed, but used as a sanity check. |
Master key | _ks (max 1536) _ | This is set to the random data generated when the volume was created; it represents the en/decryption key used to encrypt the encrypted partition image |
Requested drive letter | 8 | The drive letter the volume should be typically be mounted as. Set to 0x00 if there is no particular drive letter the volume should be mounted as; mount using the first available drive letter. |
Random padding #2 | All remaining bits to pad out to Total size | Random "padding" data. Required to pad out the encrypted block to a multiple of bs, and to increase the size of this block to the maximum length that can fit within the "critical data block". |
_Total size:_ | (((4096 - sl) / bs*)* * bs*_*)** - _hk | Note: "/" represents integer division |
The design of the critical data layout eliminates the need for the cypher/hash used to be stored anywhere, denying an attacker this information and increasing the amount of work required to attack a volume file.
The "critical data block" is encrypted.
The "password salt" appears before the "encrypted block", and no indication of the length of salt used is stored anywhere in order to prevent an attacker from even knowing where the "encrypted block" starts within the "critical data block".
The "Check hash" appears before the volume details block. This may seem a little strange since the size of "Check hash" is variable (its actual length is dependent on the hash algorithm chosen), but appears first in order to reduce the amount of "known" (or predictable) data early on in the volume. Theoretically this is desirable as (for example) cyphers operating in CBC (or similar) modes which "whiten" data will do so with data that is less predictable than would occur if the hash appeared towards the end of the block it appears in.
The "Check hash" is limited to 512 bits. This is limited as, in practical terms, some kind of limit is required if the critical data block is to be of a predetermined size. See section on mounting volume files for how multiple matching check hashes is handled.
The "Password salt" is (fairly arbitrarily) limited to 512 bits. Again, this is primarily done for practical reasons.
Although at time of writing (2004) this limit to the length of salt used should be sufficient, the format of the critical data block (with included layout version ID) does allow future scope for modification in order to allow the critical data block to be extended (e.g. from 4096 to 8192 bits), should this limit be determined as insufficient.
The "Encrypted block" does contain a certain amount of data that may be reasonably guessed by an attacker (e.g. the critical data version), however this would be of very limited use to an attacker launching a "known plaintext" attack as the amount of this data is minimal, and as with pretty much any transparant encryption system, the "Encrypted partition image" can reasonably expected to contain significantly more known plaintext anyway (e.g. the partition's boot sector)
To create a container file, a fairly significant amount of information is required due to freedom that LibreCrypt gives you in creating volume files.
Broadly speaking, creating a container consists of three distinct stages:
Stage 1 is straightforward; write data to the file until is has gained the required size. This stage is skipped when creating a hidden volume.
Stage 2 is more complex; and will be described below.
Stage 3 is required to set the volume up for use
The following procedure is used to build up a container's critical volume block:
The following information is determined:
"sl" - The number of "salt" bits required by the user
"ks" - The keysize (in bits) of the user's chosen cypher. If the cypher driver reports that this value is "-1", then "ks" should be assumed to be 8 bits.
The length (in bits) of hashes generated by the user's chosen hash algorithm. If the hash driver reports that this value is "-1", then "hk" should be assumed to be 512 bits.
(((4096 - **sl**) / **bs****)** * **bs**_****_**)** - _hk_(See the layout breakdown diagrams of the "Critical data area" to understand where this algorithm comes from.) * With the user's selection of hash algorithm, hash the "Volume details block" to generate the "Check hash". * If the "Check hash" generated has less than "**hk**" bits, it should be right-padded with zero bits until it is "**hk**" bits long. * If the "Check hash" generated has more than "**hk**" bits, it should be truncated to the first "**hk**" bits. * Prepend the "Check hash" onto the "Volume details block" to build the plaintext version of the "Encrypted block" * Append the salt onto the user's password * Hash the salted password with the user's chosen hash algorithm * If the hash generated has less than "**ks**" bits, it should be right-padded with zero bits until it is "**ks**" bits long. * If the hash generated has more than "**ks**" bits, it should be truncated to the first "**ks**" bits. **The truncated/padded hash will be used as the "critical data key"** * Encrypt the plaintext "Encrypted block" with the user's selection of cypher, an IV of "**bs"** zeroed bits, and the "critical data key" * Prepend the salt onto the cyphertext version of the "Encrypted block" * Append "Random padding #1" to the "Encrypted block" in order to pad it out to 4096 bits (512 bytes) and form the complete "Critical data block" * Write the "Critical data block" to the volume file, beginning from the start of the file for normal LibreCrypt volumes, or from the user's offset in the case of a hidden volume.
((4096 - **sl**) / **bs**) * _bs _Alternatively, the length of "Random padding #1" can be viewed as being:
((4096 - **sl**) % **bs**)
Where % represents the modulus, and / integer division* The "Encrypted block" is decrypted using:
<OL>
*
The first "ks" bits of the hash value previously generated as the decryption key; if "hk" is less than "ks", then the hash will have extra zero bits appended to it in order to pad it out to "ks"
*
An IV consisting of a block of "bs" bits, all set to 0.
</OL>
In either case, all remaining hash/cypher combinations will be processed in the same manner.
As a result of the volume's layout, it is not necessary to store the cypher or hash algorithm used for en/decryption anywhere. Nor is it necessary to prompt the user for this information since during mounting a container formatted volume, this information can be determined dynamically by attempting the mount using all possible combinations of installed hash/cypher in conjunction with the check hash.