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

Element-R: very slow to open #26821

Closed
richvdh opened this issue Jan 3, 2024 · 0 comments · Fixed by matrix-org/matrix-react-sdk#12543
Closed

Element-R: very slow to open #26821

richvdh opened this issue Jan 3, 2024 · 0 comments · Fixed by matrix-org/matrix-react-sdk#12543
Assignees
Labels
A-Element-R Issues affecting the port of Element's crypto layer to Rust T-Enhancement

Comments

@richvdh
Copy link
Member

richvdh commented Jan 3, 2024

TL;DR: It takes tens of seconds to open the indexeddb database. We should do less PBKDF.


The rust SDK encrypts its data in indexeddb with ChaChaPoly-1305, and hashes its keys with Blake3-256.

Obviously, we need to be able to recover the keys for those algorithms on subsequent runs of the application. Currently, they are derived as follows:

  1. A 256-bit AES-GCM key is created, and saved in indexeddb. (The cryptoKey property of an entry in the pickleKey store in the matrix-react-sdk database)
  2. A random 32-byte (=256 bits) array is created. This becomes the pickleKey. It is encrypted with the cryptoKey, and stored in indexeddb. (The encrypted property of the entry in the pickleKey store.)
  3. Two more random 32-byte arrays are created; these become the ChaChaPoly-1305 and Blake3 keys.
  4. The pickleKey is passed through 200000 rounds of PBKDF2-SHA2 to produce another random 32-byte array, which is used as another ChaChaPoly-1305 key.
  5. The primary ChaChaPoly-1305 and Blake3 keys are encrypted by this new ChaChaPoly-1305 key, and then stored, along with details of the PBKDF derivation, in indexeddb. (The value of an entry in the matrix-sdk-crypto store in the matrix-js-sdk::matrix-sdk-crypto-meta).

[The storage of the pickleKey is slightly different on element desktop (it is stored in the system keychain, rather than being encrypted by the AES-GCM key and stored in indexeddb), but the net result is the same: it is a crypto-random 32-byte array.]

On reload, we effectively reverse the process:

  1. The encrypted pickleKey is loaded from the matrix-react-sdk/pickleKey store.
  2. The encrypted pickleKey is decrypted using the cryptoKey, also loaded from the matrix-react-sdk/pickleKey store.
  3. The encrypted ChaChaPoly-1305 and Blake3 keys, and details of the PBKDF derivation, are loaded from matrix-js-sdk::matrix-sdk-crypto-meta/matrix-sdk-crypto.
  4. The pickleKey is passed through PBKDF to produce the intermediate ChaChaPoly-1305 key.
  5. The primary ChaChaPoly-1305 and Blake3 keys are decrypted using the intermediate ChaChaPoly-1305 key.

It seems to me that this is, ahem, /baroque/. It is also very slow: the PBKDF calculation takes 10s of seconds. (That is the job of PBKDF: it is designed to resist brute-forcing of human-readable passwords by slowing down the process. However, it has little value when the input is a pseudo-random array the same size as the output).

Fundamentally, both the Javascript and Rust layers are jumping through their own hoops for "security", and the whole thing is overcomplicated.

I think an easy win would be to skip the PBKDF step and use the pickleKey directly as a ChaChaPoly-1305 key to encrypt the primary ChaChaPoly-1305 and Blake3 keys. (Or, maybe better, pass pickleKey through an HMAC-based KDF). I think this could be done without breaking existing sessions, since we already store details of the PBKDF derivation: we would simply switch to the faster derivation for new sessions.

It would be nice to get rid of the whole matrix-js-sdk::matrix-sdk-crypto-meta/matrix-sdk-crypto store, and just use an HMAC-based KDF to derive the ChaChaPoly-1305 and Blake3 keys from the pickleKey. But that's a bit harder to do without breaking existing sessions.

@richvdh richvdh added the A-Element-R Issues affecting the port of Element's crypto layer to Rust label Jan 3, 2024
@github-actions github-actions bot added the Z-Labs label Jan 3, 2024
@richvdh richvdh self-assigned this May 16, 2024
richvdh added a commit to matrix-org/matrix-rust-sdk that referenced this issue May 22, 2024
…3423)

Allow applications to skip the PBKDF2 operation if they already have a cryptographically secure key,
instead using a simple HKDF to derive a key.

In order to maintain compatibility for existing element-web sessions, if we discover that we have an
existing store that was encrypted with a key derived from PBKDF2, then we reconstruct what
element-web used to do: specifically, we base64-encode the key to obtain the "passphrase" that
was previously passed in. If that matches, we know we've got the right key, and can update the
meta store accordingly.

Part of a resolution to element-hq/element-web#26821.

Signed-off-by: Richard van der Hoff <[email protected]>
Co-authored-by: Damir Jelić <[email protected]>
@richvdh richvdh removed the Z-Labs label May 23, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-Element-R Issues affecting the port of Element's crypto layer to Rust T-Enhancement
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants