🔧 AI Nachrichten Major AI platforms go down in unprecedented simultaneous outage(03.09.2026 um 17:34 Uhr)
🔧 AI Nachrichten ChatGPT, Claude, and Grok Down? Users Report Widespread Outages(03.09.2026 um 19:14 Uhr)
🔧 AI Nachrichten OpenAI Launches GPT-6 Astra, Says We May Have Entered the AGI Era(03.09.2026 um 22:08 Uhr)
🔧 AI Nachrichten Claude Comes to CarPlay as Fifth Major AI Chatbot App(05.09.2026 um 05:31 Uhr)
🔧 AI Nachrichten OpenAI’s GPT-6 Astra Is AGI, Says NVIDIA CEO Jensen Huang(07.09.2026 um 06:31 Uhr)
🔧 AI Nachrichten Blame AI companies for Mac mini and Mac Studio shortage(31.08.2026 um 10:32 Uhr)
🔧 AI Nachrichten Major AI platforms go down in unprecedented simultaneous outage(03.09.2026 um 17:34 Uhr)
🔧 AI Nachrichten ChatGPT, Claude, and Grok Down? Users Report Widespread Outages(03.09.2026 um 19:14 Uhr)
🔧 AI Nachrichten OpenAI Launches GPT-6 Astra, Says We May Have Entered the AGI Era(03.09.2026 um 22:08 Uhr)
🔧 AI Nachrichten Claude Comes to CarPlay as Fifth Major AI Chatbot App(05.09.2026 um 05:31 Uhr)
🔧 AI Nachrichten OpenAI’s GPT-6 Astra Is AGI, Says NVIDIA CEO Jensen Huang(07.09.2026 um 06:31 Uhr)
🔧 AI Nachrichten Blame AI companies for Mac mini and Mac Studio shortage(31.08.2026 um 10:32 Uhr)

🔧 Programmierung 🕛 kürzlich 4 Min Lesezeit
0

Building an AES encrypt/decrypt tool with nothing but the Web Crypto API

↗ Quelle (dev.to)
🗣️ Stimme:
📑 Inhaltsübersicht




What this is



that does AES-GCM/AES-CBC encryption and decryption entirely in the browser.



No CryptoJS, no external crypto library — just the browser's native SubtleCrypto (Web Crypto API). Here's how it's built.






Why avoid a crypto library




  • Keeps the tool's shipped bundle small


  • SubtleCrypto is a native implementation — faster and more auditable than a pure-JS crypto library

  • Fewer dependencies, less to maintain



The tradeoff: SubtleCrypto is a low-level API. Deriving a key from a user-supplied passphrase, and managing salt/IV, is on you.






Deriving a key from a passphrase (PBKDF2)



Users type a passphrase, not a raw AES key, so the tool derives one with PBKDF2:




CODE
const PBKDF2_ITERATIONS = 100_000;

async function deriveKey(
passphrase: string,
salt: Uint8Array,
algorithm: AesAlgorithm,
keySize: AesKeySize,
): Promise<CryptoKey> {
const enc = new TextEncoder();
const baseKey = await crypto.subtle.importKey(
"raw",
enc.encode(passphrase),
"PBKDF2",
false,
["deriveKey"],
);
return crypto.subtle.deriveKey(
{ name: "PBKDF2", salt, iterations: PBKDF2_ITERATIONS, hash: "SHA-256" },
baseKey,
{ name: algorithm, length: keySize },
false,
["encrypt", "decrypt"],
);
}






This is a two-step dance:





  1. importKey("raw", ..., "PBKDF2", ...) treats the passphrase as PBKDF2 key material


  2. deriveKey(...) actually derives the AES key from it



100,000 SHA-256 iterations. Since everything runs client-side and shouldn't freeze the UI, that number is a deliberate tradeoff between security and how long the browser blocks on the calculation.






A self-contained format: salt and IV travel with the ciphertext



Reusing the same key+IV pair for AES is dangerous, so a fresh salt and IV are generated on every encryption. Since decryption needs both, they're packed into one byte array together with the ciphertext and Base64-encoded:




