JSPM

  • Created
  • Published
  • Downloads 108320
  • Score
    100M100P100Q198121F
  • License MIT

A Hybrid Public Key Encryption (HPKE) core module for various JavaScript runtimes

Package Exports

  • @hpke/core
  • @hpke/core/package.json

Readme

@hpke/core

A TypeScript Hybrid Public Key Encryption (HPKE) core module implemented using only Web Cryptography API. It does not support the X25519/X448-based KEMs and the ChaCha20Poly1305 AEAD, but it has no external module dependencies and is small in size.

Index

Installation

Web Browser

Followings are how to use with typical CDNs. Other CDNs can be used as well.

Using esm.sh:

<!-- use a specific version -->
<script type="module">
  import * as hpke from "https://esm.sh/@hpke/core@1.1.0";
  // import { KemId, KdfId, AeadId, CipherSuite } from "https://esm.sh/@hpke/core@1.1.0";
</script>

<!-- use the latest stable version -->
<script type="module">
  import * as hpke from "https://esm.sh/@hpke/core";
  // ...
</script>

Using unpkg:

<!-- use a specific version -->
<script type="module">
  import * as hpke from "https://unpkg.com/@hpke/core@1.1.0/esm/mod.js";
  import { KemId, KdfId, AeadId, CipherSuite} from "https://unpkg.com/@hpke/core@1.1.0/esm/mod.js";
  // ...
</script>

Node.js

Using npm:

npm install @hpke/core

Using yarn:

yarn add @hpke/core

Deno

Using deno.land:

// use a specific version
import * as hpke from "https://deno.land/x/hpke@1.1.0/core/mod.ts";

// use the latest stable version
import * as hpke from "https://deno.land/x/hpke/core/mod.ts";

Cloudflare Workers

git clone git@github.com:dajiaji/hpke-js.git
cd hpke-js/core
npm install -g esbuild
deno task dnt
deno task minify > $YOUR_SRC_PATH/hpke-core.js

Usage

This section shows some typical usage examples.

Browsers

<html>
  <head></head>
  <body>
    <script type="module">
      // import * as hpke from "https://esm.sh/hpke-js@1.1.0";
      import { KemId, KdfId, AeadId, CipherSuite } from "https://esm.sh/@hpke/core@1.1.0";

      globalThis.doHpke = async () => {

        const suite = new CipherSuite({
          kem: KemId.DhkemP256HkdfSha256,
          kdf: KdfId.HkdfSha256,
          aead: AeadId.Aes128Gcm
        });
 
        const rkp = await suite.kem.generateKeyPair();
      
        const sender = await suite.createSenderContext({
          recipientPublicKey: rkp.publicKey
        });

        const recipient = await suite.createRecipientContext({
          recipientKey: rkp.privateKey, // rkp (CryptoKeyPair) is also acceptable.
          enc: sender.enc,
        });

        // encrypt
        const ct = await sender.seal(new TextEncoder().encode("hello world!"));
      
        // decrypt
        try {
          const pt = await recipient.open(ct);

          // hello world!
          alert(new TextDecoder().decode(pt));
        } catch (err) {
          alert("failed to decrypt.");
        }
      }
      
    </script>
    <button type="button" onclick="doHpke()">do HPKE</button>
  </body>
</html>

Node.js

import { AeadId, CipherSuite, KdfId, KemId } from "@hpke/core";
// const { KemId, KdfId, AeadId, CipherSuite } = require("@hpke/core");

async function doHpke() {
  // setup
  const suite = new CipherSuite({
    kem: KemId.DhkemP256HkdfSha256,
    kdf: KdfId.HkdfSha256,
    aead: AeadId.Aes128Gcm,
  });

  const rkp = await suite.kem.generateKeyPair();

  const sender = await suite.createSenderContext({
    recipientPublicKey: rkp.publicKey,
  });

  const recipient = await suite.createRecipientContext({
    recipientKey: rkp.privateKey,
    enc: sender.enc,
  });

  // encrypt
  const ct = await sender.seal(new TextEncoder().encode("my-secret-message"));

  // decrypt
  try {
    const pt = await recipient.open(ct);

    console.log("decrypted: ", new TextDecoder().decode(pt));
    // decrypted: my-secret-message
  } catch (err) {
    console.log("failed to decrypt.");
  }
}

doHpke();

Deno

import { KdfId, AeadId, CipherSuite } from "https://deno.land/x/hpke@1.1.0/core/mod.ts";

async function doHpke() {
  // setup
  const suite = new CipherSuite({
    kem: KemId.DhkemP256HkdfSha256,
    kdf: KdfId.HkdfSha256,
    aead: AeadId.Aes128Gcm,
  });

  const rkp = await suite.kem.generateKeyPair();

  const sender = await suite.createSenderContext({
    recipientPublicKey: rkp.publicKey,
  });

  const recipient = await suite.createRecipientContext({
    recipientKey: rkp.privateKey,
    enc: sender.enc,
  });

  // encrypt
  const ct = await sender.seal(new TextEncoder().encode("my-secret-message"));

  try {
    // decrypt
    const pt = await recipient.open(ct);

    console.log("decrypted: ", new TextDecoder().decode(pt));
    // decrypted: my-secret-message
  } catch (_err: unknown) {
    console.log("failed to decrypt.");
  }
}

doHpke();

Contributing

We welcome all kind of contributions, filing issues, suggesting new features or sending PRs.