Documentation Index Fetch the complete documentation index at: https://mintlify.com/cloudflare/workerd/llms.txt
Use this file to discover all available pages before exploring further.
The Crypto API implements the Web Crypto standard for performing cryptographic operations. It provides secure, efficient implementations of hashing, encryption, signing, and key management.
Overview
The Crypto API provides:
Cryptographically secure random number generation
Hash functions (SHA-256, SHA-384, SHA-512, etc.)
Symmetric encryption (AES-GCM, AES-CBC, AES-CTR)
Asymmetric encryption (RSA-OAEP)
Digital signatures (RSA-PSS, ECDSA, EdDSA)
Key derivation (PBKDF2, HKDF)
Key generation and management
Implementation: src/workerd/api/crypto/ directory
Random values
Generate cryptographically secure random values:
// Generate random bytes
const array = new Uint8Array ( 32 );
crypto . getRandomValues ( array );
// Generate random UUID
const uuid = crypto . randomUUID ();
console . log ( uuid ); // "a7f32a8c-..."
Hashing
Compute message digests:
// Hash a string
const data = new TextEncoder (). encode ( 'Hello World' );
const hashBuffer = await crypto . subtle . digest ( 'SHA-256' , data );
// Convert to hex string
const hashArray = Array . from ( new Uint8Array ( hashBuffer ));
const hashHex = hashArray
. map ( b => b . toString ( 16 ). padStart ( 2 , '0' ))
. join ( '' );
console . log ( hashHex );
Supported hash algorithms
// SHA-2 family
await crypto . subtle . digest ( 'SHA-1' , data ); // Not recommended
await crypto . subtle . digest ( 'SHA-256' , data );
await crypto . subtle . digest ( 'SHA-384' , data );
await crypto . subtle . digest ( 'SHA-512' , data );
// MD5 (not recommended for security)
await crypto . subtle . digest ( 'MD5' , data );
Implementation: src/workerd/api/crypto/digest.h and digest.c++
Symmetric encryption
AES-GCM
Encrypt and decrypt with authenticated encryption:
// Generate a key
const key = await crypto . subtle . generateKey (
{ name: 'AES-GCM' , length: 256 },
true ,
[ 'encrypt' , 'decrypt' ]
);
// Encrypt
const iv = crypto . getRandomValues ( new Uint8Array ( 12 ));
const data = new TextEncoder (). encode ( 'Secret message' );
const encrypted = await crypto . subtle . encrypt (
{ name: 'AES-GCM' , iv },
key ,
data
);
// Decrypt
const decrypted = await crypto . subtle . decrypt (
{ name: 'AES-GCM' , iv },
key ,
encrypted
);
const text = new TextDecoder (). decode ( decrypted );
console . log ( text ); // "Secret message"
AES-CBC
Block cipher mode with padding:
const key = await crypto . subtle . generateKey (
{ name: 'AES-CBC' , length: 256 },
true ,
[ 'encrypt' , 'decrypt' ]
);
const iv = crypto . getRandomValues ( new Uint8Array ( 16 ));
const encrypted = await crypto . subtle . encrypt (
{ name: 'AES-CBC' , iv },
key ,
data
);
AES-CTR
Counter mode for stream encryption:
const key = await crypto . subtle . generateKey (
{ name: 'AES-CTR' , length: 256 },
true ,
[ 'encrypt' , 'decrypt' ]
);
const counter = crypto . getRandomValues ( new Uint8Array ( 16 ));
const encrypted = await crypto . subtle . encrypt (
{ name: 'AES-CTR' , counter , length: 64 },
key ,
data
);
Implementation: src/workerd/api/crypto/aes.c++
Asymmetric encryption
RSA-OAEP
Public key encryption:
// Generate key pair
const keyPair = await crypto . subtle . generateKey (
{
name: 'RSA-OAEP' ,
modulusLength: 2048 ,
publicExponent: new Uint8Array ([ 1 , 0 , 1 ]),
hash: 'SHA-256'
},
true ,
[ 'encrypt' , 'decrypt' ]
);
// Encrypt with public key
const encrypted = await crypto . subtle . encrypt (
{ name: 'RSA-OAEP' },
keyPair . publicKey ,
data
);
// Decrypt with private key
const decrypted = await crypto . subtle . decrypt (
{ name: 'RSA-OAEP' },
keyPair . privateKey ,
encrypted
);
Implementation: src/workerd/api/crypto/rsa.h and rsa.c++
Digital signatures
ECDSA
Elliptic curve signatures:
// Generate key pair
const keyPair = await crypto . subtle . generateKey (
{
name: 'ECDSA' ,
namedCurve: 'P-256'
},
true ,
[ 'sign' , 'verify' ]
);
// Sign
const signature = await crypto . subtle . sign (
{
name: 'ECDSA' ,
hash: 'SHA-256'
},
keyPair . privateKey ,
data
);
// Verify
const valid = await crypto . subtle . verify (
{
name: 'ECDSA' ,
hash: 'SHA-256'
},
keyPair . publicKey ,
signature ,
data
);
console . log ( 'Valid:' , valid );
EdDSA
Edwards curve signatures:
// Generate Ed25519 key pair
const keyPair = await crypto . subtle . generateKey (
{
name: 'Ed25519'
},
true ,
[ 'sign' , 'verify' ]
);
// Sign
const signature = await crypto . subtle . sign (
{ name: 'Ed25519' },
keyPair . privateKey ,
data
);
// Verify
const valid = await crypto . subtle . verify (
{ name: 'Ed25519' },
keyPair . publicKey ,
signature ,
data
);
RSA-PSS
RSA probabilistic signature scheme:
const keyPair = await crypto . subtle . generateKey (
{
name: 'RSA-PSS' ,
modulusLength: 2048 ,
publicExponent: new Uint8Array ([ 1 , 0 , 1 ]),
hash: 'SHA-256'
},
true ,
[ 'sign' , 'verify' ]
);
const signature = await crypto . subtle . sign (
{
name: 'RSA-PSS' ,
saltLength: 32
},
keyPair . privateKey ,
data
);
Implementation: src/workerd/api/crypto/ec.h and ec.c++
Key derivation
PBKDF2
Password-based key derivation:
// Import password as key material
const password = new TextEncoder (). encode ( 'password' );
const keyMaterial = await crypto . subtle . importKey (
'raw' ,
password ,
'PBKDF2' ,
false ,
[ 'deriveBits' , 'deriveKey' ]
);
// Derive key
const salt = crypto . getRandomValues ( new Uint8Array ( 16 ));
const key = await crypto . subtle . deriveKey (
{
name: 'PBKDF2' ,
salt ,
iterations: 100000 ,
hash: 'SHA-256'
},
keyMaterial ,
{ name: 'AES-GCM' , length: 256 },
true ,
[ 'encrypt' , 'decrypt' ]
);
HKDF
HMAC-based key derivation:
const keyMaterial = await crypto . subtle . importKey (
'raw' ,
inputKeyMaterial ,
'HKDF' ,
false ,
[ 'deriveBits' , 'deriveKey' ]
);
const key = await crypto . subtle . deriveKey (
{
name: 'HKDF' ,
salt ,
info ,
hash: 'SHA-256'
},
keyMaterial ,
{ name: 'AES-GCM' , length: 256 },
true ,
[ 'encrypt' , 'decrypt' ]
);
Implementation: src/workerd/api/crypto/pbkdf2.c++ and hkdf.c++
Key management
Generate keys
Generate cryptographic keys:
// Symmetric key
const aesKey = await crypto . subtle . generateKey (
{ name: 'AES-GCM' , length: 256 },
true ,
[ 'encrypt' , 'decrypt' ]
);
// Asymmetric key pair
const rsaKeyPair = await crypto . subtle . generateKey (
{
name: 'RSA-PSS' ,
modulusLength: 2048 ,
publicExponent: new Uint8Array ([ 1 , 0 , 1 ]),
hash: 'SHA-256'
},
true ,
[ 'sign' , 'verify' ]
);
Export keys
Export keys in various formats:
// Export as JWK
const jwk = await crypto . subtle . exportKey ( 'jwk' , key );
console . log ( jwk );
// Export as raw bytes
const raw = await crypto . subtle . exportKey ( 'raw' , key );
// Export as PKCS#8 (private key)
const pkcs8 = await crypto . subtle . exportKey ( 'pkcs8' , privateKey );
// Export as SPKI (public key)
const spki = await crypto . subtle . exportKey ( 'spki' , publicKey );
Import keys
Import keys from various formats:
// Import from JWK
const key = await crypto . subtle . importKey (
'jwk' ,
jwkObject ,
{ name: 'AES-GCM' },
true ,
[ 'encrypt' , 'decrypt' ]
);
// Import from raw bytes
const key = await crypto . subtle . importKey (
'raw' ,
keyBytes ,
{ name: 'AES-GCM' },
true ,
[ 'encrypt' , 'decrypt' ]
);
// Import from PKCS#8
const privateKey = await crypto . subtle . importKey (
'pkcs8' ,
pkcs8Bytes ,
{ name: 'RSA-PSS' , hash: 'SHA-256' },
true ,
[ 'sign' ]
);
Implementation: src/workerd/api/crypto/keys.h and keys.c++, jwk.h and jwk.c++
DigestStream
Compute hashes from streams:
const digestStream = new DigestStream ( 'SHA-256' );
const writer = digestStream . getWriter ();
await writer . write ( new TextEncoder (). encode ( 'Hello ' ));
await writer . write ( new TextEncoder (). encode ( 'World' ));
await writer . close ();
const digest = await digestStream . digest ;
const hashHex = Array . from ( new Uint8Array ( digest ))
. map ( b => b . toString ( 16 ). padStart ( 2 , '0' ))
. join ( '' );
Best practices
Prefer modern algorithms: // Good: AES-GCM for encryption
const key = await crypto . subtle . generateKey (
{ name: 'AES-GCM' , length: 256 },
true ,
[ 'encrypt' , 'decrypt' ]
);
// Avoid: MD5 or SHA-1 for security
Always generate new random values: // Good: new random IV for each encryption
const iv = crypto . getRandomValues ( new Uint8Array ( 12 ));
// Bad: reusing IVs
const iv = new Uint8Array ( 12 ); // All zeros!
Never hardcode keys in source code: // Good: get keys from environment or secrets
const keyData = await env . SECRETS . get ( 'encryption-key' );
const key = await crypto . subtle . importKey ( ... );
// Bad: hardcoded key
const key = new Uint8Array ([ 1 , 2 , 3 , ... ]);
Use sufficient key lengths
Use recommended key sizes: // Good: 256-bit AES
{ name : 'AES-GCM' , length : 256 }
// Good: 2048-bit RSA minimum
{ name : 'RSA-OAEP' , modulusLength : 2048 }
Implementation details
The Crypto API is implemented across multiple files in src/workerd/api/crypto/:
crypto.h / .c++ - Public API (SubtleCrypto, CryptoKey)
impl.h / .c++ - Internal base classes and algorithm dispatch
keys.h / .c++ - Key management and encoding
aes.c++ - AES algorithms (CBC, CTR, GCM, KW)
rsa.h / .c++ - RSA algorithms (OAEP, PSS, PKCS1)
ec.h / .c++ - Elliptic curve algorithms (ECDSA, ECDH, EdDSA)
digest.h / .c++ - Hash functions
kdf.h, pbkdf2.c++, hkdf.c++ - Key derivation
jwk.h / .c++ - JWK import/export
All operations use BoringSSL (Google’s OpenSSL fork) wrapped with the OSSLCALL() macro for error handling.
Key usage tracking from src/workerd/api/crypto/crypto.h:28:
class CryptoKeyUsageSet {
static constexpr CryptoKeyUsageSet encrypt ();
static constexpr CryptoKeyUsageSet decrypt ();
static constexpr CryptoKeyUsageSet sign ();
static constexpr CryptoKeyUsageSet verify ();
static constexpr CryptoKeyUsageSet deriveKey ();
static constexpr CryptoKeyUsageSet deriveBits ();
static constexpr CryptoKeyUsageSet wrapKey ();
static constexpr CryptoKeyUsageSet unwrapKey ();
};