Key derivation steps
- Generate a 16 byte salt with
crypto.getRandomValues. - Feed the password and salt into PBKDF2 with SHA-256.
- Run 100,000 iterations to slow down offline cracking attempts.
- Import the derived bytes as a 256-bit AES key.
Encrypt or decrypt text locally using AES-GCM or AES-CBC with PBKDF2 and SHA-256 derived keys.
Tokens follow the format mode.salt.iv.ciphertext using Base64 components.
AES-GCM is an authenticated encryption mode: it encrypts data while calculating an integrity tag that proves the ciphertext has not been tampered with. HashyTools derives the AES key from your password using PBKDF2 with SHA-256 so human phrases gain the entropy they need to resist brute-force attacks.
crypto.getRandomValues.Both modes secure data when implemented correctly, but they carry different requirements. Use the matrix below to pick the mode that aligns with your interoperability and security constraints.
| Characteristic | AES-GCM | AES-CBC |
|---|---|---|
| Integrity protection | Built-in authentication tag. Detects tampering automatically. | Requires separate HMAC to verify authenticity. |
| Performance | Fast and parallelizable on modern CPUs with AES-NI. | Sequential; cannot be parallelized across blocks. |
| Nonce/IV requirements | Must never reuse the same IV with the same key. | IV must be unpredictable, but reuse has less catastrophic impact. |
| Interoperability | Supported in modern browsers, APIs, TLS 1.3, and WebCrypto. | Common in legacy stacks, older TLS versions, and hardware HSMs. |
Encrypting data locally prevents sensitive information from touching third-party servers. These scenarios highlight when the tool is especially helpful.
Encrypt API keys or environment variables before dropping them into chat or ticketing tools. Recipients decrypt locally with the agreed password.
Protect notes or configuration files before persisting them in localStorage or IndexedDB so accidental leaks reveal only ciphertext.
Generate reference ciphertext for automation tests. The Base64 token encodes every parameter your backend needs to replicate the key schedule.
Follow these guidelines when integrating AES tokens into larger systems.
Do you need interoperability with a specific backend language or framework for your tokens?
async function deriveKey(password, salt) {
const enc = new TextEncoder();
const keyMaterial = await crypto.subtle.importKey('raw', enc.encode(password), 'PBKDF2', false, ['deriveKey']);
return crypto.subtle.deriveKey(
{ name: 'PBKDF2', salt, iterations: 100_000, hash: 'SHA-256' },
keyMaterial,
{ name: 'AES-GCM', length: 256 },
false,
['encrypt', 'decrypt']
);
}
async function encryptText(password, plaintext) {
const enc = new TextEncoder();
const salt = crypto.getRandomValues(new Uint8Array(16));
const iv = crypto.getRandomValues(new Uint8Array(12));
const key = await deriveKey(password, salt);
const cipher = await crypto.subtle.encrypt({ name: 'AES-GCM', iv }, key, enc.encode(plaintext));
return [
'gcm',
btoa(String.fromCharCode(...salt)),
btoa(String.fromCharCode(...iv)),
btoa(String.fromCharCode(...new Uint8Array(cipher)))
].join('.');
}
from base64 import b64encode, b64decode
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
import os
def encrypt_text(password: str, plaintext: str) -> str:
salt = os.urandom(16)
iv = os.urandom(12)
kdf = PBKDF2HMAC(algorithm=hashes.SHA256(), length=32, salt=salt, iterations=100_000)
key = kdf.derive(password.encode('utf-8'))
aesgcm = AESGCM(key)
cipher = aesgcm.encrypt(iv, plaintext.encode('utf-8'), associated_data=None)
return 'gcm.' + '.'.join(
b64encode(part).decode('ascii') for part in (salt, iv, cipher)
)
AES-GCM provides authenticated encryption, combining confidentiality with integrity tags so tampering is detected before decryption. It is efficient and well supported in modern runtimes.
PBKDF2 stretches low-entropy passwords into strong 256-bit AES keys using a unique salt and thousands of SHA-256 iterations, raising the cost of offline attacks.
Choose AES-CBC only when interoperating with older systems that cannot handle GCM. Always pair CBC with an HMAC so you can detect modification attacks.
The token embeds the mode, salt, IV, and ciphertext as Base64 segments. Anyone with the password can recompute the derived key, apply the IV, and recover the plaintext.
No. All encryption and decryption happens locally via the Web Crypto API—your plaintext and passwords never leave the browser.