You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This library implements ECIES (Elliptic Curve Integrated Encryption Scheme) with an additional RSA layer that wraps the shared secret before decryption.
Note: You only need the X-coordinate for key derivation. No need to decompress the full point.
Step 3: Derive AES Key using HKDF
Property
Value
Algorithm
HKDF
Hash
SHA-256
Salt
Empty/None (new Uint8Array(0))
IKM (Input Key Material)
X-coordinate (32 bytes)
Info
context parameter
Output Length
32 bytes (256 bits)
// Import the X-coordinate as raw key materialconstikm=awaitcrypto.subtle.importKey("raw",xCoordinate,"HKDF",false,["deriveKey"]);// Derive the AES-256 keyconstaesKey=awaitcrypto.subtle.deriveKey({name: "HKDF",hash: "SHA-256",salt: newUint8Array(0),// No saltinfo: context// The context bytes},ikm,{name: "AES-GCM",length: 256},false,["decrypt"]);
Step 4: AES-GCM Decrypt
Property
Value
Algorithm
AES-256-GCM
Key Size
256 bits (32 bytes)
Nonce/IV Size
96 bits (12 bytes)
Tag Size
128 bits (16 bytes, appended to ciphertext)
constplaintext=awaitcrypto.subtle.decrypt({name: "AES-GCM",iv: nonce,tagLength: 128// 16 bytes},aesKey,ciphertext// Includes auth tag at the end);
Complete JavaScript Implementation
asyncfunctioneciesDecryptWithRsa(encryptedSharedSecret,rsaPrivateKey,ciphertext,nonce,context){// Step 1: RSA-OAEP decrypt to recover the EC pointconstpointBytes=newUint8Array(awaitcrypto.subtle.decrypt({name: "RSA-OAEP"},rsaPrivateKey,encryptedSharedSecret));// Step 2: Extract X-coordinate (bytes 1-32 of compressed point)constxCoordinate=pointBytes.slice(1,33);// Step 3: HKDF to derive AES keyconstikm=awaitcrypto.subtle.importKey("raw",xCoordinate,"HKDF",false,["deriveKey"]);constaesKey=awaitcrypto.subtle.deriveKey({name: "HKDF",hash: "SHA-256",salt: newUint8Array(0),info: context},ikm,{name: "AES-GCM",length: 256},false,["decrypt"]);// Step 4: AES-GCM decryptconstplaintext=awaitcrypto.subtle.decrypt({name: "AES-GCM",iv: nonce,tagLength: 128},aesKey,ciphertext);returnnewUint8Array(plaintext);}
RSA Key Requirements
When importing or generating the RSA private key:
// For importing a PKCS#8 private key:constrsaPrivateKey=awaitcrypto.subtle.importKey("pkcs8",privateKeyDer,{name: "RSA-OAEP",hash: "SHA-256"// Must match!},false,["decrypt"]);
Test Vectors
To verify compatibility, have the Rust side output these intermediate values: