Web Crypto API: Building Browser-Side Encryption
The Web Crypto API is a browser-native JavaScript API that provides cryptographic operations without any external libraries. It enables hardware-accelerated encryption, key generation, and hashing directly in the browser. Here's a practical guide for developers building privacy-focused applications.
Why Web Crypto API?
- No external dependencies β Built into all modern browsers (Chrome, Firefox, Safari, Edge)
- Hardware acceleration β Uses the CPU's AES-NI instruction set for fast encryption
- Secure random number generation β
crypto.getRandomValues()uses the OS's CSPRNG - Async design β Non-blocking operations via Promises
- Key isolation β Non-extractable keys never leave the browser's crypto subsystem
Core Operations
1. Generating Random Values
// Generate a random 96-bit IV for AES-GCM
const iv = crypto.getRandomValues(new Uint8Array(12));
// Generate a random 256-bit value
const randomBytes = crypto.getRandomValues(new Uint8Array(32));
2. Generating an AES-256-GCM Key
const key = await crypto.subtle.generateKey(
{ name: "AES-GCM", length: 256 },
true, // extractable (set false for maximum security)
["encrypt", "decrypt"]
);
3. Encrypting Data
const encoder = new TextEncoder();
const data = encoder.encode("my secret message");
const iv = crypto.getRandomValues(new Uint8Array(12));
const ciphertext = await crypto.subtle.encrypt(
{
name: "AES-GCM",
iv: iv,
additionalData: encoder.encode("context-binding-data"),
tagLength: 128
},
key,
data
);
4. Decrypting Data
const plaintext = await crypto.subtle.decrypt(
{
name: "AES-GCM",
iv: iv,
additionalData: encoder.encode("context-binding-data"),
tagLength: 128
},
key,
ciphertext
);
const decoded = new TextDecoder().decode(plaintext);
5. Key Derivation with HKDF
// Import raw key material for HKDF
const keyMaterial = await crypto.subtle.importKey(
"raw",
masterKeyBytes,
{ name: "HKDF" },
false,
["deriveKey"]
);
// Derive a per-message AES-256 key
const derivedKey = await crypto.subtle.deriveKey(
{
name: "HKDF",
hash: "SHA-256",
salt: saltBytes,
info: new TextEncoder().encode(messageId)
},
keyMaterial,
{ name: "AES-GCM", length: 256 },
false,
["encrypt", "decrypt"]
);
6. Exporting and Importing Keys
// Export to share (e.g., in a URL fragment)
const rawKey = await crypto.subtle.exportKey("raw", key);
const keyString = btoa(String.fromCharCode(...new Uint8Array(rawKey)));
// Import from shared key material
const importedKey = await crypto.subtle.importKey(
"raw",
keyBytes,
{ name: "AES-GCM", length: 256 },
false,
["decrypt"]
);
Building a Zero-Knowledge Architecture
The Web Crypto API makes it straightforward to build zero-knowledge systems. The key design pattern used by Only Once Share:
- Generate a key in the browser
- Encrypt data client-side
- Send only ciphertext to the server
- Put the key in the URL fragment (
#), which browsers never send to servers - The recipient's browser reads the key from the fragment and decrypts
Common Mistakes
- Using
Math.random()for cryptographic purposes β Always usecrypto.getRandomValues() - Reusing IVs β Generate a fresh random IV for every encryption operation
- Putting keys in URL paths β Use URL fragments (
#), not paths or query parameters, for keys - Ignoring AAD β Always use Additional Authenticated Data to bind context to ciphertext
- Using extractable keys unnecessarily β Set
extractable: falseunless you need to export the key
Browser Support
The Web Crypto API is supported in all modern browsers: Chrome 37+, Firefox 34+, Safari 11+, Edge 12+. For older browsers, consider a fallback to a JavaScript implementation like asmcrypto.js, though this should be rare in 2025.
Conclusion
The Web Crypto API provides everything you need to build secure, privacy-first applications without external crypto libraries. For zero-knowledge architectures like secret sharing tools, it enables client-side AES-256-GCM encryption with hardware acceleration, HKDF key derivation, and secure random number generation β all natively in the browser.
Share secrets securely β for free
Only Once Share uses AES-256-GCM encryption with zero-knowledge architecture. No account required.
Try Only Once Share