# How to Implement Crypto Operations in workerd: Web Crypto and Node.js Compatibility

> Implement crypto operations in workerd using Web Crypto API or Node.js compatibility. Leverage a shared OpenSSL core for secure and efficient cryptographic tasks.

- Repository: [Cloudflare/workerd](https://github.com/cloudflare/workerd)
- Tags: how-to-guide
- Published: 2026-03-18

---

**workerd exposes cryptographic operations through both the standard Web Crypto API (`crypto.subtle`) and a Node.js-compatible layer (`node:crypto`), with both stacks sharing a common OpenSSL-based core implemented in `src/workerd/api/crypto/crypto.c++`.**

The cloudflare/workerd repository provides a complete stack for implementing **crypto operations in workerd**, exposing standard Web Crypto interfaces alongside Node.js compatibility primitives. Whether you are hashing data with SHA-256, encrypting with AES-GCM, or extending the runtime with custom algorithms, understanding the underlying C++ architecture helps you leverage these APIs effectively.

## Cryptographic Stacks in workerd

workerd provides two fully-featured cryptography stacks that share a common core wrapping OpenSSL primitives:

- **Web Crypto API**: Accessed via `crypto.subtle` in JavaScript, implemented primarily in [`src/workerd/api/crypto/crypto.h`](https://github.com/cloudflare/workerd/blob/main/src/workerd/api/crypto/crypto.h) and `src/workerd/api/crypto/crypto.c++`
- **Node.js-compatible crypto**: Accessed via `require('node:crypto')`, implemented in [`src/workerd/api/node/crypto.h`](https://github.com/cloudflare/workerd/blob/main/src/workerd/api/node/crypto.h) and `src/workerd/api/node/crypto.c++`

Both stacks expose functionality through the **JSG** binding layer (`jsg::Object`), routing JavaScript calls through generated stubs to C++ methods that delegate to algorithm-specific implementations.

## Implementing Web Crypto Operations

The **SubtleCrypto** interface declared in [`src/workerd/api/crypto/crypto.h`](https://github.com/cloudflare/workerd/blob/main/src/workerd/api/crypto/crypto.h) (lines 337-382) provides the standard Web Crypto methods including `digest()`, `encrypt()`, `sign()`, and `generateKey()`. Each method forwards to corresponding virtual methods on `CryptoKey::Impl` subclasses.

### AES-GCM Encryption Example

```javascript
// Generate an AES-GCM key
const key = await crypto.subtle.generateKey(
  { name: 'AES-GCM', length: 256 },
  true,               // extractable
  ['encrypt', 'decrypt']
);

// Encrypt a message
const iv = crypto.getRandomValues(new Uint8Array(12));
const plaintext = new TextEncoder().encode('Hello, workerd!');
const ciphertext = await crypto.subtle.encrypt(
  { name: 'AES-GCM', iv },
  key,
  plaintext
);

// Decrypt
const decrypted = await crypto.subtle.decrypt(
  { name: 'AES-GCM', iv },
  key,
  ciphertext
);
console.log(new TextDecoder().decode(decrypted)); // → Hello, workerd!

```

### Internal Routing of Crypto Calls

When you invoke a Web Crypto method, workerd follows this execution path:

1. The **JSG-generated stub** receives the JavaScript call and forwards it to the C++ method
2. The `lookupAlgorithm` function in `src/workerd/api/crypto/crypto.c++` (lines 7-28) identifies the appropriate algorithm implementation
3. The `validateOperation` function (lines 40-55) ensures key-algorithm compatibility
4. A **`CryptoKey::Impl`** subclass executes the algorithm-specific logic using OpenSSL objects (`EVP_*`, `RSA*`, `EC_KEY*`)
5. The implementation returns a `jsg::BufferSource` or `CryptoKey` back to JavaScript

## Using Node.js Crypto Compatibility

The Node.js compatibility layer mirrors Web Crypto primitives but follows Node.js method signatures. According to [`src/workerd/api/node/crypto.h`](https://github.com/cloudflare/workerd/blob/main/src/workerd/api/node/crypto.h) (lines 14-52), this API provides methods like `crypto.createHash()`, `crypto.randomBytes()`, and `crypto.pbkdf2()`. Key export and import helpers reside in `src/workerd/api/node/crypto-keys.c++`.

### Hashing and Key Derivation Example

```javascript
import crypto from 'node:crypto';

// One-shot SHA-256 hash
const hash = crypto.createHash('sha256')
  .update('Hello, workerd!')
  .digest('hex');
console.log(hash); // 9b... (SHA-256 digest)

// PBKDF2 key derivation
crypto.pbkdf2(
  'password',
  'salt',
  100_000,
  32,
  'sha256',
  (err, derivedKey) => {
    if (err) throw err;
    console.log(derivedKey.toString('hex'));
  }
);

```

Internally, these methods reuse the same core implementations from the Web Crypto stack. For example, `HashHandle` calls `HashContext` from the OpenSSL wrapper defined in the base crypto layer.

## Adding Custom Cryptographic Algorithms

To implement a new algorithm (such as a post-quantum KEM) in workerd:

1. **Register the algorithm** in `src/workerd/api/crypto/crypto.c++` by adding an entry to the `lookupAlgorithm` static set
2. **Create a subclass of `CryptoKey::Impl`** in the implementation headers (see [`src/workerd/api/crypto/impl.h`](https://github.com/cloudflare/workerd/blob/main/src/workerd/api/crypto/impl.h)) that implements required virtual methods: `import`, `generate`, `encrypt`, `decrypt`, `sign`, or `verify`
3. **Expose algorithm parameters** by adding a new dictionary struct to the Web Crypto definitions if extra parameters are required
4. **Update the Node compatibility layer** by adding static methods on `CryptoImpl` in `src/workerd/api/node/crypto.c++` that forward to your new `CryptoKey::Impl` functions
5. **Write tests** in `src/workerd/api/tests/` (e.g., `crypto-myalgo-test.wd-test`) and verify Node compatibility in `src/workerd/api/node/tests/`

## Summary

- workerd exposes **crypto operations** through both the **Web Crypto API** (`crypto.subtle`) and **Node.js-compatible** interfaces (`node:crypto`)
- Both stacks share a common **OpenSSL-based core** implemented in `src/workerd/api/crypto/crypto.c++` and [`src/workerd/api/crypto/crypto.h`](https://github.com/cloudflare/workerd/blob/main/src/workerd/api/crypto/crypto.h)
- The **JSG binding layer** routes JavaScript calls to C++ implementations via `lookupAlgorithm` and `CryptoKey::Impl` subclasses
- **Web Crypto** methods validate operations through `validateOperation` before executing algorithm-specific logic
- **Node.js compatibility** methods in `src/workerd/api/node/crypto.c++` delegate to the same core implementations used by Web Crypto
- New algorithms require registry updates, `CryptoKey::Impl` subclassing, and comprehensive testing in the `src/workerd/api/tests/` directory

## Frequently Asked Questions

### How does workerd route Web Crypto API calls to OpenSSL?

When you call `crypto.subtle.encrypt()` or similar methods, workerd uses the **JSG** binding system to forward the call to C++. The `lookupAlgorithm` function in `src/workerd/api/crypto/crypto.c++` maps the algorithm name to a specific implementation class derived from `CryptoKey::Impl`. This class then uses OpenSSL primitives (`EVP_*` functions) to perform the actual cryptographic operation and returns the result as a `jsg::BufferSource`.

### What is the difference between Web Crypto and Node crypto in workerd?

The **Web Crypto API** (`crypto.subtle`) follows the W3C standard with Promise-based async methods and structured algorithm dictionaries. The **Node.js compatibility layer** (`node:crypto`) provides synchronous, callback-based APIs matching Node.js signatures like `createHash()` and `pbkdf2()`. Despite different interfaces, both layers ultimately call the same underlying C++ implementations in `src/workerd/api/crypto/crypto.c++`, ensuring consistent behavior across both APIs.

### Can I add custom cryptographic algorithms to workerd?

Yes. To add a new algorithm, you must extend the algorithm registry in `src/workerd/api/crypto/crypto.c++`, implement a subclass of `CryptoKey::Impl` (defined in [`src/workerd/api/crypto/impl.h`](https://github.com/cloudflare/workerd/blob/main/src/workerd/api/crypto/impl.h)) with methods for key generation, import, and cryptographic operations, and expose the algorithm name in the Web Crypto dictionaries. You should also add corresponding methods to the Node compatibility layer in `src/workerd/api/node/crypto.c++` and write tests in `src/workerd/api/tests/`.

### Where are the cryptographic test suites located?

Web Crypto API tests reside in `src/workerd/api/tests/` with files following the pattern `crypto-*.wd-test`. Node.js compatibility tests are located in `src/workerd/api/node/tests/` with files named `crypto_*.js`. These test harnesses verify algorithm correctness, key import/export functionality, and compatibility with standard Web Crypto and Node.js behaviors.