react-native-quick-crypto icon indicating copy to clipboard operation
react-native-quick-crypto copied to clipboard

✨subtle.deriveBits for ECDH

Open mbirnhak opened this issue 9 months ago • 0 comments

What feature or enhancement are you suggesting?

I am creating a react native app for a digital identity wallet. I am trying to use JOSE to create a JWE to wrap a verifiable presentation. The JOSE library uses node, which I am trying to substitute for QuickCrypto. However, it does not yet support subtle.deriveBits for ECDH, which seems to be an important alg used for creating JWE. Support for this would be a great help!

What Platforms whould this feature/enhancement affect?

iOS, Android

Alternatives/Workarounds

I have created a workaround for the P-256 curve using a different library for elliptic curve cryptography. I created my own deriveBits method that takes the same parameters and produces the same output format, but I have not thoroughly tested it so I cannot confirm is is 100% correct. Let me know your thoughts!

import { p256 } from '@noble/curves/p256';
function convertToHexString(jwk, keyField) {
    const keyValue = jwk[keyField];
    const cleanBase64 = keyValue.replace(/\.$/, '').replace(/-/g, '+').replace(/_/g, '/');
    const padding = '='.repeat((4 - (cleanBase64.length % 4)) % 4);
    const base64 = cleanBase64 + padding;
    const keyHexString = atob(base64).split('').map((c) => {
        const hex = c.charCodeAt(0).toString(16);
        return hex.length === 1 ? '0' + hex : hex;
    }).join('');
    return keyHexString;
}
QuickCrypto.subtle.deriveBits = async (algorithm, privateKey, length = 256) => {
            try {
                const exportedPublicKey = await QuickCrypto.subtle.exportKey('jwk', algorithm.public);
                const exportedPrivatKey = await QuickCrypto.subtle.exportKey('jwk', privateKey);

                const privateKeyHex = convertToHexString(exportedPrivatKey, 'd');
                const publicKeyHexX = convertToHexString(exportedPublicKey, 'x');
                const publicKeyHexY = convertToHexString(exportedPublicKey, 'y');
                const publicKeyHex = "04" + publicKeyHexX + publicKeyHexY;

                const sharedSecret = p256.getSharedSecret(privateKeyHex, publicKeyHex, false);
                // Convert uint8Array to ArrayBuffer
                const sharedSecretBuffer = sharedSecret.buffer.slice(
                    sharedSecret.byteOffset,
                    sharedSecret.byteOffset + sharedSecret.byteLength
                );
                return sharedSecretBuffer;
            } catch (error) {
                console.error('SETUP: Error in deriveBits', error);
                throw error;
            }
        }

Additional information

mbirnhak avatar Apr 03 '25 19:04 mbirnhak