Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Zero-knowledge Encryption, Attempt 2 #57

Open
AnalogJ opened this issue Nov 3, 2023 · 6 comments
Open

Zero-knowledge Encryption, Attempt 2 #57

AnalogJ opened this issue Nov 3, 2023 · 6 comments

Comments

@AnalogJ
Copy link
Member

AnalogJ commented Nov 3, 2023

Follow up to #29

From discussion in Discord:

@starsoccer
Copy link

So a few of my thoughts on how this can/should be implemented:
Disclaimer I am not an expert in this field by any means and do not know if what Im proposing is 100% fool proof

  1. Ideally a users password should be part of if not the whole encryption key. To avoid weak passwords we may need to increase the strength/validation around existing passwords and then I believe the industry standard is to basically take the password and hash it some amount of times and then use this as the key.
  2. While I think this encryption key(generated from a users password) could be given to the server to then gather whatever information is needed and refresh data, etc..,), ideally only encrypted data would be sent back to clients/end users. So a login flow in my mind would look something like this. User puts in a username and password and presses login. Server sends back a small encrypted blob to validate the user truly knows the decryption key, and then asks for proof back before sending any further data. The client hashes the password, uses this to decrypt the blob and provides proof back to the server. Once provided the server will then assume this user is trusted/authenticated and send any further encrypted blobs for this users session.
  3. CORS/Background sync - Since fasten currently refreshes data, this wouldnt really be feasible with zero knowledge encryption. So I think the ideal solution would be forcing users .to download an app that can do this itself and then send those newly encrypted blobs to the fasten server to store. This also would resolve the issue of dealing with CORS as well. It may also be possible to get data in the background in a limited way in web apps by hacking around with the push notifications though, https://developer.mozilla.org/en-US/docs/Web/API/Push_API. Something like just push a notification to say background updating or something along those lines though Im not sure if this would actually bypass CORS or not

@cfu288
Copy link
Contributor

cfu288 commented Nov 4, 2023

@starsoccer
Just to add to #1: We can generate encryption keys from user passwords using algorithms like PBKDF2 or Argon2. You can even do this in the browser client using the web crypto SubtleCrypto API (for PBKDF2 at least). Obviously the strength of the underlying key is still dependent on the strength of the user password. We can strengthen the encryption key by combining a user provided password with a client generated secret key like 1password does that is not shared with the fasten server, but this adds significant complexity to implementation and UX. Although if fasten is doing native apps, maybe fasten can tap into iCloud keychain for easier secret key sharing across a user's apple devices.

Related to #3: This approach shifts a lot of the responsibility to the client. While not necessarily a bad thing, I'm assuming this may not be trivial to do with the current architecture.

@starsoccer
Copy link

  1. Yup totally agreed, and yes I agree adding keys does increase the complexity. I think we could offer users the option though and/or possibly store the key itself encrypted with the users password on the fasten server so all they need is their password so to speak. Its not ideal still though.
  2. Agreed it does. I do think there could be limited ways to avoid CORS by somehow providing time limited keys to the fasten server so yes your still trusting it slightly with data to refresh/update but its for a limited period of time. The ideal solution though requires more or less removing most if not all of the fasten server and makiing it mostly a standalone app though as your more or less bypassing it all at this stage anyways

@AnalogJ
Copy link
Member Author

AnalogJ commented Nov 7, 2023

Just to confirm that we're on the same page, are you familiar with 1Password? I'm a huge fan of their Zero-knowledge encryption implementation, and their development team has published a couple of pretty detailed articles about how it works. Ideally I'd like to mimic their implementation (since I'm not/we aren't security experts)

regarding #3, I actually attempted to build a SPA version of Fasten's backend previously - and I ran into a number of issues with performance, CORS and device compatibility. I'm curious what @cfu288's experience has been with SPA's since he built MereMedical as one.

@cfu288
Copy link
Contributor

cfu288 commented Nov 7, 2023

@AnalogJ I could talk a lot about the challenges of pursuing the SPA/PWA approach, but I have a lot to say that would be very out of scope for this issue.

I've recently released an optional and experimental password based encryption-at-rest support for Mere. Note that Mere cannot currently share data between devices. Data is local only to the device that the user is on. Zero-knowledge multi-device sync something I would like to explore once I've nailed/felt sufficiently happy with my encryption-at-rest strategy.

Currently, my implementation is simple:

  1. Mere implements simple full db encryption at rest by taking a user provided password, generating a key with Web Crypto, and using that as the key to encrypt/decrypt the entire user db. No secret key 1Password-esqe strategy is used right now due to UX difficulties of key sharing.
  2. When encryption is enabled:
  • save events: the entire user db serialized to a string, encrypted, and stored in indexeddb as a single row.
  • when the db initially loads: the entire user db is deserialized, decrypted, and stored entirely in memory.

The goal is to be able to share encrypted blobs between devices in the future. This is a pretty naive approach with pretty terrible theoretical performance, but acceptable (IMO) user performance for now.

Limitations:

  1. I do not do background sync of any type - I initiate a sync only when a user opens the PWA
  2. Mere uses local storage and is focused on mobile, single user devices

I do want to note that Mere is primarily a platform for my experimental exploration into PHR's and not a mature product.

@starsoccer
Copy link

Just to confirm that we're on the same page, are you familiar with 1Password? I'm a huge fan of their Zero-knowledge encryption implementation, and their development team has published a couple of pretty detailed articles about how it works. Ideally I'd like to mimic their implementation (since I'm not/we aren't security experts)

regarding #3, I actually attempted to build a SPA version of Fasten's backend previously - and I ran into a number of issues with performance, CORS and device compatibility. I'm curious what @cfu288's experience has been with SPA's since he built MereMedical as one.

Personally I am not. I dont doubt 1passwords approach and am by no means a security expert though.

Regarding the SPA doc you linked a few thoughts:

  1. I am not sure what you used web workers for but I am happy to assist with that as I have frontend experience. I am not clear on what was sluggish and why so any context there would be useful. My first suggestion would be to investigate WASM which Ive personally used and should drastically speed things up, assuming it was data processing intensive
  2. I think for atleast an initial POC the focus should be less on moving all the server side and lighthouse logic, and more on just getting data stored in zero knowledge way. I dont think there will be a way atleast right now to support client ids and secrets.
  3. For multiple devices, ideally this can still be easily accomplished as long as the data is still stored server side even if it is encrypted
  4. Multiuser roles do add alot of complexity. I think this is also something to skip for POC, but long term I think its possible to support using something like shamir secret sharing where data we want accessible to users is using a piece of there key and its a 1 of N protection

I dont perrsonally know angular, but Im happy to help however I can. My personally preference is towards React or Preact.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants