I implemented a crypto format (in the form of a MultiCipherOutputStream and a MultiCipherInputStream) that supports nesting multiple cipher streams into one another. The goal was to produce a flexible crypto file format that will satisfy even the most paranoid users. While I believe I have gathered quite a bit of knowledge about how to implement something like this, I am not an in-depth crypto expert. Background: The crypto format is for Syncany, a use-any-storage Dropbox-like file sync tool.
So my questions are:
- Is the concept of this crypto format cryptographically sound?
- Are any of my assumptions and design concepts wrong or questionable?
- Is it implemented correctly?
Here is a description for the format:
Length HMAC'd Description
----------------------------------------------
04 no "Sy" 0x02 0x05 (magic bytes, 4 bytes)
01 no Version (1 byte)
12 no Header HMAC salt
01 yes (in header) Cipher count (=n, 1 byte)
repeat n times:
01 yes (in header) Cipher spec ID (1 byte)
12 yes (in header) Salt for cipher i (12 bytes)
(dyn.) yes (in header) IV for cipher i (cipher specific length, 0..x)
32 no Header HMAC (32 bytes, for "HmacSHA256")
(dyn.) yes (in mode) Ciphertext (HMAC'd by mode, e.g. GCM)
General design concepts and assumptions:
- Assumption: A single password is shared among all users
- Input parameters: Password string, list of cipher specs (e.g. AES/GCM/NoPadding, 128 bit)
- The password is used to derive one symmetric key per cipher using PBKDF2 (12 byte salt, 1k rounds)
- The symmetric key(s) are used to encrypt files; it is reused in max. 100 files (~ 200 MB)
- Cipher algorithms are configurable, but not every cipher is allowed: only AES and Twofish (128/256 bit), only authenticated modes (as of now only GCM; no ECB, CBC, etc.)
- Ciphers are initialized with a random initialization vector (IV), IVs are never re-used
- Multiple cipher algorithms can be nested/chained (1-n ciphers), e.g. AES-128 and Twofish-256
- Cipher configurations, IVs and salts are authenticated with an HMAC (SHA256)
Source: