From b9275642e12e81a70e6753e97cf079cf12418e8a Mon Sep 17 00:00:00 2001 From: larabr <7375870+larabr@users.noreply.github.com> Date: Wed, 9 Jul 2025 16:21:33 +0200 Subject: [PATCH] Add workaround for WebCrypto X25519 key export bug on WebKit Linux https://bugs.webkit.org/show_bug.cgi?id=289693 --- src/crypto/public_key/elliptic/ecdh_x.js | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/crypto/public_key/elliptic/ecdh_x.js b/src/crypto/public_key/elliptic/ecdh_x.js index 608c990a..6a0f562b 100644 --- a/src/crypto/public_key/elliptic/ecdh_x.js +++ b/src/crypto/public_key/elliptic/ecdh_x.js @@ -33,6 +33,12 @@ export async function generate(algo) { const privateKey = await webCrypto.exportKey('jwk', webCryptoKey.privateKey); const publicKey = await webCrypto.exportKey('jwk', webCryptoKey.publicKey); + if (privateKey.x !== publicKey.x) { // Weird issue with Webkit on Linux: https://bugs.webkit.org/show_bug.cgi?id=289693 + const err = new Error('Unexpected mismatching public point'); + err.name = 'NotSupportedError'; + throw err; + } + return { A: new Uint8Array(b64ToUint8Array(publicKey.x)), k: b64ToUint8Array(privateKey.d) @@ -190,15 +196,21 @@ export async function generateEphemeralEncryptionMaterial(algo, recipientA) { case enums.publicKey.x25519: try { const webCrypto = util.getWebCrypto(); - const jwk = publicKeyToJWK(algo, recipientA); const ephemeralKeyPair = await webCrypto.generateKey('X25519', true, ['deriveKey', 'deriveBits']); + const ephemeralPublicKeyJwt = await webCrypto.exportKey('jwk', ephemeralKeyPair.publicKey); + const ephemeralPrivateKeyJwt = await webCrypto.exportKey('jwk', ephemeralKeyPair.privateKey); + if (ephemeralPrivateKeyJwt.x !== ephemeralPublicKeyJwt.x) { // Weird issue with Webkit on Linux: https://bugs.webkit.org/show_bug.cgi?id=289693 + const err = new Error('Unexpected mismatching public point'); + err.name = 'NotSupportedError'; + throw err; + } + const jwk = publicKeyToJWK(algo, recipientA); const recipientPublicKey = await webCrypto.importKey('jwk', jwk, 'X25519', false, []); const sharedSecretBuffer = await webCrypto.deriveBits( { name: 'X25519', public: recipientPublicKey }, ephemeralKeyPair.privateKey, getPayloadSize(algo) * 8 // in bits ); - const ephemeralPublicKeyJwt = await webCrypto.exportKey('jwk', ephemeralKeyPair.publicKey); return { sharedSecret: new Uint8Array(sharedSecretBuffer), ephemeralPublicKey: new Uint8Array(b64ToUint8Array(ephemeralPublicKeyJwt.x))