Encrypted stream data format
cream data is the concatenation of a 40
bytes header and a flow of encrypted data.
Data is encrypted with a key derivated from a password and a salt.
For convenience, encryption parameters are included at the beginning of the stream. The header is 40 bytes long, and has the following format:
|6||magic string CREAM\1||6*8-bit BE character|
|2||header version||16-bit BE unsigned integer|
|4||xchacha20 block size||32-bit BE unsigned integer|
|4||argon2id memory||32-bit BE unsigned integer|
|4||argon2id time cost||32-bit BE unsigned integer|
|4||argon2id parallelism||32-bit BE unsigned integer|
|16||salt||16*8-bit BE unsigned integer|
XChaCha20-Poly1305 is used to encrypt the data. As a symetrical cipher, the key used to encrypt the data must be used to decrypt it.
To encrypt, or decrypt a continuous stream, the input data is split in chunks, and a new key is generated to encrypt it. The smaller chunks are, the more keys are computed for a given amount of data.
To lower computation cycles, or accomodate memory-constrained system, the buffer size can be changed. However, this buffer size must be the same for both encryption and decryption, otherwise resulting in a failure to decrypt the data.
Argon2id is used to derivate the key from a password and a salt.
The master password must be known to both parties, while the salt is sent as part of the header. This means that the receiver must only know the password to decrypt the data.
Computing an Argon2id key takes multiple factor into accounts:
- Memory (m)
- Defines the memory usage, given in kibibytes.
- Time (t)
- Defines the amount of computation realized and therefore the execution time, given in number of iterations
- Parallelism (p)
- Defines the number of parallel threads.
These parameters will affect the speed at which the key is computed, but will also change the key itself.
For use as a symmetric key, you will want to use the exact same parameters for both encryption and decryption, otherwise decryption of the stream will be impossible.
The recommended values are m=2Gib, t=1, p=4. For memory constrained environment, use m=64Mib, t=3, p=4. See rfc 9106 for a procedure to pick good parameters.
magic(5) file pattern can be used to parse
cream headers using the
# cream.magic 0 string CREAM\1 CREAM encrypted data, >6 beshort x version %d, >8 belong x xchachapoly1305 >8 belong x bs=%d, >12 belong x argon2id >12 belong x m=%d >16 belong x t=%d >20 belong x p=%d
% file -m cream.magic cipher.cream cipher.cream: CREAM encrypted data, version 16, xchachapoly1305 bs=4096, argon2id m=65536 t=3 p=4
cream(1), file(1), magic(5)
D. J. Bernstein, The ChaCha family of stream ciphers, https://cr.yp.to/chacha.html, January 2008.
Y. Nir and A. Langley, ChaCha20 and Poly1305 for IETF Protocols, RFC 8439, June 2018.
A. Biryukov, D. Dinu, D. Khovratovich, and S. Josefsson, Argon2 Memory-Hard Function for Password Hashing and Proof-of-Work Applications, RFC 9106, September 2021.
Willy Goiffon <firstname.lastname@example.org>