Quick wins for a faster PC:
Scan for outdated or missing drivers - takes under a minuteDriver Scan →Clear out junk files and repair common Windows errorsFree Scan →Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Client-side encryption uses the browser to turn readable data into ciphertext before it reaches a server or storage provider. The Web Crypto API—exposed through window.crypto.subtle and workers—supplies the primitives, but it does not design a secure product for you. A sound implementation needs a threat model, authenticated encryption, careful key storage, recovery procedures, and controls for the JavaScript that performs the work.
For most application data, use a randomly generated AES-GCM key and a fresh IV for every encryption. Use RSA-OAEP only for short secrets such as wrapping a symmetric key; a 2048-bit RSA-OAEP key using SHA-256 can encrypt at most 190 bytes in MDN Web Docs’ concrete example. Treat the API as a low-level building block, not as a complete security system.
As an Amazon Associate I earn from qualifying purchases.
What client-side encryption protects—and what it cannot
In a client-side encryption design, plaintext exists in the browser, is encrypted there, and only ciphertext is uploaded. This can reduce the impact of a database breach, an untrusted storage service, or an intermediary that should not see document contents. The server may still store account identifiers, ciphertext, timestamps, key identifiers, and other metadata.
Write the threat model before choosing an algorithm. Ask exactly which party must be unable to read the data:
#1 Best Overall
- Storage or database compromise: encryption helps when attackers obtain stored ciphertext but not the decryption key.
- Curious service operators: the service cannot decrypt data if keys remain under the user’s control and the application never sends them to the service.
- Compromised browser delivery: encryption does not help if an attacker can modify the JavaScript, inject a dependency, or control an extension. Malicious code can copy plaintext before encryption or after decryption.
- Compromised endpoint: malware, a hostile extension, or an unlocked device can read data while the application is using it.
HTTPS and a secure context protect delivery in transit, but they do not make a compromised origin trustworthy. Content-security policy, dependency pinning, integrity monitoring, short-lived sessions, and an incident-response plan are part of the same system.
MDN Web Docs describes Web Crypto as “a number of low-level cryptographic primitives” and warns that “it’s very easy to misuse them.” It also notes that secure key management and overall security-system design are extremely hard to get right.
Prerequisites and secure-context checks
SubtleCrypto is available only in a secure context, normally an HTTPS origin. It is also available in web workers, which can keep expensive operations away from the user-interface thread. Browser support should be checked against the browsers and versions your application actually supports; do not assume that a feature works identically in every embedded web view.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Fail early and provide a useful message:
if (!window.isSecureContext || !window.crypto?.subtle) {
throw new Error('A secure context with Web Crypto API support is required.');
}
For large files, a worker can perform encryption and report progress through messages. A worker does not change the trust model: it still executes JavaScript delivered by the origin and still has access to plaintext supplied to it.
Choose the primitive for the job
| Property | AES-GCM | RSA-OAEP |
|---|---|---|
| Cryptographic model | Symmetric: the same secret key encrypts and decrypts. | Public-key: a public key encrypts; the private key decrypts. |
| Best use | Bulk data, files, records, and messages. | Short secrets, commonly a symmetric key in a hybrid design. |
| Message size | Suitable for application-sized data, subject to memory and implementation limits. | Limited by the modulus and hash padding. MDN’s 2048-bit/SHA-256 example allows no more than 190 bytes. |
| Integrity | Authenticated encryption; decryption fails when ciphertext, IV, or authenticated metadata is altered. | Provides encryption padding, not a general bulk-data authenticated-encryption mode. Add signatures or an authenticated symmetric layer when authenticity is required. |
| Key distribution | Both sides need the secret, so distribution and recovery are central design problems. | Public keys can be distributed openly, while private-key protection and rotation remain critical. |
| Performance | Efficient for large payloads. | Expensive and unsuitable for encrypting documents directly. |
| Rotation and recovery | Rotate data keys or re-wrap them under a new key; losing the only copy loses the data. | Rotate key pairs and re-wrap stored symmetric keys; retain a controlled recovery path for private keys. |
CTR and CBC are available in Web Crypto but do not authenticate by default. They require a separate, correctly composed integrity mechanism. AES-GCM is generally the safer built-in choice when its nonce requirements are followed.
Implement AES-GCM correctly
1. Generate a key with the narrowest permissions
Generate a 256-bit AES-GCM key for ordinary application data. Set extractable to false unless a documented export or wrapping operation requires otherwise, and grant only the usages you need.
const dataKey = await crypto.subtle.generateKey(
{ name: 'AES-GCM', length: 256 },
false,
['encrypt', 'decrypt']
);
A non-exportable key can still be used by the browser and persisted as a CryptoKey through structured cloning. Non-exportability is a useful barrier, not a guarantee against code that can invoke the key while your page is running.
Recommended Free Tools
2. Create a fresh IV for every encryption
Generate a unique, unpredictable IV (also called a nonce) for each encryption under a given AES-GCM key. A 96-bit IV is the conventional choice. Never reuse an IV with the same key; nonce reuse can reveal relationships between messages and undermine authentication.
const iv = crypto.getRandomValues(new Uint8Array(12));
const encoder = new TextEncoder();
const plaintext = encoder.encode('Sensitive text');
const ciphertext = await crypto.subtle.encrypt(
{ name: 'AES-GCM', iv },
dataKey,
plaintext
);
Store the IV beside the ciphertext. It is not secret. If the protocol needs to bind unencrypted context—such as a record identifier, tenant identifier, or envelope version—pass a canonical byte representation as additionalData. The receiver must supply exactly the same bytes during decryption.
const aad = encoder.encode('record:v1:customer-42');
const ciphertext = await crypto.subtle.encrypt(
{ name: 'AES-GCM', iv, additionalData: aad },
dataKey,
plaintext
);
3. Serialize a versioned envelope
Do not store an unexplained blob. Define a stable envelope that allows future migrations and key rotation. Include the algorithm, version, key identifier, IV, ciphertext, and any authenticated-data identifier or parameters. Base64 is convenient for JSON transport, but it increases size; binary formats are reasonable for file storage.
const envelope = {
version: 1,
alg: 'AES-GCM-256',
keyId: 'account-key-2026-01',
iv: toBase64(iv),
aadId: 'record:v1:customer-42',
ciphertext: toBase64(new Uint8Array(ciphertext))
};
Use a tested byte-to-text encoder rather than assuming that arbitrary bytes are UTF-8. The following compact helper is suitable for small values; use a chunked implementation for large files to avoid argument-size limits:
Free tools Windows power users keep installed
One-click scans. No signup required.
function toBase64(bytes) {
return btoa(String.fromCharCode(...bytes));
}
function fromBase64(value) {
return Uint8Array.from(atob(value), character => character.charCodeAt(0));
}
4. Decrypt and authenticate before releasing plaintext
Reconstruct the exact algorithm parameters and associated data from the validated envelope. AES-GCM rejects altered ciphertext, IV, or associated data. Return a generic failure to callers; do not reveal whether a key was wrong, the tag was invalid, or a particular field failed.
async function decryptEnvelope(envelope, key) {
try {
if (envelope.version !== 1 || envelope.alg !== 'AES-GCM-256') {
throw new Error('Unsupported envelope');
}
const iv = fromBase64(envelope.iv);
const ciphertext = fromBase64(envelope.ciphertext);
const aad = new TextEncoder().encode(envelope.aadId);
const bytes = await crypto.subtle.decrypt(
{ name: 'AES-GCM', iv, additionalData: aad },
key,
ciphertext
);
return new TextDecoder().decode(bytes);
} catch {
throw new Error('Unable to verify and decrypt this item.');
}
}
Log only non-sensitive diagnostics such as an internal request identifier, envelope version, and operation type. Never log plaintext, raw keys, IVs together with identifying data, or detailed oracle responses.
Use RSA-OAEP as a key-wrapping layer
RSA-OAEP is a public-key encryption scheme for short inputs. The maximum plaintext is determined by the modulus size and hash function; with a 2048-bit key and SHA-256, MDN documents a 190-byte limit. A document, image, or even a large JSON record will exceed that limit. Encrypt a random AES key instead, then encrypt the data with AES-GCM.
Generate an RSA-OAEP pair
const rsaKeys = await crypto.subtle.generateKey(
{
name: 'RSA-OAEP',
modulusLength: 2048,
publicExponent: new Uint8Array([1, 0, 1]),
hash: 'SHA-256'
},
false,
['wrapKey', 'unwrapKey']
);
Applications that need to export a public key commonly generate the pair with extractable: true and export only the public portion. Keep the private key non-exportable where possible. RSA-OAEP encryption alone does not prove who supplied a public key; authenticate or pin public-key fingerprints through your account or device-enrollment protocol.
Rank #4
Wrap and unwrap a symmetric key
wrapKey requires the wrapped key to be extractable. One practical pattern is to generate a random AES data key as extractable, wrap it immediately with the recipient’s RSA public key, store only the wrapped result, and unwrap it as non-exportable when needed.
const aesKey = await crypto.subtle.generateKey(
{ name: 'AES-GCM', length: 256 },
true,
['encrypt', 'decrypt']
);
const wrapped = await crypto.subtle.wrapKey(
'raw',
aesKey,
rsaKeys.publicKey,
{ name: 'RSA-OAEP' }
);
const unwrapped = await crypto.subtle.unwrapKey(
'raw',
wrapped,
rsaKeys.privateKey,
{ name: 'RSA-OAEP' },
{ name: 'AES-GCM' },
false,
['encrypt', 'decrypt']
);
Destroy references to the original extractable key as soon as the wrapped form is safely stored. A hybrid envelope normally contains the AES-GCM ciphertext and IV plus the RSA-wrapped AES key and the identifier of the recipient public key.
Persist keys without exposing raw key bytes
Structured cloning allows serializable CryptoKey objects to be stored in IndexedDB in browsers that support the relevant API behavior. Store key metadata—identifier, algorithm, creation time, status, and rotation state—in a separate record. Keep the ciphertext envelope and key record transactionally consistent so a successful upload cannot point to a key that was never persisted.
Prefer non-exportable keys. When export or cross-device persistence is unavoidable, use wrapKey and unwrapKey with a separately protected wrapping key rather than writing raw key material to local storage, cookies, logs, or application databases. Local storage is string-based and offers no special protection for secrets against JavaScript running in the same origin.
Decide what happens when IndexedDB is cleared, a user signs out, a device is lost, or a browser profile is reset. If the only decryption key disappears, ciphertext is intentionally unrecoverable. Recovery can involve a second device, a user-held recovery secret, or an organization-controlled escrow key; each option changes the threat model and must be documented.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Derive a key from a password
Passwords are not encryption keys. Use a password-derivation primitive such as PBKDF2 exposed by Web Crypto, a unique random salt, and a work factor selected and reviewed for your application’s devices and threat model. There is no universal value supplied by the API documentation. Store the salt, algorithm version, and work-factor parameters beside the ciphertext, and define how parameters will be increased later.
async function deriveAesKey(password, salt, iterations) {
const material = await crypto.subtle.importKey(
'raw',
new TextEncoder().encode(password),
'PBKDF2',
false,
['deriveKey']
);
return crypto.subtle.deriveKey(
{
name: 'PBKDF2',
salt,
iterations,
hash: 'SHA-256'
},
material,
{ name: 'AES-GCM', length: 256 },
false,
['encrypt', 'decrypt']
);
}
Generate a new salt for each independent password-derived key. A parameter migration usually decrypts with the old parameters and re-encrypts under the new ones after successful authentication. Rate-limit password attempts and avoid revealing whether a password, salt, or envelope component was incorrect.
Key lifecycle, rotation, and access control
Key identifiers and rotation
Give every key an opaque identifier and a status such as active, decrypt-only, revoked, or destroyed. New encryptions use the active key. During rotation, retain the old key for decryption, re-wrap or re-encrypt existing data in controlled batches, then retire it only after verifying coverage. Keep algorithm and envelope versions independent so a format migration does not silently change key ownership.
Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchWindows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallAuthorization is separate from decryption
Possessing a CryptoKey should not be the only authorization check. Enforce account, tenant, document, and device permissions on the server before returning ciphertext or wrapped keys. Client-side checks improve user experience but cannot replace server authorization.
Backups and revocation
Back up encrypted key envelopes and metadata according to the same confidentiality policy as the data. Plan revocation for a stolen device, a removed collaborator, or a compromised private key. Revocation cannot erase plaintext already viewed or copied by an authorized client.
Testing and failure handling
Build tests around protocol properties, not just successful examples:
- Encrypt and decrypt known vectors across every supported browser and between window and worker contexts.
- Verify that changing one ciphertext byte, the IV, authenticated data, algorithm version, or key identifier causes a generic failure.
- Confirm that the application never reuses an IV under one AES-GCM key, including after retries, offline queues, and restored sessions.
- Test malformed JSON, truncated base64, oversized inputs, unsupported envelope versions, wrong keys, deleted IndexedDB records, and interrupted uploads.
- Exercise RSA wrapping and unwrapping, public-key import, private-key rotation, and recovery from a lost key.
- Check that logs, analytics, crash reports, browser history, and clipboard integrations contain no plaintext or key bytes.
- Measure worker responsiveness and memory use for the largest supported files; reject or stream inputs that would exhaust the page.
Use independent code review for cryptographic boundaries. Fuzz envelope parsers, run dependency and content-security checks, and test the exact deployment path that serves JavaScript to users.
The Tool Desk
Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Common mistakes and their fixes
| Mistake | Why it fails | Corrective action |
|---|---|---|
| Encrypting a large file directly with RSA-OAEP | RSA-OAEP has a strict modulus-and-hash-dependent size limit. | Generate an AES-GCM data key, encrypt the file symmetrically, and wrap that key with RSA-OAEP. |
| Reusing an AES-GCM IV | Nonce reuse can compromise confidentiality and authentication. | Generate a fresh 96-bit IV for every operation and store it in the envelope. |
| Using AES-CBC or AES-CTR without authentication | Confidentiality alone does not detect tampering. | Use AES-GCM or add a separately reviewed authenticated construction. |
| Putting raw keys in local storage or logs | Same-origin scripts and diagnostic systems can read them. | Keep keys non-exportable; otherwise wrap them under a separately protected key. |
| Assuming HTTPS defeats malicious JavaScript | A compromised origin can read plaintext in memory. | Harden the delivery chain, dependencies, sessions, and endpoint, and state this limitation to users. |
| Returning detailed decryption errors | Different errors can create an oracle or leak protocol state. | Return one generic integrity/authentication failure and keep sensitive details out of logs. |
| Omitting a recovery plan | Deleted browser storage or a lost device can make ciphertext permanently unreadable. | Design, test, and clearly explain recovery before deployment. |
Deployment checklist
- Document the threat model, trust boundaries, supported browsers, and secure-context requirement.
- Use AES-GCM for bulk data, unique IVs, authenticated metadata where needed, and a versioned envelope.
- Use RSA-OAEP only for short secrets or key wrapping, observing the 190-byte 2048-bit/SHA-256 example limit.
- Generate keys with minimal usages and prefer non-exportable
CryptoKeyobjects. - Persist keys through IndexedDB or wrapped envelopes, never raw key bytes in ordinary application storage.
- Record salts and derivation parameters for password-based keys and define a migration policy.
- Separate cryptographic possession from authorization and enforce permissions server-side.
- Harden JavaScript delivery, dependencies, content-security policy, session handling, and endpoint access.
- Test tampering, nonce reuse, malformed envelopes, rotation, deletion, recovery, workers, and browser interoperability.
- Publish a clear lost-key policy: what can be recovered, by whom, and under which trust assumptions.
The Bottom Line
SubtleCrypto can provide strong browser-side encryption when the design uses AES-GCM with disciplined nonce handling, wraps short-lived symmetric keys when public-key distribution is needed, protects CryptoKey material, and treats JavaScript delivery and recovery as security-critical. The API performs cryptographic operations; your threat model and key lifecycle determine whether the resulting system is actually secure.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

