How AES-256 Encryption Protects Files
A technical review of PBKDF2 key expansion, Galois/Counter Mode (GCM) ciphers, and Web Crypto client integrations.
How AES-256 Encryption Protects Files
Encryption is the core standard of data security. But how does symmetric encryption actually lock and protect a file from unauthorized access?
In this article, we examine AES-256 (Advanced Encryption Standard), key derivation functions, and how the Web Crypto API implements zero-knowledge file encryption.
What is AES-256?
AES is a symmetric-key block cipher adopted by governments and security agencies worldwide. The "256" denotes the length of the key (256 bits), which creates $1.1 imes 10^{77}$ possible key combinations.
Even a supercomputer performing billions of combinations per second would take trillions of years to brute-force a single file.
Galois/Counter Mode (GCM)
FlexiFile implements AES in GCM mode, which provides both:
1. Confidentiality: Scrambles the data so it cannot be read.
2. Authenticity (Integrity): Computes a tag verifying that the encrypted data has not been modified or corrupted in transit.
The Key: PBKDF2 Key Derivation
Passwords entered by users are easy to guess. To secure files against dictionary attacks, we expand passwords using PBKDF2 (Password-Based Key Derivation Function 2):
- We append a random 16-byte value called a salt.
- We hash the combined password and salt 100,000 times using SHA-256.
- This generates a cryptographic key block of 256 bits.
Implementing Web Crypto AES-256
Using the browser's built-in cryptographic engine (window.crypto.subtle), we encrypt file array buffers locally:
async function encryptBuffer(fileBytes: Uint8Array, passwordStr: string) {
// Generate random salt and Initialization Vector (IV)
const salt = window.crypto.getRandomValues(new Uint8Array(16));
const iv = window.crypto.getRandomValues(new Uint8Array(12));
// Import raw password string
const rawKey = await window.crypto.subtle.importKey(
'raw',
new TextEncoder().encode(passwordStr),
{ name: 'PBKDF2' },
false,
['deriveKey']
);
// Expand key using PBKDF2 (100,000 iterations)
const aesKey = await window.crypto.subtle.deriveKey(
{
name: 'PBKDF2',
salt,
iterations: 100000,
hash: 'SHA-256'
},
rawKey,
{ name: 'AES-GCM', length: 256 },
false,
['encrypt']
);
// Encrypt array buffer
const ciphertextBuffer = await window.crypto.subtle.encrypt(
{ name: 'AES-GCM', iv },
aesKey,
fileBytes
);
return { salt, iv, ciphertext: new Uint8Array(ciphertextBuffer) };
}By packaging the salt and IV along with the ciphertext, we construct a secure .enc file. Decryption follows the reverse flow, using the same password and salt to reconstruct the AES key.