
AES256 Encryption in JavaScript
Java ScriptHi, I’m Lovefield.
In web development, there are times when you need to securely transmit sensitive user information. When sending important data to the server, it's crucial to encrypt the data to prevent it from being intercepted or tampered with along the way. In this post, we'll explore how to encrypt and decrypt data using the AES256 algorithm through the window.crypto API in a TypeScript environment.
What is AES256 Encryption?
AES (Advanced Encryption Standard) is one of the most widely used symmetric key encryption algorithms today. The term "symmetric key" means the same key is used for both encryption and decryption. AES supports various key lengths, and AES256 specifically uses a 256-bit key, offering an exceptionally high level of security. Due to its strength, even modern computing power would require an enormous amount of time and resources to break it, making it one of the most trusted encryption standards today.
What is the window.crypto API?
window.crypto is a JavaScript API provided by web browsers for handling cryptographic operations securely. It supports tasks like generating random numbers, encrypting/decrypting data, and creating digital signatures. In particular, the crypto.subtle interface offers low-level cryptographic operations, including support for algorithms like AES.
Encryption Function
TypeScript
async function encodeAESValue(value:string) : string {
if(window.crypto !== undefined){
const key: string = ""; // Fixed 32-byte key
const iv: string = ""; // Fixed 16-byte IV
const keyData = new TextEncoder().encode(key);
const ivData = new TextEncoder().encode(iv);
const importKey = await crypto.subtle.importKey("raw", keyData, { name: "AES-CBC" }, false, ["encrypt"]);
const textData = new TextEncoder().encode(value);
const encrypted = await crypto.subtle.encrypt({ name: "AES-CBC", iv: ivData }, importKey, textData);
return btoa(String.fromCharCode(...new Uint8Array(encrypted)));
}else{
throw new Error(“Not Supported”);
}
}
Explanation
- if (window.crypto !== undefined): Checks if the crypto API is supported.
- new TextEncoder(): Encodes the key and IV into Uint8Array format.
- await crypto.subtle.importKey: Imports the encryption key.
- "raw": Specifies the format of the key data.
- name: "AES-CBC": Specifies the algorithm and mode (CBC - Cipher Block Chaining).
- ["encrypt"]: Restricts key usage to encryption only. - new TextEncoder().encode(value): Encodes the input string into a Uint8Array.
- await crypto.subtle.encrypt: Performs the actual encryption.
- btoa(String.fromCharCode(...new Uint8Array(encrypted))): Converts the encrypted ArrayBuffer into a Base64 string.
Decryption Function
TypeScript
async function decodeAESValue(value:string) : string {
if(window.crypto !== undefined){
const key: string = ""; // Fixed 32-byte key
const iv: string = ""; // Fixed 16-byte IV
const keyData = new TextEncoder().encode(key);
const ivData = new TextEncoder().encode(iv);
const importKey = await crypto.subtle.importKey("raw", keyData, { name: "AES-CBC" }, false, ["decrypt"]);
const textData = base64ToUint8Array(value);
const encrypted = await crypto.subtle.decrypt({ name: "AES-CBC", iv: ivData }, importKey, textData);
const decryptedBytes = new Uint8Array(decrypted);
return new TextDecoder().decode(decryptedBytes);
}else{
throw new Error(“Not Supported”);
}
}
Explanation
- if (window.crypto !== undefined): Checks if the crypto API is supported.
- new TextEncoder().encode(key), new TextEncoder().encode(iv): Encodes the key and IV into Uint8Array format.
- crypto.subtle.importKey("raw", keyData, { name: "AES-CBC" }, false, ["decrypt"]): Imports the decryption key.
- base64ToUint8Array(value): Converts the Base64-encoded string back into a Uint8Array.
- crypto.subtle.decrypt({ name: "AES-CBC", iv: ivData }, importKey, textData): Decrypts the encrypted data.
- new TextDecoder().decode(decryptedBytes): Converts the decrypted binary data back into a readable string.
Helper Function: Convert Base64 to Uint8Array
When decrypting, you need to convert the Base64-encoded string back into binary data. Here's a simple helper function to do that:
TypeScript
function base64ToUint8Array(base64: string): Uint8Array {
const binary = atob(base64);
const bytes = new Uint8Array(binary.length);
for (let i = 0; i < binary.length; i += 1) {
bytes[i] = binary.charCodeAt(i);
}
return bytes;
}
In this post, we learned how to use the window.crypto and crypto.subtle APIs in a TypeScript environment to implement AES256 encryption and decryption.
Using this method, you can securely transmit sensitive user data, which is especially critical for features like login, payment, or personal information input.
Since the crypto API is built into modern browsers, you can apply strong encryption without relying on third-party libraries, ensuring both simplicity and efficiency. However, keep in mind that using fixed keys and IVs can pose security risks in real-world applications. For stronger security, it's recommended to generate keys dynamically, rotate them periodically, and manage them over secure channels. Encryption is fundamental to data security. Apply these techniques to build safer and more reliable web services! Thank you for reading.