Asymmetric encryption with the Web Cryptography API

The Web Cryptography API lets us generate RSA and EC keypairs, but these keys don’t support encryption/decryption! The only algorithms supporting encryption and decryption are symmetric (and the obscure-sounding RSA-OAEP). Instead of directly providing asymmetric encryption/decryption, the Web Cryptography API provides the deriveKey method, which lets two communicators derive a shared symmetric secret. This post shows how to derive a shared AES key given two ECDH keys. This code should log true, asserting that Alice’s derived AES key is the same as Bob’s derived AES key:

const aliceKeyPair = await genKeyPair();
const bobKeyPair   = await genKeyPair();
const aliceSecret  = await deriveKey(aliceKeyPair.privateKey, bobKeyPair.publicKey  );
const bobSecret    = await deriveKey(  bobKeyPair.privateKey, aliceKeyPair.publicKey);
console.log((await exportKey(aliceSecret)).k === (await exportKey(bobSecret)).k);

Here’s the accompanying code which calls the crypto.subtle API:

function genKeyPair() {
  return crypto.subtle.generateKey({name:"ECDH", namedCurve: "P-256"}, true, ["deriveKey"]);
function deriveKey(privKey, pubKey) {
  return crypto.subtle.deriveKey(
    {"name": "ECDH", "public": pubKey},
    {name:"AES-CTR", length: 256},
    ["encrypt", "decrypt"]
async function exportKey(k) {
  return JSON.stringify(await crypto.subtle.exportKey("jwk", k));

After Alice and Bob have derived their shared symmetric secret, they can use this to communicate using normal symmetric crypto.

Tagged #programming, #crypto, #javascript.

Similar posts

More by Jim

Want to build a fantastic product using LLMs? I work at Granola where we're building the future IDE for knowledge work. Come and work with us! Read more or get in touch!

This page copyright James Fisher 2017. Content is not associated with my employer. Found an error? Edit this page.