Implementing safe sync functionality in a server-less extension

The major change in PfP: Pain-free Passwords 2.1.0 is the new sync functionality. Given that this password manager is explicitly not supposed to rely on any server, how does this work? I chose to use existing cloud storage like Dropbox or Google Drive for this, PfP will upload its encrypted backup file there.

This would be pretty trivial, but sync functionality is also supposed to sync records if data is modified by multiple clients concurrently. Not just that, sync has to work even when passwords are locked, meaning: without the possibility to decrypt data. The latter is addressed by uploading local data without any modifications. Records are encrypted in the same way both locally and remotely, so decrypting them is unnecessary.

Merging changes without access to decrypted data is more complicated. This is done by using record identifiers that are both deterministic (same site and password name result in the same record identifier on all devices) and opaque (don’t allow any conclusions about site and password name). PfP uses HMAC to create record identifiers, with the HMAC secret being a random byte sequence that is stored encrypted. When sync is set up for a device, its HMAC secret is replaced to make it match the HMAC secret of other devices connected to the same storage. After that a particular site/password combination is guaranteed to be stored with the same record identifier on all devices.

The merge operation itself is comparably easy then: PfP downloads remote data and replaces any records (by record identifier) that changed locally since the previous sync by local versions. It then needs to make sure that no conflicting changes by two clients are uploaded at the same time. This is fairly straightforward for Dropbox, you can always specify the file version you want to replace — if the file changed in the meantime, the operation fails and sync is restarted. Google Drive API makes it more complicated, you have to use underdocumented ETag functionality and cannot avoid conflicts when creating a new file. Worse yet, this feature only exists in the v2 API, whereas the newer v3 API has no conflict resolution whatsoever. One has to hope that Google doesn’t decide to deprecate v2 API soon.

Altogether, the sync functionality required more effort than I imagined but it works really well. And what about the Edge version that I promised before? Stuck in traffic. I figured out everything necessary with the 2.0.2 release a month ago already. However, turned out that uploading Edge extensions to the Windows Store requires a special permission. I requested this permission and that’s where we still are. Microsoft is making this ridiculously complicated, I suspect that they don’t really want people to create Edge extensions.


There are currently no comments on this article.