Loading…

Kryptel Storage

Kryptel 6 Advanced Storage

The purpose of this article is to provide information on Kryptel internal data formats for public scrutiny. At least a basic understanding of programming is required.

Container Format

Kryptel 6 container consists of six parts, some of which may be missing.

[Container Header]      Always present
[Data Area]             Optional, contains data blocks
[Agent Data Area]       Optional
[Directory]             Always present
[Header Copy]           Always present
[Trailer]               Always present
		

Container Header

Container header contains IDs of the components used for encryption, component initialization values, and other critical data required for opening the container.

Size Description
4 Container tag
2 Header size including header hash
2 Version of handler that created the container
2 Version of handler required to process the container
16 Storage Handler component ID (must be CID_BASIC_STORAGE)
16 Agent component ID
16 Cipher component ID
16 Compressor component ID
16 Hash function component ID
20 Cipher parameter block
4 Compressor parameter block
12 Hash function parameter block
16 Key ID
2 Size of reserved area (must be 0)
. . . Reserved area (not present in Kryptel 6 storage)
4 Number of key verification passes
HashSize Key verification block
4 Size of agent data field (0 if no agent data)
6 Agent data address (points to directory if no agent data)
HashSize Agent data HMAC (0 if no agent data)
6 Size of the directory area
BlockSize Directory area init vector (encrypt it to get the actual vector)
HashSize Directory HMAC (computed on unencrypted data)
STR Cipher name string
STR Cipher scheme string
STR Compressor name string
STR Compressor scheme string
STR Hash function name string
STR Hash function scheme string
16 MD5 hash of the header

STR represents a UTF-16 string; first word (2 bytes) contains the string length in characters. The string does not contain trailing zero. Each UNICODE character occupies 2 bytes.

The container tag, the offset to the handler component ID, and the offset to the agent component ID are constants. The container tag goes first; the position of the agent/handler component IDs must remain the same for the given tag in order for the GetContainerHandlers function to work correctly.

Note that the cipher, the compressor, and the hash function cannot be null components.

Data Area

Data area is a set of objects' data blocks. Each data block is an independent encrypted stream. Data area is never accessed sequentally so gaps are allowed.

Data recovery block

A data stream may be followed by an optional data recovery block. Note that recovery blocks are created but never accessed except during recovery scan.

Size Description
4 Random data
4 Recovery block tag
2 Size of the recovery block
6 Size of the data stream
. . . Initialization vector
16 Data stream MD5 hash
2 Size of agent-owned recovery data
. . . Agent-owned recovery data
. . . Bytes 0xE8 to align to BlockSize boundary - 4
4 CRC-32 of the previous data

Unlike data streams and the directory area, recovery blocks are encrypted as a simple sequence of blocks in CBC chaining mode, using zero initialization vector.

Agent Data Area

Raw data block defined by the agent. The storage handler just stores the data that the agent provides.

Container Directory

The container directory is an encrypted stream. The directory data is compressed before encryption. It contains exactly one directory entry for the upper-level object (which in turn may contain any number of child objects). In some sense this object may be considered as the container itself.

Directory Entry

Size Description
2 Object start tag
16 Object ID
6 Size of object's data block (0 if no data)
6 Size of uncompressed data block (present if data size > 0)
6 Address of data block (present if data size > 0)
2 Size of associated recovery block (present if data size > 0)
BlockSize Initialization vector (present if data size > 0)
16 Data block MD5 hash (present if data size > 0)
4 Size of object's attribute block (0 if no attributes)
. . . Attribute block
. . . [Optional directory entries for child objects]
2 Object end tag

If the object has a data block, it is an encrypted stream. The stream is always compressed, however the storage client (i.e. an agent) can specify the compression level when calling IEncryptedObject::CreateStream, and that level may be set to CT_NO_COMPRESSION. The Kryptel agents use this method to turn off compression for specific files.

Container Trailer

Trailer is used for container verification only. The standard Open operation does not read it.

Size Description
4 Trailer tag
2 Header size including the header hash field
6 Address of agent data area
6 Directory address
16 MD5 hash of the header
16 MD5 hash of the data area
16 MD5 hash of the agent data area
16 MD5 hash of the directory area
16 MD5 hash of the trailer

All hashes are computed on the encrypted data so that the user could verify the container integrity without entering the password. If the corresponding area is not present, the hash value is ignored (setting it to 0 is recommended).

Tag Values

Container tag           0x07AA050B
Object start tag        0x050B
Object end tag          0x07AA
Trailer tag             0x0B0507AA
Recovery block tag      0xE0EAF0C8
		

Key Usage Notes

Although cipher and HMAC (HMACs are computed for agent data and directory, and are used for key verification) use the same key, they use it differently.

Cipher uses first no more than KeySize bytes of the key (padded with zeroes if necessary).

HMAC reverts and inverts the significant bytes of the key, pads with zeroes if necessary, and uses the first 64 bytes of the result.

For example, in the default case of 256-bit AES and SHA-512, the cipher will use the first 256 bits of the SHA-512 password hash, and HMAC will use the whole reversed and inverted password hash. In most cases this method ensures that cipher and HMAC use completely different or at least weakly related keys.

In case of user-defined binary key (IDENT_BINARY_KEY), HMAC assumes its size is 512 bits and prepares (reverts and inverts) that portion. It is responsibility of the user to pad the key with zeros up to BINARY_KEY_SIZE. Note that end-user Kryptel does not fully supports user-defined binary keys – Kryptel Browser can open a container, encrypted with a user-defined key, however creating such a container requires programmatic access to the file agent.