mirror of
https://github.com/yusufipk/dead-man-switch-2.0.git
synced 2026-09-11 09:26:07 +00:00
97 lines
3.1 KiB
TypeScript
97 lines
3.1 KiB
TypeScript
export async function deriveKeyFromPassword(password: string): Promise<string> {
|
|
const encoder = new TextEncoder();
|
|
const keyMaterial = await crypto.subtle.importKey(
|
|
"raw",
|
|
encoder.encode(password),
|
|
"PBKDF2",
|
|
false,
|
|
["deriveBits", "deriveKey"]
|
|
);
|
|
const key = await crypto.subtle.deriveKey(
|
|
{
|
|
name: "PBKDF2",
|
|
salt: encoder.encode("dead-man-switch-salt"),
|
|
iterations: 100000,
|
|
hash: "SHA-256",
|
|
},
|
|
keyMaterial,
|
|
{ name: "AES-GCM", length: 256 },
|
|
true,
|
|
["encrypt", "decrypt"]
|
|
);
|
|
const exported = await crypto.subtle.exportKey("raw", key);
|
|
return btoa(String.fromCharCode(...new Uint8Array(exported)));
|
|
}
|
|
|
|
export async function generateKey(): Promise<string> {
|
|
const key = await crypto.subtle.generateKey(
|
|
{ name: "AES-GCM", length: 256 },
|
|
true,
|
|
["encrypt", "decrypt"]
|
|
);
|
|
const exported = await crypto.subtle.exportKey("raw", key);
|
|
return btoa(String.fromCharCode(...new Uint8Array(exported)));
|
|
}
|
|
|
|
export async function importKey(keyString: string): Promise<CryptoKey> {
|
|
const keyData = Uint8Array.from(atob(keyString), (c) => c.charCodeAt(0));
|
|
return crypto.subtle.importKey(
|
|
"raw",
|
|
keyData,
|
|
{ name: "AES-GCM", length: 256 },
|
|
false,
|
|
["encrypt", "decrypt"]
|
|
);
|
|
}
|
|
|
|
export async function encrypt(data: string, keyString: string): Promise<string> {
|
|
const key = await importKey(keyString);
|
|
const iv = crypto.getRandomValues(new Uint8Array(12));
|
|
const encoded = new TextEncoder().encode(data);
|
|
const encrypted = await crypto.subtle.encrypt(
|
|
{ name: "AES-GCM", iv },
|
|
key,
|
|
encoded
|
|
);
|
|
const combined = new Uint8Array(iv.length + encrypted.byteLength);
|
|
combined.set(iv);
|
|
combined.set(new Uint8Array(encrypted), iv.length);
|
|
return btoa(String.fromCharCode(...combined));
|
|
}
|
|
|
|
export async function decrypt(encryptedData: string, keyString: string): Promise<string> {
|
|
const key = await importKey(keyString);
|
|
const combined = Uint8Array.from(atob(encryptedData), (c) => c.charCodeAt(0));
|
|
const iv = combined.slice(0, 12);
|
|
const data = combined.slice(12);
|
|
const decrypted = await crypto.subtle.decrypt(
|
|
{ name: "AES-GCM", iv },
|
|
key,
|
|
data
|
|
);
|
|
return new TextDecoder().decode(decrypted);
|
|
}
|
|
|
|
export async function encryptFile(file: File, keyString: string): Promise<Blob> {
|
|
const key = await importKey(keyString);
|
|
const iv = crypto.getRandomValues(new Uint8Array(12));
|
|
const arrayBuffer = await file.arrayBuffer();
|
|
const encrypted = await crypto.subtle.encrypt(
|
|
{ name: "AES-GCM", iv },
|
|
key,
|
|
arrayBuffer
|
|
);
|
|
const combined = new Uint8Array(iv.length + encrypted.byteLength);
|
|
combined.set(iv);
|
|
combined.set(new Uint8Array(encrypted), iv.length);
|
|
return new Blob([combined], { type: "application/octet-stream" });
|
|
}
|
|
|
|
export async function decryptFile(encryptedBlob: Blob, keyString: string): Promise<ArrayBuffer> {
|
|
const key = await importKey(keyString);
|
|
const combined = new Uint8Array(await encryptedBlob.arrayBuffer());
|
|
const iv = combined.slice(0, 12);
|
|
const data = combined.slice(12);
|
|
return crypto.subtle.decrypt({ name: "AES-GCM", iv }, key, data);
|
|
}
|