"A cryptographic system should be secure even if everything about the system, except the key, is public knowledge.โ โ Auguste Kerckhoffs
To develop a webapp promising to the user his privacy and that his personal data will never leave his device, I first looked around but ended up building my own solution (without AI) so that it would do all this but also, allow to authenticate users on the server without compromising on their privacy.
NB: in our case user data is very sensitive; users are on the app not only to track news, prices or get alerted when a market moves, but also and mostly their portfolio worth (crypto, fiat, metals, shares,etc) and their transaction history.
Here is how it works :
-
Upon creating a new portfolio the webcrypto javascript API is used to create two pairs of RSA Keys. One to wrap / unwrap, one to verify / sign, along with a hash string to uniquely identify the portfolio (rather than the user). NB: the user can also import & use his own keys.
-
Optional : the user can add encryption (so that its data will be stored in his browser database - indexedDB - encrypted). If so he has to enter a password (not recoverable). This password is used only to encrypt the keys of the portfolio in the browser database. NB: the user can chose to not use browser memory and instead (manually) backup his data as a file (encrypted or not).
-
Optional : at the last step of portfolio creation, the verify key is sent to the app server along with a hash string (the portfolio id in the server database)
-
When adding data to his portfolio (and to indexedDB for storage) : a random single use (by key/value in indexedDB store) AES key is created to encrypt the value string, that key is then wrapped with the RSA wrap key & saved along the encrypted object in indexedDB.
-
To retrieve from indexedDB : the user gets a password prompt, the password decrypts the unwrap RSA key that will unwrap the AES key that will decrypt the encrypted object back to a string (and json).
NB: Why this hybrid encryption ? Because RSA encrypt/decrypt keys can only deal with very short strings and, although it has no use for us for now, we want the portfolio to have a public encrypt key so that it can (in the future) receive encrypted message from the server or from other users (process will be the same, wrapping an AES key to be sent along the, here stringified, encrypted object).
- To authenticate the portfolio server side (work in progress as not required for now = all the gates are open, no limit on searches, on tracking prices of cryptos & fiats not listed in kraken) : requests to the server that need to authenticate the portfolio will post the hash of the portfolio signed by the RSA key - password prompt first to decrypt sign key - and server will verify the signature before answering the request.
NB: users can chose to have the webapp remember the password for some time or the full session, which allow the private keys to remain in javascript memory, as a property of a const (not exactly global as the js of the app is wrapped in an anonymous function).
I don't believe it is possible to make encrypted portfolio recoverable in case of password loss unless storing the portfolio private unwrap key on the server.... Which would defeat the initial purpose.
Anyhow, would love your feedback (& I mean criticisms!).
All the best
To see this no sign up required process in action => https://kapkap.app/