Files
multiverse/jumpa-vc/lib/xcu-quantum-cipher.ts

67 lines
1.6 KiB
TypeScript

export class XCUQuantumCipher {
private key: CryptoKey | null = null;
private roomSecret: string;
constructor(roomSecret: string) {
this.roomSecret = roomSecret;
}
public async initialize() {
const enc = new TextEncoder();
const keyMaterial = await crypto.subtle.importKey(
"raw",
enc.encode(this.roomSecret.padEnd(32, "0").slice(0, 32)), // 256-bit derivation
{ name: "PBKDF2" },
false,
["deriveBits", "deriveKey"]
);
this.key = await crypto.subtle.deriveKey(
{
name: "PBKDF2",
salt: enc.encode("xcom_ultra_salt_v1"),
iterations: 100000,
hash: "SHA-256",
},
keyMaterial,
{ name: "AES-GCM", length: 256 },
false,
["encrypt", "decrypt"]
);
}
public async encrypt(plaintext: string): Promise<Uint8Array> {
if (!this.key) throw new Error("Cipher not initialized");
const iv = crypto.getRandomValues(new Uint8Array(12));
const enc = new TextEncoder();
const ciphertext = await crypto.subtle.encrypt(
{
name: "AES-GCM",
iv: iv,
},
this.key,
enc.encode(plaintext)
);
const result = new Uint8Array(iv.length + ciphertext.byteLength);
result.set(iv, 0);
result.set(new Uint8Array(ciphertext), iv.length);
return result;
}
public async decrypt(data: Uint8Array): Promise<string> {
if (!this.key) throw new Error("Cipher not initialized");
const iv = data.slice(0, 12);
const ciphertext = data.slice(12);
const plaintext = await crypto.subtle.decrypt(
{
name: "AES-GCM",
iv: iv,
},
this.key,
ciphertext
);
const dec = new TextDecoder();
return dec.decode(plaintext);
}
}