Glossary

crypto.subtle

crypto.subtle is the property that returns a SubtleCrypto object, the low-level toolbox of the Web Crypto API for hashing, signing, encrypting and managing keys. It is defined by the W3C Web Cryptography specification and is exposed only in secure contexts, meaning HTTPS or localhost. Every method returns a Promise, and the work runs outside your JavaScript code.

How it works

SubtleCrypto has these methods: digest, encrypt, decrypt, sign, verify, generateKey, deriveKey, deriveBits, importKey, exportKey, wrapKey and unwrapKey. You name the algorithm with a string or an object such as { name: "AES-GCM", iv }. Keys are opaque CryptoKey objects, and you choose at creation whether they are extractable.

  • digest accepts SHA-1, SHA-256, SHA-384 and SHA-512 and returns an ArrayBuffer. A SHA-256 digest is always 32 bytes. MD5 is not available.
  • encrypt and decrypt with AES-GCM take an initialization vector in the parameters. The authentication tag is 128 bits by default and is appended to the ciphertext, so the output is 16 bytes longer than the input.
  • Input must be bytes, not strings. Use TextEncoder to convert text and TextDecoder to read results back.
const enc = new TextEncoder();
const d = await crypto.subtle.digest('SHA-256', enc.encode('hello'));
console.log(Buffer.from(d).toString('hex'), d.byteLength);

const key = await crypto.subtle.generateKey({ name: 'AES-GCM', length: 256 }, true, ['encrypt', 'decrypt']);
const iv = crypto.getRandomValues(new Uint8Array(12));
const ct = await crypto.subtle.encrypt({ name: 'AES-GCM', iv }, key, enc.encode('hello'));
console.log(ct.byteLength);
console.log(new TextDecoder().decode(await crypto.subtle.decrypt({ name: 'AES-GCM', iv }, key, ct)));

const bad = new Uint8Array(ct); bad[0] ^= 1;
try { await crypto.subtle.decrypt({ name: 'AES-GCM', iv }, key, bad); } catch (e) { console.log(e.name, '|', e.message); }
try { await crypto.subtle.digest('MD5', enc.encode('x')); } catch (e) { console.log(e.name, '|', e.message); }

Output from Node.js 22.22.0 (the ES module top-level await form, where Buffer is only used to print hex):

2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824 32
21
hello
OperationError | The operation failed for an operation-specific reason
NotSupportedError | Unrecognized algorithm name

Why is crypto.subtle undefined?

It is undefined because the page is not a secure context. Browsers hide subtle on plain http: pages, except on localhost. Serve the page over HTTPS to fix it. Test with window.isSecureContext, which is false in that case. Node.js has crypto.subtle without that restriction.

How do you get a SHA-256 hash in the browser?

Call crypto.subtle.digest('SHA-256', bytes) and convert the returned ArrayBuffer to hex yourself. There is no built-in hex helper, so map each byte to a two-digit hex string. Hash Generator on this site does the same for pasted text.

Common pitfalls

  • Reusing an AES-GCM IV with the same key: this breaks the security of GCM. Generate a fresh 12-byte value with crypto.getRandomValues for every message and store it next to the ciphertext. RFC 5116 fixes the GCM nonce at 12 octets.
  • Passing a string: digest and encrypt reject strings with a TypeError. Encode with TextEncoder first.
  • Ignoring OperationError on decrypt: it means the key, IV or data is wrong, or the data was changed. The browser gives no further detail by design.
  • Using SHA-1 or a bare hash for passwords: a fast digest is the wrong tool. Derive keys with PBKDF2 through deriveKey and a high iteration count.
  • Forgetting that it is asynchronous: the methods return a Promise, so await them or the result is a pending object.
  • Hex mix-ups: printing the ArrayBuffer directly shows nothing useful. Wrap it in Uint8Array first.

Related terms

  • crypto.getRandomValues — fills typed arrays with secure random bytes, used for IVs and salts
  • SHA-256 — the digest most code asks digest for
  • HMAC — available through sign and verify with the HMAC algorithm
  • AES — the cipher behind the AES-GCM and AES-CBC modes
  • Promise — the type every SubtleCrypto method returns

See also

  • Tool: Hash Generator — creates MD5, SHA-1, SHA-256 and SHA-512 hashes from text
  • Tool: AES Encrypt / Decrypt — encrypts and decrypts text with AES-256 in CBC and GCM modes