fix(e2ee): verify transferred key pair after QR login and fallback to fresh registration#197
Merged
Merged
Conversation
… fresh registration Fixes #195. After QR login, the E2EE key received via decodeE2EEKeyV1 may not match the server-registered public key — this happens when the primary device does not complete PIN-authorized key transfer for accounts with pre-existing identity keys. Changes: - Add verifyE2EEKeyPair / verifyStoredKeyAgainstServer to validate that the decrypted private key derives to the server-registered public key - decodeE2EEKeyV1 now rejects mismatched keys (emits e2ee:keyMismatch) - Both requestSQR and requestSQR2 fall back to registerE2EEKeyPair when decodeE2EEKeyV1 returns undefined (mismatch or missing e2eeInfo) - registerE2EEKeyPair generates a fresh Curve25519 key pair and registers it with the server, ensuring the local private key always matches
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #195.
After QR login, the E2EE key received via
decodeE2EEKeyV1may not match the server-registered public key. This happens when the primary device does not complete PIN-authorized key transfer for accounts with pre-existing identity keys — theencryptedKeyChaindecrypts to a private key that does not correspond to the public key the server advertises for thatkeyId.Root cause: For accounts whose E2EE identity was established on the phone, the server expects the primary device to participate in key transfer (via
respondE2EELoginRequestor the QR migration flow). If this doesn't complete, the key chain in the QR login response contains an invalid/stale private key.Fix:
verifyE2EEKeyPair()— derives the public key from a private key vianacl.scalarMult.baseand compares against a registered public keyverifyStoredKeyAgainstServer()— fetches registered public keys and verifies the decoded private key matchesdecodeE2EEKeyV1now validates the decoded key pair before storing:undefinedand emitse2ee:keyMismatchevent if either check failsrequestSQRandrequestSQR2now fall back toregisterE2EEKeyPair()whendecodeE2EEKeyV1returnsundefined— this generates a fresh Curve25519 key pair, registers it with the server, and stores it locallyResult: The local private key always matches the server-registered public key, so ECDH-derived shared secrets are symmetric between sender and receiver.
Test plan
deno checkpasses on modified filese2ee:keyMismatchfires and fallback key registration succeedsdecodeE2EEKeyV1passes validation (no fallback needed)🤖 Generated with Claude Code