Performance and slight worry of collisions on the shorter random nonces in AES-GCM. I’ve gotten some feedback on the overall design from a certain very knowledgeable cryptogopher that I’m acting on, and I’m writing up some better specs on how the whole thing works for another round of review. Hopefully this thing will have some sort of theoretical seal of approval on launch day, so we only need to worry about actual implementation bugs and not me accidentally holding the algorithm upside down.
There are some spec notes here: https://docs.syncthing.net/branch/untrusted/html/specs/untrusted.html
I know a little bit about cryptography and have taken a look the spec. It does look decent, but I have some questions about the integrity between blocks and version rollbacks.
Is the order of the encrypted blocks authenticated? It shouldn’t be possible to reorder the encrypted blocks, even when the contents cannot be changed.
Is there anything that prevents an untrusted device from replacing a file with a previous version (or even deleting it) while claiming it is a new update? I think every file needs some kind of version number that increases and is authenticated, so the untrusted device cannot do a rollback. The trusted devices should also check that it does in fact increase.
How does syncing between untrusted devices work in case of a conflict? Trusted devices create a new file for the conflict, but untrusted devices cannot do that.
Thanks for looking and thinking!
The block order could be tampered with on the untrusted device to the extent that it can modify the fake file metadata and block order on disk. However, this wouldn’t matter to the trusted device, or rather it would be detected and rejected. A trusted device doesn’t look at the fake metadata, but decrypts and uses the attached encrypted metadata (or uses its own original copy of that metadata). When requesting a block that has been changed on disk on the untrusted side it would then get data which might decrypt properly but will fail the hash check after decryption, much like bad data on a normal trusted device.
Rolling back is prevented by the same metadata wrapping mechanism – it doesn’t matter how new or improved the untrusted device claims the file is, the original attached metadata is what’s used, and that metadata will contain the truth. The untrusted device will just look out of date.
This also affects the conflict handling. The untrusted device doesn’t see or understand the real history of a file given that it can’t decrypt the real metadata. It just passes on whatever is the most recent metadata from another trusted device, much like a dumb wire. Conflict resolution will then happen on some trusted device.
Thanks for your reaction! Encrypting the metadata as a whole indeed works well, and the versioning already done by Syncthing prevents rollbacks.
I understand that conflict resolution normally happens on the trusted device, but my question was about syncing between untrusted ones (maybe it was not clear). Consider the following setup that you wanted to support:
A <-encrypted-> B <-normal-> C <-encrypted-> D
(A and D trusted, B and C not.) Let’s say they all share a file, but A and D make concurrent modifications to it, and they share these to B and C. Now B and C have to handle the conflict themselves. How do they do it? If they use the normal Syncthing algorithm they will create
.sync-conflict files, but their filenames will not be of the proper encrypted form. Maybe it is enough to allow these files as well, to allow the resolution to happen at the trusted devices? But it should be documented explicitly.
I also think that an untrusted device is able to prevent/reject specific updates. Of course it can’t give any updates at all, but preventing some may be undesirable if trusted devices don’t connect directly. Solving this is complicated I think, so you may as well say that availability attacks are not in the scope of the proposal.
Normal conflict detection is based on the version vector of the file, where we can detect concurrent modification. The untrusted variant of files don’t get the real version vector, they get a fake one that always has just one member with a version that is the send time in Unix nanos. This means that a wall-clock-newer untrusted file will always look like a linear descendent of all other versions of the same untrusted file (assuming correct clocks). So it will be accepted as the newest without conflict by any untrusted device, and in the end passed on to a trusted device who might see the real conflict and act on it. But there will never be a conflict between untrusted devices. (Unless one is intentionally introduced, but that will then be a file without encrypted metadata and it will be rejected by normal devices.)
You’re entirely correct on the second part. An untrusted device can elect to ignore any and all updates and not pass them on. They could be even devious and announce them back so they look in-sync to the originator, but then not tell anyone else.
Semi OT -> Can this forum link or the current proposed PR be posted to the (to my filter bubble) first google result for syncthing untrusted devices github -> Support for file encryption (e.g. non-trusted servers) ?
I would post it myself (can’t; collaborator lock) since I just found myself taking the scenic route through several dead-ended hyperlinks before I gave up and found this link in my email.