Structure of Silver Key 5 Parcel
Parcel Format
Silver Key 5.x parcel is based on Silver Key 4.x parcel with the following changes:
- Key-related fields have been removed and replaced with three fields – the size of the key block, the key block itself, and the key block HMAC. The key block incapsulates the parcel's key(s); the engine handles it as a black box.
- Init vector has been removed from parcel header. The engine now uses a non-random init vector produced as described below in 'Notes on key usage'.
Parcel Structure
[Pre-header data] Optional arbitrary data (decryptor stub, for example) [Parcel header] Always present [File area] A set of encrypted streams containing file data (optional) [Script area] Encrypted stream containing parcel script (always present) [Parcel trailer] Always present [Post-parcel data] Optional arbitrary data
Even if the parcel is empty, it contains a header, a script containing a null command (marking the end of the script), and a trailer.
This structure radically differs from the structure of pre-4.0 parcel, which stores commands and data as a single stream. The new Kryptel-like format allows one-pass parcel creation and partial decryption (Parcel Analyzer is the end-user partial decryption tool).
Parcel Header
Parcel header contains information about the key material, the components used for encryption, and other important data.
Size | Description |
---|---|
4 | Parcel tag (0x7A95FFEB) |
2 | Engine version used to create the parcel |
2 | Extractor version required |
16 | Engine GUID (11056249-400A-4461-BD5E-FE06113CA002) |
16 | Parcel GUID, always {11056249-400A-4461-BD5E-BC88BE010405} |
4 | Parcel flags |
16 | Cipher component ID |
20 | Cipher parameter block |
2 | Size of key block |
. . . | Key block |
HashSize | Key block HMAC |
STR | Cipher name string |
STR | Cipher scheme string |
STR | Parcel title |
--- Description (if SK_FLAG_SHOW_DESCRIPTION) --- | |
4 | Uncompressed description size (number of UTF-16 chars, no terminating zero) |
4 | Compressed description size (bytes) |
. . . | Compressed description (UTF-16, no terminating zero) |
--- Uninstaller (if SK_FLAG_UNINSTALLER) --- | |
4 | Uncompressed uninstaller size |
4 | Compressed uninstaller size |
. . . | Compressed uninstaller |
--- Localized strings (if SK_FLAG_LOCALIZED_STRINGS) --- | |
2 | Uncompressed size of string set |
2 | Compressed size of string set |
. . . | Compressed string set |
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.
Silver Key engine uses ZIP compressor. SHA-512 is used to produce the key and the HMACs so HashSize is always 64.
The first 44 bytes of header (from parcel tag to parcel flags, inclusively) have the same meaning for all Silver Key 4.0 and later engines.
Format of string set
Size | Description |
---|---|
2 | Language code |
1 | String 1 identifier |
STR | String 1 |
1 | String 2 identifier |
STR | String 2 |
. . . | |
1 | String N identifier |
STR | String N |
1 | Zero byte (PARCEL_STRING_TERMINATOR) |
If the extractor can't recognize a string identifier, the string should be quietly ignored. The list of the identifiers can be found in SilverKey.h
Key Usage Notes
The cipher key, the HMAC key (for those HMACs that are computed for agent data and directory), and the directory/fixup init vector are produced from the HashSize-long base key.
Cipher uses first KeySize bytes of the key. If KeySize is greater than HashSize, the base key is padded with zeroes to KeySize;
In order to produce HMAC key revert the base key's bytes and invert them. For example:
Base key: 01 02 03 ... D0 E0 F0
HMAC key: 0F 1F 2F ... FC FD FE
The size of HMAC key is also HashSize.
Initialization vector is produced the same way as HMAC key. After that the HashSize long result is either truncated to BlockSize or extended with bytes 0xA5. On the last step the result is encrypted; the encrypted BlockSize-long vector is used as the init vector.
Note about parcel GUID
Time has shown that adding this field was a wrong idea. Although a unique parcel ID could be useful in some scenarios, a random 128-bit value can be used to store some 'backdoor' information, for example, a part of the key. In any case, it is not possible to avoid such a suspicion.
As a solution to this problem, the engine should not generate a unique GUID. This field may contain any value, but the value must remain the same for all parcels created by the given engine version/variation. This way it still can be used for trailer verification, but it is impossible to store any backdoor information there.
Parcel Trailer
Size | Description |
---|---|
HashSize | HMAC of parcel header, starting from parcel tag |
HashSize | HMAC of file area (computed on encrypted data) |
HashSize | HMAC of script area (computed on encrypted data) |
4 | Parcel end tag (0xEBFF957A) |
16 | Parcel GUID, always {11056249-400A-4461-BD5E-BC88BE010405} |
8 | Offset to the file area, relative to header start |
8 | Offset to the script area, relative to header start |
8 | File position of the parcel ID tag; 0 if no stub |
16 | MD5 hash of the preceding area, starting from parcel ID tag |
The last 60 bytes of the trailer (starting with parcel end tag) must have the same meaning for all Silver Key 4.0 and later engines.
Note that the position of the parcel ID tag is just a hint, and may in fact point to a wrong place. This pointer is valid for newly created parcels, but after repacking it naturally gets out of sync as repacking does not modify the parcel trailer. The purpose of this field is to enable quick recognition with IsParcel function. If the parcel gets repacked, LocateParcel function is required to locate the parcel inside a file.
If the last 16 bytes of the file is not a valid MD5 signature, or if the header position offset does not point to a parcel ID tag, then the parcel may contain trailing data. In this case the decryptor should scan the file to locate 'parcel start' and 'parcel end' tags. After locating the parcel's header and trailer, the decryptor must compare the parcel GUID values to ensure that the trailer matches the header.
Note about post-parcel data
Silver Key 5 engine does not adds random obfuscation data at the end of the parcel. This feature could be used to store backdoor information so it has been removed. However the obfuscation data can be added by the repacker. Repacker is an independent program that has no access to the key and so its random obfuscation block is guaranteed to be genuine. The decryptor should warn the user that the parcel includes post-parcel data.
Script Area
Silver Key script area is a sequence of commands, encrypted to a standard compressed and encrypted stream.
The decryptor processes commands in the same order as they appear in the parcel - for example, in order to decrypt a file and create a shortcut to it, you must place first [COMMAND_FILE], and then [COMMAND_LINK].
The last command is always a null command, so the stream cannot be empty. Note that the terminating null command may be followed by a block of random obfuscation data, so the parser must stop processing and reset the cipher and the compressor as soon as it encounters the terminating null command.
Script Commands
Statistics
The primary purpose of this command is setting up a progress bar. It is highly recommended to place this command first to ensure that the decryptor's progress bar will not get out of sync.
Size | Description |
---|---|
4 | [COMMAND_PROGRESS] |
4 | Number of directories |
4 | Number of files in parcel |
8 | Total size of all files in the parcel (bytes) |
Comment
Shows the encrypted message stored in the file area. The stored comment does not include terminating zero.
Size | Description |
---|---|
4 | [COMMAND_COMMENT] |
BlockSize | Cipher initialization vector |
8 | Comment position (offset from the header start) |
4 | Comment uncompressed size (number of UTF-16 chars) |
4 | Comment compressed size (bytes) |
Directory
Creates a directory.
Size | Description |
---|---|
4 | [COMMAND_DIRECTORY] |
4 | Target (value from TARGETS enumeration) |
STR | Target-relative path |
File
Decrypts a file stored in the file area.
Size | Description |
---|---|
4 | [COMMAND_FILE] |
BlockSize | Cipher initialization vector |
8 | File data position (offset from the header start) |
8 | File original uncompressed size |
8 | Size of the file's encrypted stream |
8 | File creation time (time_t value) |
4 | Target (value from TARGETS enumeration) |
STR | Target-relative path |
Delete
Deletes a file system object (i.e. file or directory). See the Security Considerations chapter in the program's Help for a detailed discussion.
Size | Description |
---|---|
4 | [COMMAND_DELETE] |
4 | Target (value from TARGETS enumeration) |
STR | Target-relative path |
Create Link
Creates a shortcut to a decrypted file system object.
Size | Description |
---|---|
4 | [COMMAND_LINK] |
4 | Shortcut's target (value from TARGETS enumeration) |
4 | File's target (value from TARGETS enumeration) |
4 | Icon's target (value from TARGETS enumeration) |
STR | Shortcut target-relative path |
STR | File target-relative path |
STR | Icon target-relative path |
STR | Command-line arguments |
STR | Shortcut description string |
The shortcut path and the file path are mandatory arguments and cannot be empty. Other strings may be empty; if the icon path is empty, the icon target value is ignored.
Open
Opens a decrypted file system object in the associated application.
Size | Description |
---|---|
4 | [COMMAND_OPEN] |
4 | Open mode (value from SK_OPEN enumeration) |
4 | Target (value from TARGETS enumeration) |
STR | Target-relative path |
Tag Values
PARCEL_TAG 0x7A95FFEB PARCEL_END_TAG 0xEBFF957A COMMAND_NULL 0x7A250000 COMMAND_PROGRESS 0x7A250001 COMMAND_COMMENT 0x7A250012 COMMAND_DIRECTORY 0x7A254FAE COMMAND_LINK 0x7A25BF00 COMMAND_FILE 0x7A25BFC0 COMMAND_DELETE 0x7A25C0BF COMMAND_OPEN 0x7A25F005