I'm considering storing a sysmetric encryption key in the form of a CyptoKey Object with extractable set to false in IndexedDB and I was wandering whether this is safe or not. The questions that I didn't find the answers to are:

  • How are the keys stored on the users computer ? in plain text ? encrypted ? or as function states ? if the implementation is browser dependent, how does chromium do it ?
  • How easy is it for a malware on the users computer to retrieve the key from the storage ?
  • if this comes down to endpoint security, how secure is chromium's implementation in this sense ?

most of what I found so far can be linked to this answer

  • Do you need the key to be used automatically, without the user typing or making some sort of selection? – brynk Feb 8 at 2:26
  • @brynk yes I need to access the key from the js environment without the user entering an encryption password. – Mekacher Anis Feb 8 at 5:34
  • 1
    OP, I wrote the answer that you referenced in your question. AFAIK, information written to IndexedDB is unencrypted. If it were encrypted, then it would beg the question, where is that encryption key stored? It basically comes down to the problem of endpoint security. It would be nice if there was a way to use a HSM with the Web Crypto API, but AFAIK, there is no solution for this as of yet. – mti2935 Feb 8 at 13:48
  • @mti2935 in the Webcrypto standard it states that the standard doen't specify any storage implementation details to allow the user agents to use system specific storage mechanisms like OS key stores and HSMs, so I wonder how secure is chromium's implementation for example. A reference to a documentation or a source code would be amazing. – Mekacher Anis Feb 8 at 17:54
  • @MekacherAnis, I agree. IMO, setting .extractable to false is helpful for mitigating attacks where a malicious js could potentially access the underlying private key, and send it somewhere (e.g. a xss attack). But, AFAIK, neither this nor IndexedDB were intended to mitigate a side-channel attack, such as an end-point device compromise, which could potentially acess a private key stored on the device. End-point device security is an achillies heel in any end-to-end encryption system. Even the developers of Signal note this in their documentation (see bit.ly/3705uUW section 6.2) – mti2935 Feb 9 at 15:05

"I need to access the key from the js environment without the user entering an encryption password"

As @mti2935 points out, it is unencrypted in major browsers, and basically impossible at this point in time to achieve this goal without storing the key-encryption-key 'somewhere else'. I second that observation (for Firefox up to about 2019 at least, last time I looked at indexed-db).

Here is a possibility that wouldn't require you to store your long-term key un-encrypted: it won't allow your user to get away with 'doing nothing' if they want something more closely resembling security...

  1. an input type=password field, which possibly the user might choose to 'remember' in their password manager^ - this becomes the long-term key input
  2. this long-term key is then derived using a built-in WebCrypto PBKDF2, and used to decrypt the application symmetric key stored in indexed-db - you might wish to use another pbkdf such as Libsodium's Argon2 implementation, crypto_pwhash

^ If the user chooses to store the long-term key input (as a 'saved password') in their browser, then they won't need to type this again. It will be stored encrypted, and possibly further secured if the user applies a password for the internal password database key.

One obvious downside to this is potentially the repeated use of the pbkdf, which may interfere with the user's experience, depending on how 'hard' you tune it. Another is the static nature of your long term key, and what would be required if the user wishes to update any of the inputs. Since you don't specify how you're using the symmetric key that you wan't to store, I'll assume it's to access other encrypted data stored locally. (If you edit your question to clarify, I might update this answer.)

As to how the initial long-term key input is derived, you might consider having the user provide additional material via a key-file that they hold. You would then take the secure hash of any key-file that they choose, using a local file picker and the built-in keyed hashing functions.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.