CODE
export async function aesEncrypt(
plaintext: string,
passphrase: string,
opts: AesOptions,
): Promise<AesEncryptResult> {
const salt = crypto.getRandomValues(new Uint8Array(SALT_LENGTH));
const iv = crypto.getRandomValues(new Uint8Array(ivLengthFor(opts.algorithm)));
const key = await deriveKey(passphrase, salt, opts.algorithm, opts.keySize);

const cipherBuffer = await crypto.subtle.encrypt(
opts.algorithm === "AES-GCM"
? { name: "AES-GCM", iv }
: { name: "AES-CBC", iv },
key,
new TextEncoder().encode(plaintext),
);
const ciphertext = new Uint8Array(cipherBuffer);

const header = new Uint8Array([algoToByte(opts.algorithm), opts.keySize / 8]);
const combined = new Uint8Array(
HEADER_LENGTH + salt.length + iv.length + ciphertext.length,
);
combined.set(header, 0);
combined.set(salt, HEADER_LENGTH);
combined.set(iv, HEADER_LENGTH + salt.length);
combined.set(ciphertext, HEADER_LENGTH + salt.length + iv.length);

return { combined: uint8ToBase64(combined), /* ...hex breakdown for display */ };
}






The binary layout:




CODE
[algorithm byte] [keySize/8 byte] [salt (16 bytes)] [IV (12 or 16 bytes)] [ciphertext]






Encoding the algorithm and key size into the first two bytes means decryption can figure out AES-GCM vs. AES-CBC, and the 128/192/256-bit key size, straight from the ciphertext itself. So the person decrypting only ever needs to type the passphrase — no separate dropdown for algorithm or key size on the decrypt side. Small implementation detail, but it keeps the UI simpler.






Decryption gets tamper detection for free






CODE
export async function aesDecrypt(
combinedBase64: string,
passphrase: string,
): Promise<string> {
const combined = base64ToUint8(combinedBase64.trim());
const algorithm = byteToAlgo(combined[0]);
const keySize = (combined[1] * 8) as AesKeySize;
// ... slice out salt, iv, ciphertext

const key = await deriveKey(passphrase, salt, algorithm, keySize);

// Wrong passphrase or corrupted data both just throw here
// (AES-GCM's auth tag verification doubles as tamper detection)
const plainBuffer = await crypto.subtle.decrypt(
algorithm === "AES-GCM" ? { name: "AES-GCM", iv } : { name: "AES-CBC", iv },
key,
ciphertext,
);
return new TextDecoder().decode(plainBuffer);
}






AES-GCM is an AEAD cipher — it appends an authentication tag to the ciphertext. That means a wrong passphrase, corrupted data, or tampering all just cause crypto.subtle.decrypt to throw, with no custom integrity-check code needed. This is probably the single best argument for reaching for SubtleCrypto directly instead of a higher-level wrapper library: the primitives already do the hard part.






One caveat: not designed for interop



This format is intentionally self-contained — built so the tool can decrypt what it encrypted — not designed to be binary-compatible with external tools like OpenSSL. Pasting output from openssl enc -aes-256-cbc into this tool won't decrypt (the header format differs). It's built for one specific use case: encrypt and decrypt entirely in the browser, nothing more.






Wrap-up



The Web Crypto API is low-level enough that you have to think through key derivation and your own wire format, but in exchange you get fine-grained control over exactly what's happening, with fewer dependencies to trust. Hopefully useful if you're building something similar.



Try it here: https://tools.torinoa.com/tools/aes-encrypt-decrypt/

Vollständiger Original-Bericht
Ausführliche Details, Code-Beispiele & Hersteller-Stellungnahme auf dev.to.
↗ Original-Artikel auf dev.to lesen
Wie bewertest du diesen Beitrag?
1 Klick Feedback
Teilen mit Netzwerk & Team:

Community-Analysen & Experten-Meinungen 0

Verfasse deine eigene Analyse, teile Workarounds oder diskutiere diesen Vorfall im Blog.
Noch keine Community-Analyse verfasst. Markiere einen Textabschnitt oder klicke oben auf Eigene Analyse verfassen“!
Community Pulse: Relevanz-Einschätzung
1 Klick Experten-Votum
🔴 Akute Relevanz 0%
🟡 In Evaluierung 0%
🟢 Keine Auswirkung 0%
Spannende Innovation 0%
Verwandte Story-Cluster & Quellen (Vektor-KI)
Port 8095 Engine
3 Quellen
GPT-6 Astra Release Today? OpenAI’s Next Major AI Model Is Almost Here
1 Quelle
Apple accuses OpenAI of destroying evidence as trade-secrets fight intensifies
1 Quelle
Major AI platforms go down in unprecedented simultaneous outage
Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten Building an AES encrypt/decrypt tool with nothing but the Web Crypto API

Thematisch verwandte Begriffe: Building, encryptdecrypt, tool, with · 6 Treffer

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...