This section specifies the method for deriving a cryptographic key from a password using the Password-Based Key Derivation Function 2 (PBKDF2). The PBKDF2 algorithm is designed to produce keys that are computationally intensive to derive, thereby providing a defense against attacks such as dictionary attacks and brute force.
PBKDF2 applies a pseudorandom function (PRF) to the input password along with a salt value and iterates this process a specified number of times to produce a derived key. The iteration count is a critical security parameter and should be chosen with consideration to the desired level of security and the performance constraints of the system.
Further details on the key derivation algorithm are given in the PBKDF2 specification RFC-2898 and PBKDF2 Test Vectors RFC-6070
The security of PBKDF2 is directly related to the number of iterations, the strength of the PRF, and the length and randomness of the salt. It is recommended to use a salt that is unique to each derivation process to prevent the use of precomputed tables for deriving keys.
When PBKDF2 is used as the PHSF algorithm for an AEAD encrypted datastream (FHED or SHED Cipher mode = 2), the derived key length is 32 bytes (256 bits), and the output is used as K_master in §8.3.
As per NIST SP 800-132, it is recommended to use at least 10,000 iterations for PBKDF2 when deriving keys for non-interactive applications. However, this value should be increased as computational power advances to ensure the security of the derived keys.
This section delineates the methodology for deriving cryptographic keys via the memory-hard key derivation function, Argon2. Recognized as the winner of the Password Hashing Competition in 2015, Argon2 is engineered to resist attacks from both specialized hardware and parallel computing, making it a robust choice for password hashing and key derivation.
Argon2 is a high-level key derivation function that operates with three distinct variants: Argon2d, Argon2i, and Argon2id, each tailored for different security applications. The function utilizes a large memory size, parallelism, and a variable number of iterations to thwart off-line brute-force attacks.
Memory Size: The amount of memory used by the algorithm. Iterations: The number of iterations the function is to perform. Parallelism: The number of threads and lanes that the algorithm utilizes. Salt: A unique sequence of bytes used as an input to the hash function. Tag Length: The desired length of the output key. Secret Value: An optional secret value that can be used as a key for HMAC when generating the hash.
Assign the memory to a matrix of blocks. Fill the matrix with hashes derived from the password, salt, and optional secret. Perform the specified number of iterations, mixing the blocks both within and between threads. Extract the tag of the requested length as the output of the function.
Further details on the key derivation algorithm are given in the argon2 specification and RFC-9106
The selection between Argon2d, Argon2i, and Argon2id should be made according to the threat model:
Argon2d maximizes resistance to GPU cracking attacks and is suitable for cryptocurrencies and applications without a threat from side-channel attacks. Argon2i is optimized to resist side-channel attacks and is preferable for password hashing and key derivation where the input is not secret. Argon2id is a hybrid that combines the resistance to side-channel attacks of Argon2i with the GPU cracking resistance of Argon2d, suitable for applications that require a balance of both.
When Argon2 is used as the PHSF algorithm for an AEAD encrypted datastream (FHED or SHED Cipher mode = 2), the derived key length is 32 bytes (256 bits), and the output is used as K_master in §8.3.
As per current best practices, it is advised to allocate as much memory as is practical for the application and at least two iterations. The parallelism should be set according to the number of available processor cores. The salt should be a unique, cryptographically secure random value for each password.
Keys for AEAD encrypted datastreams (Cipher mode = 2) are derived in two stages.
K_stream = HKDF-SHA-256(IKM = K_master, salt = stream_salt, info = entry_context)
output length = 32 bytes
stream_salt is the 32-byte value stored in the stream header (§7.5.1). Because a random salt separates the key of each stream, GCM nonce management is confined to a single stream and per-key usage limits are not a concern.
CBC and CTR (Cipher mode = 0, 1) use the KDF output directly as the encryption key.
entry_context is the byte concatenation of the following fields, 88 bytes in total:
| Bytes | Field | Value |
|---|---|---|
| 13 | Domain tag | ASCII "PNA-STREAM-v1" |
| 32 | Header hash | SHA-256(FHED chunk type || data) or SHA-256(SHED chunk type || data) |
| 32 | KDF params hash | SHA-256(PHSF chunk data) |
| 7 | nonce_prefix | The nonce_prefix field of the stream header (§7.5.1) |
| 4 | segment_size | The segment_size field of the stream header (§7.5.1), big-endian as stored |
The input to the Header hash is the byte concatenation of the target header chunk’s 4-byte Type field and its raw Data field, excluding Length and CRC. In per-entry mode this is the ASCII bytes FHED followed by the FHED data of the entry; in solid mode it is the ASCII bytes SHED followed by the SHED data of the solid stream.
The input to the KDF params hash is the raw Data field of the PHSF chunk, excluding Length, Type, and CRC. The PHSF is the one placed before the FDAT or SDAT chunks of the datastream.
This construction binds the header chunk’s contents, the KDF parameters, and the nonce_prefix and segment_size into the key. Tampering with any of them, or swapping encrypted datastreams between entries, results in a different K_stream and fails tag verification on the first segment.
When an archive contains multiple entries whose FHED chunk data is byte-for-byte identical, swapping their encrypted datastreams cannot be detected. Likewise, an entry copied in its entirety into another archive protected by the same password decrypts successfully: the key derivation binds an encrypted datastream to its entry, not to the containing archive.
key_confirmation is the 32-byte value stored in the stream header (§7.5.1). It is derived from K_master:
key_confirmation = HKDF-SHA-256(IKM = K_master, salt = empty, info = ASCII "PNA-KC-v1")
output length = 32 bytes
A decoder must verify the stored value against the derived value before processing any segment (§12.4). Verification binds the datastream to a single K_master, providing key commitment. key_confirmation gives an offline password-guessing attacker no capability beyond what the first segment’s authentication tag already provides.