This commit is contained in:
Tyler
2025-05-01 18:46:29 -10:00
committed by GitHub
parent 766386501b
commit 7ec213fad0
18 changed files with 1321 additions and 659 deletions
+29 -11
View File
@@ -1,10 +1,21 @@
// encryption.js
/**
* Encryption module.
* Handles cryptographic operations using Web Crypto API.
* Implements AES-GCM encryption with PBKDF2 key derivation.
*/
// ===== Constants =====
const SALT_LENGTH = 16;
const IV_LENGTH = 12;
const PBKDF2_ITERATIONS = 200_000;
const KEY_LENGTH = 256;
// ===== Key Derivation =====
/**
* Derives an AES-GCM key from a password using PBKDF2.
* @param {string} password - User-supplied password.
* @param {Uint8Array} salt - Randomly generated salt.
* @returns {Promise<CryptoKey>}
* @returns {Promise<CryptoKey>} - Derived cryptographic key.
*/
export async function deriveKey(password, salt) {
const encoder = new TextEncoder();
@@ -20,16 +31,17 @@ export async function deriveKey(password, salt) {
{
name: 'PBKDF2',
salt,
iterations: 200_000,
iterations: PBKDF2_ITERATIONS,
hash: 'SHA-256'
},
keyMaterial,
{ name: 'AES-GCM', length: 256 },
{ name: 'AES-GCM', length: KEY_LENGTH },
false,
['encrypt', 'decrypt']
);
}
// ===== Encryption =====
/**
* Encrypts a message using AES-GCM with a derived key.
* @param {string} message - Plaintext message to encrypt.
@@ -38,12 +50,16 @@ export async function deriveKey(password, salt) {
*/
export async function encryptAdvanced(message, password) {
const encoder = new TextEncoder();
const salt = crypto.getRandomValues(new Uint8Array(16));
const iv = crypto.getRandomValues(new Uint8Array(12));
const salt = crypto.getRandomValues(new Uint8Array(SALT_LENGTH));
const iv = crypto.getRandomValues(new Uint8Array(IV_LENGTH));
const key = await deriveKey(password, salt);
const encoded = encoder.encode(message);
const ciphertext = await crypto.subtle.encrypt({ name: 'AES-GCM', iv }, key, encoded);
const ciphertext = await crypto.subtle.encrypt(
{ name: 'AES-GCM', iv },
key,
encoded
);
const output = new Uint8Array(salt.length + iv.length + ciphertext.byteLength);
output.set(salt);
@@ -53,6 +69,7 @@ export async function encryptAdvanced(message, password) {
return btoa(String.fromCharCode(...output));
}
// ===== Decryption =====
/**
* Decrypts an AES-GCM encrypted string.
* @param {string} encryptedData - Base64-encoded ciphertext.
@@ -64,9 +81,9 @@ export async function decryptAdvanced(encryptedData, password) {
atob(encryptedData).split('').map(c => c.charCodeAt(0))
);
const salt = encrypted.slice(0, 16);
const iv = encrypted.slice(16, 28);
const ciphertext = encrypted.slice(28);
const salt = encrypted.slice(0, SALT_LENGTH);
const iv = encrypted.slice(SALT_LENGTH, SALT_LENGTH + IV_LENGTH);
const ciphertext = encrypted.slice(SALT_LENGTH + IV_LENGTH);
const key = await deriveKey(password, salt);
const decrypted = await crypto.subtle.decrypt(
@@ -78,8 +95,9 @@ export async function decryptAdvanced(encryptedData, password) {
return new TextDecoder().decode(decrypted);
}
// ===== Module Initialization =====
/**
* Optional init logging for module diagnostics.
* Initializes the encryption module and logs its status.
*/
export function setupEncryption() {
console.log('[Encryption] Module loaded');