Web Crypto

Last updated Sep 30, 2026

Background

The Web Crypto API provides a set of low-level functions for common cryptographic tasks. The Workers runtime implements the full surface of this API, but with some differences in the supported algorithms compared to those implemented in most browsers.

Performing cryptographic operations using the Web Crypto API is significantly faster than performing them purely in JavaScript. If you want to perform CPU-intensive cryptographic operations, you should consider using the Web Crypto API.

The Web Crypto API is implemented through the SubtleCrypto interface, accessible via the global crypto.subtle binding. A simple example of calculating a digest (also known as a hash) is:

const myText = new TextEncoder().encode('Hello world!');

const myDigest = await crypto.subtle.digest(
  {
    name: 'SHA-256',
  },
  myText // The data you want to hash as an ArrayBuffer
);

console.log(new Uint8Array(myDigest));

Some common uses include signing requests.

Caution

The Web Crypto API differs significantly from the Node.js Crypto API. If you are working with code that relies on the Node.js Crypto API, you can use it by enabling the nodejs_compat compatibility flag.


Constructors

  • crypto.DigestStream(algorithm) DigestStream
  • A non-standard extension to the crypto API that supports generating a hash digest from streaming data. The DigestStream itself is a WritableStream that does not retain the data written into it. Instead, it generates a hash digest automatically when the flow of data has ended.

Parameters

Usage

export default {
  async fetch(req) {
    // Fetch from origin
    const res = await fetch(req);

// We need to read the body twice so we `tee` it (get two instances)
    const [bodyOne, bodyTwo] = res.body.tee();
    // Make a new response so we can set the headers (responses from `fetch` are immutable)
    const newRes = new Response(bodyOne, res);
    // Create a SHA-256 digest stream and pipe the body into it
    const digestStream = new crypto.DigestStream("SHA-256");
    bodyTwo.pipeTo(digestStream);
    // Get the final result
    const digest = await digestStream.digest;
    // Turn it into a hex string
    const hexString = [...new Uint8Array(digest)]
      .map(b => b.toString(16).padStart(2, '0'))
      .join('')
    // Set a header with the SHA-256 hash and return the response
    newRes.headers.set("x-content-digest", `SHA-256=${hexString}`);
    return newRes;
  }
}
export default {
  async fetch(req): Promise<Response> {
    // Fetch from origin
    const res = await fetch(req);

// We need to read the body twice so we `tee` it (get two instances)
    const [bodyOne, bodyTwo] = res.body.tee();
    // Make a new response so we can set the headers (responses from `fetch` are immutable)
    const newRes = new Response(bodyOne, res);
    // Create a SHA-256 digest stream and pipe the body into it
    const digestStream = new crypto.DigestStream("SHA-256");
    bodyTwo.pipeTo(digestStream);
    // Get the final result
    const digest = await digestStream.digest;
    // Turn it into a hex string
    const hexString = [...new Uint8Array(digest)]
      .map(b => b.toString(16).padStart(2, '0'))
      .join('')
    // Set a header with the SHA-256 hash and return the response
    newRes.headers.set("x-content-digest", `SHA-256=${hexString}`);
    return newRes;
  }
} satisfies ExportedHandler;

Methods

  • crypto.randomUUID() : string
  • Generates a new random (version 4) UUID as defined in RFC 4122 ↗︎.
  • crypto.getRandomValues(bufferArrayBufferView) : ArrayBufferView
  • Fills the passed ArrayBufferView with cryptographically sound random values and returns the buffer.

Parameters

  • bufferArrayBufferView
  • Must be an Int8Array | Uint8Array | Uint8ClampedArray | Int16Array | Uint16Array | Int32Array | Uint32Array | BigInt64Array | BigUint64Array.

SubtleCrypto Methods

These methods are all accessed via crypto.subtle ↗︎, which is also documented in detail on MDN.

encrypt

  • encrypt(algorithm, key, data) : Promise\<ArrayBuffer>
  • Returns a Promise that fulfills with the encrypted data corresponding to the clear text, algorithm, and key given as parameters.

Parameters

decrypt

  • decrypt(algorithm, key, data) : Promise\<ArrayBuffer>
  • Returns a Promise that fulfills with the clear data corresponding to the ciphertext, algorithm, and key given as parameters.

Parameters

sign

  • sign(algorithm, key, data) : Promise\<ArrayBuffer>
  • Returns a Promise that fulfills with the signature corresponding to the text, algorithm, and key given as parameters.

Parameters

verify

  • verify(algorithm, key, signature, data) : Promise\<boolean>
  • Returns a Promise that fulfills with a Boolean value indicating if the signature given as a parameter matches the text, algorithm, and key that are also given as parameters.

Parameters

  • algorithmstring | object
  • Describes the algorithm to be used, including any required parameters, in an algorithm-specific format ↗︎.
  • keyCryptoKey
  • signatureArrayBuffer
  • dataArrayBuffer

digest

  • digest(algorithm, data) : Promise\<ArrayBuffer>
  • Returns a Promise that fulfills with a digest generated from the algorithm and text given as parameters.

Parameters

generateKey

  • generateKey(algorithm, extractable, keyUsages) : Promise\<CryptoKey> | Promise\<CryptoKeyPair>
  • Returns a Promise that fulfills with a newly-generated CryptoKey, for symmetrical algorithms, or a CryptoKeyPair, containing two newly generated keys, for asymmetrical algorithms. For example, to generate a new AES-GCM key:

js let keyPair = await crypto.subtle.generateKey( { name: 'AES-GCM', length: 256, }, true, ['encrypt', 'decrypt'] );

Parameters

deriveKey

  • deriveKey(algorithm, baseKey, derivedKeyAlgorithm, extractable, keyUsages) : Promise\<CryptoKey>
  • Returns a Promise that fulfills with a newly generated CryptoKey derived from the base key and specific algorithm given as parameters.

Parameters

deriveBits

  • deriveBits(algorithm, baseKey, length) : Promise\<ArrayBuffer>
  • Returns a Promise that fulfills with a newly generated buffer of pseudo-random bits derived from the base key and specific algorithm given as parameters. It returns a Promise which will be fulfilled with an ArrayBuffer containing the derived bits. This method is very similar to deriveKey(), except that deriveKey() returns a CryptoKey object rather than an ArrayBuffer. Essentially, deriveKey() is composed of deriveBits() followed by importKey().