syncthing:master
← calmh:encryption
opened 10:00PM - 05 Dec 19 UTC
Since it came up again, here's a fairly lightweight attempt at encrypted devices…. It's early days and lots of user friendlyness lacking, but the basics work for me. I can sync files back and forth to an encrypted device. In principle it works like this:
- The encryption is added as a shim at the protocol layer, transforming Index(Updated)/Request/Response messages. There is no new folder type or such.
- Only the sending (encrypting) side needs to know that encryption is enabled; the other side doesn't need to know or care.
- Both sides need to be upgraded to this version though, because there is a new field in the FileInfo that needs to be sent over the wire and retained in the database on encrypted devices.
- The encryption is enabled by setting an encryption password config on a given device+folder.
- The encryption hides everything except file sizes which are derivable from but not identical to the original (some per-block overhead). We could easily pad this to further obfuscate file sizes, but splitting up completely might be more difficult. I think we're fine here as long as we're similar to the level of encfs etc.
- All items in an encrypted folder get encrypted names, with slashes inserted to follow max path component lengths.
Protocol wise, it's like this:
- Encryption is AES-GCM.
- Key derivation is scrypt, with fixed salt (we need to generate the same key on two different but equivalently configured devices).
- Nonces for block hashes and file names are based on the content, passed through pbkdf2 (we need the encrypted strings to match for two different devices doing the same encryption).
- Nonces for data are random; we don't need the actual encrypted data blocks to look the same for two different devices.
- FileInfos get encrypted and packed into a new field in a "wrapping" FileInfo. This FileInfo has an encrypted name, other attributes are essentially empty or static except for the block list. The block list gets rewritten to have the same number of blocks but each being a little bit larger to account for encryption overhead. There are some comments in encryption.go to explain the transformation.
- Requests/Responses get tweaked to account for the changed size on the wire compared to on disk.
That's pretty much it.
On the encrypted side, the folder type should be receive only and don't do any scans... Changes to the stuff on the encrypted side will predictable break things.
Other code changes are mostly to account for hashes being nil on encrypted files, so they cannot be verified, and to propagate the block number being pulled. This latter simplifies calculating the correct offset for a block, as we know how many block overheads to add or remove...