The Web Cryptography API provides cryptographic operations in web applications. Deno's implementation is located in the deno_crypto extension ext/crypto/lib.rs114-134 which provides the Crypto interface with a subtle property exposing SubtleCrypto for advanced cryptographic operations.
The implementation bridges JavaScript API calls to Rust-based cryptographic operations using the deno_core ops system. Cryptographic primitives are provided by aws-lc-rs, rsa, p256, p384, p521, x25519_dalek, and related crates.
Key Components:
Crypto interface: Provides getRandomValues(), randomUUID(), and the subtle property ext/crypto/00_crypto.js22-24SubtleCrypto interface: Methods for cryptographic operations (encrypt, decrypt, sign, verify, digest, key management) ext/crypto/00_crypto.js530-1233CryptoKey class: Represents cryptographic keys with type, algorithm, usages, and extractability ext/crypto/00_crypto.js67-98deno_crypto extension ext/crypto/lib.rs116-124Sources: ext/crypto/00_crypto.js3-15 ext/crypto/lib.rs1-134
The Web Crypto API implementation follows a layered architecture where JavaScript API calls are validated, normalized, and delegated to Rust operations. Most operations are implemented as methods on cppgc-wrapped Rust classes ext/crypto/00_crypto.js3-10
Web Crypto API Flow
Sources: ext/crypto/00_crypto.js3-15 ext/crypto/00_crypto.js821-956 ext/crypto/lib.rs107-113
The CryptoKey class ext/crypto/00_crypto.js67-98 represents a cryptographic key. The type, extractable, usages, and algorithm getters all live in Rust ext/crypto/00_crypto.js67-70
Key Storage: The actual key material is stored in RawKeyData ext/crypto/shared.rs85-97 which owns its bytes in Rust rather than borrowing from JavaScript. This allows the key material to live in Rust—held alive by the cppgc handle—instead of being passed back and forth to JavaScript ext/crypto/shared.rs70-76
Key Construction: Keys are minted via cppgc instances. Structured-clone resurrection is handled by CryptoKey.fromCloneData(data) which parses snapshots back into freshly-minted instances ext/crypto/00_crypto.js100-109
Properties:
type: Read-only, returns KeyType ("secret", "private", "public") ext/crypto/lib.rs248-252extractable: Read-only boolean.algorithm: Returns the algorithm used to generate or import the key.usages: Returns an array of allowed operations.Sources: ext/crypto/00_crypto.js67-109 ext/crypto/shared.rs70-97 ext/crypto/lib.rs248-252
The SubtleCrypto class ext/crypto/00_crypto.js530-1233 provides methods for cryptographic operations. Deno uses makeAsyncForwarder to ensure methods like importKey and unwrapKey return Promises even when the underlying Rust implementation runs synchronously ext/crypto/00_crypto.js144-162
Method Categories:
| Category | Methods | Purpose |
|---|---|---|
| Digest | digest() | Hash data |
| Encryption | encrypt(), decrypt() | Symmetric/asymmetric encryption |
| Signatures | sign(), verify() | Create and verify signatures |
| Key Management | generateKey(), importKey(), exportKey() | Key lifecycle |
| Key Derivation | deriveBits(), deriveKey() | Derive keys from base material |
| Key Wrapping | wrapKey(), unwrapKey() | Wrap keys for transport |
Sources: ext/crypto/00_crypto.js144-178 ext/crypto/00_crypto.js530-1233
The digest() method computes cryptographic hashes. It delegates to Rust per-algorithm helpers.
Supported Hash Algorithms: SHA-1, SHA-256, SHA-384, SHA-512, SHA3-256, SHA3-384, SHA3-512 ext/crypto/shared.rs27-42
The Rust implementation uses crates like sha2 and sha3 ext/crypto/lib.rs39-45
Sources: ext/crypto/shared.rs27-42 ext/crypto/lib.rs39-45
Encryption and decryption are implemented in ext/crypto/encrypt.rs and ext/crypto/decrypt.rs.
Supported Algorithms:
rsa crate with configurable hash functions ext/crypto/encrypt.rs74-127cbc and aes crates with PKCS#7 padding ext/crypto/encrypt.rs129-164aes-gcm crate with support for 12 or 16 byte IVs ext/crypto/encrypt.rs202-231AES-GCM Encryption Flow:
subtle.encrypt().RawKeyData.encrypt_aes_gcm extracts the secret key ext/crypto/encrypt.rs210encrypt_aes_gcm_general performs the operation using encrypt_in_place_detached ext/crypto/encrypt.rs172-200tag_length and appended to the ciphertext ext/crypto/encrypt.rs233-235Sources: ext/crypto/encrypt.rs74-235 ext/crypto/decrypt.rs1-156
Signing and verification support RSA, ECDSA, HMAC, and Ed25519.
Ed25519 Implementation:
ed25519_sign_into uses Ed25519KeyPair::from_seed_unchecked and signs the data ext/crypto/ed25519.rs42-53ed25519_verify uses aws_lc_rs::signature::UnparsedPublicKey ext/crypto/ed25519.rs57-68ECDSA Implementation:
Uses p256, p384, and p521 crates for curve-specific operations ext/crypto/lib.rs13-23
Sources: ext/crypto/ed25519.rs42-68 ext/crypto/lib.rs13-23
Keys are generated in Rust and returned as raw bytes to be wrapped in a CryptoKey.
RSA Generation:
generate_rsa validates the public exponent (allowing only 3 and 65537) ext/crypto/generate_key.rs44-47 and uses RsaPrivateKey::new_with_exp ext/crypto/generate_key.rs89-91
HMAC Generation:
generate_hmac defaults the key length to the hash's block size if not provided ext/crypto/generate_key.rs144-183
Sources: ext/crypto/generate_key.rs44-91 ext/crypto/generate_key.rs144-183
importKey() supports multiple formats: raw, pkcs8, spki, and jwk.
Import Process:
KeyDataWire is received from JavaScript and converted to KeyData ext/crypto/import_key.rs166-199op_crypto_import_key_inner dispatches to algorithm-specific importers like import_key_rsassa or import_key_ec ext/crypto/import_key.rs245-254JWK RSA Import:
Parses n, e, d, p, q, dp, dq, qi from the JWK structure ext/crypto/import_key.rs104-113
Sources: ext/crypto/import_key.rs104-113 ext/crypto/import_key.rs166-254
exportKey() converts RawKeyData back into the requested format.
RSA Export:
SubjectPublicKeyInfo structure with the OID 1.2.840.113549.1.1.1 ext/crypto/export_key.rs155-172PrivateKeyInfo structure ext/crypto/export_key.rs174-204uint_to_b64 ext/crypto/export_key.rs206-230Sources: ext/crypto/export_key.rs155-230
Deno implements Curve25519 (X25519) and Curve448 (X448) for key derivation.
X25519:
x25519_dalek for the Montgomery ladder ext/crypto/x25519.rs33x25519_derive_bits computes the shared secret and checks for the Montgomery identity (low-order point) to prevent attacks ext/crypto/x25519.rs51-65X448:
Sources: ext/crypto/x25519.rs33-65 ext/crypto/x448.rs34-42
Deno defines a comprehensive CryptoError enum that maps Rust errors to WebIDL exceptions ext/crypto/lib.rs137-236
| Rust Error | DOMException Class |
|---|---|
EncryptionError | DOMExceptionOperationError |
DecryptionError | DOMExceptionOperationError |
ArrayBufferViewLengthExceeded | DOMExceptionQuotaExceededError |
TypedArrayNotInteger | DOMExceptionTypeMismatchError |
UnsupportedDigestAlgorithm | DOMExceptionNotSupportedError |
Sources: ext/crypto/lib.rs137-236