Spaces:
Running
Running
File size: 2,527 Bytes
1e2158c | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | // Simple AES-GCM Encryption Utility for Browser WebCrypto API
export class ChatCrypto {
private static async getEncryptionKey(password: string): Promise<CryptoKey> {
const enc = new TextEncoder();
const keyMaterial = await window.crypto.subtle.importKey(
'raw',
enc.encode(password),
{ name: 'PBKDF2' },
false,
['deriveBits', 'deriveKey']
);
return window.crypto.subtle.deriveKey(
{
name: 'PBKDF2',
salt: enc.encode('DataVision_Salt_2026'), // In production, generate a random salt per user/channel
iterations: 100000,
hash: 'SHA-256'
},
keyMaterial,
{ name: 'AES-GCM', length: 256 },
true,
['encrypt', 'decrypt']
);
}
public static async encryptMessage(message: string, channelKey: string): Promise<string> {
try {
const key = await this.getEncryptionKey(channelKey);
const iv = window.crypto.getRandomValues(new Uint8Array(12));
const enc = new TextEncoder();
const cipherBuffer = await window.crypto.subtle.encrypt(
{ name: 'AES-GCM', iv },
key,
enc.encode(message)
);
const cipherArray = Array.from(new Uint8Array(cipherBuffer));
const ivArray = Array.from(iv);
// Combine IV and Ciphertext for easy storage
const combined = {
iv: ivArray,
cipher: cipherArray
};
return btoa(JSON.stringify(combined));
} catch (e) {
console.error("Encryption failed:", e);
return message; // fallback
}
}
public static async decryptMessage(encryptedBase64: string, channelKey: string): Promise<string> {
try {
// Basic check if string looks like base64 JSON
if (!encryptedBase64.startsWith('ey')) {
return encryptedBase64;
}
const combined = JSON.parse(atob(encryptedBase64));
if (!combined.iv || !combined.cipher) {
return encryptedBase64;
}
const key = await this.getEncryptionKey(channelKey);
const iv = new Uint8Array(combined.iv);
const cipher = new Uint8Array(combined.cipher);
const decryptedBuffer = await window.crypto.subtle.decrypt(
{ name: 'AES-GCM', iv },
key,
cipher
);
const dec = new TextDecoder();
return dec.decode(decryptedBuffer);
} catch (e) {
// If decryption fails, just return the encrypted payload or a fallback
return "🔒 [Encrypted Message]";
}
}
}
|