mirror of
https://github.com/kmc7468/arkvault.git
synced 2025-12-15 22:38:47 +00:00
111 lines
2.9 KiB
TypeScript
111 lines
2.9 KiB
TypeScript
import { encodeString, decodeString, encodeToBase64, decodeFromBase64 } from "./util";
|
|
|
|
export const generateMasterKey = async () => {
|
|
return {
|
|
masterKey: await window.crypto.subtle.generateKey(
|
|
{
|
|
name: "AES-KW",
|
|
length: 256,
|
|
} satisfies AesKeyGenParams,
|
|
true,
|
|
["wrapKey", "unwrapKey"],
|
|
),
|
|
};
|
|
};
|
|
|
|
export const generateDataKey = async () => {
|
|
return {
|
|
dataKey: await window.crypto.subtle.generateKey(
|
|
{
|
|
name: "AES-GCM",
|
|
length: 256,
|
|
} satisfies AesKeyGenParams,
|
|
true,
|
|
["encrypt", "decrypt"],
|
|
),
|
|
dataKeyVersion: new Date(),
|
|
};
|
|
};
|
|
|
|
export const makeAESKeyNonextractable = async (key: CryptoKey) => {
|
|
return await window.crypto.subtle.importKey(
|
|
"raw",
|
|
await window.crypto.subtle.exportKey("raw", key),
|
|
key.algorithm,
|
|
false,
|
|
key.usages,
|
|
);
|
|
};
|
|
|
|
export const wrapDataKey = async (dataKey: CryptoKey, masterKey: CryptoKey) => {
|
|
return encodeToBase64(await window.crypto.subtle.wrapKey("raw", dataKey, masterKey, "AES-KW"));
|
|
};
|
|
|
|
export const unwrapDataKey = async (dataKeyWrapped: string, masterKey: CryptoKey) => {
|
|
return {
|
|
dataKey: await window.crypto.subtle.unwrapKey(
|
|
"raw",
|
|
decodeFromBase64(dataKeyWrapped),
|
|
masterKey,
|
|
"AES-KW",
|
|
"AES-GCM",
|
|
false, // Nonextractable
|
|
["encrypt", "decrypt"],
|
|
),
|
|
};
|
|
};
|
|
|
|
export const wrapHmacSecret = async (hmacSecret: CryptoKey, masterKey: CryptoKey) => {
|
|
return encodeToBase64(await window.crypto.subtle.wrapKey("raw", hmacSecret, masterKey, "AES-KW"));
|
|
};
|
|
|
|
export const unwrapHmacSecret = async (hmacSecretWrapped: string, masterKey: CryptoKey) => {
|
|
return {
|
|
hmacSecret: await window.crypto.subtle.unwrapKey(
|
|
"raw",
|
|
decodeFromBase64(hmacSecretWrapped),
|
|
masterKey,
|
|
"AES-KW",
|
|
{
|
|
name: "HMAC",
|
|
hash: "SHA-256",
|
|
} satisfies HmacImportParams,
|
|
false, // Nonextractable
|
|
["sign", "verify"],
|
|
),
|
|
};
|
|
};
|
|
|
|
export const encryptData = async (data: BufferSource, dataKey: CryptoKey) => {
|
|
const iv = window.crypto.getRandomValues(new Uint8Array(12));
|
|
const ciphertext = await window.crypto.subtle.encrypt(
|
|
{
|
|
name: "AES-GCM",
|
|
iv,
|
|
} satisfies AesGcmParams,
|
|
dataKey,
|
|
data,
|
|
);
|
|
return { ciphertext, iv: encodeToBase64(iv.buffer) };
|
|
};
|
|
|
|
export const decryptData = async (ciphertext: BufferSource, iv: string, dataKey: CryptoKey) => {
|
|
return await window.crypto.subtle.decrypt(
|
|
{
|
|
name: "AES-GCM",
|
|
iv: decodeFromBase64(iv),
|
|
} satisfies AesGcmParams,
|
|
dataKey,
|
|
ciphertext,
|
|
);
|
|
};
|
|
|
|
export const encryptString = async (plaintext: string, dataKey: CryptoKey) => {
|
|
const { ciphertext, iv } = await encryptData(encodeString(plaintext), dataKey);
|
|
return { ciphertext: encodeToBase64(ciphertext), iv };
|
|
};
|
|
|
|
export const decryptString = async (ciphertext: string, iv: string, dataKey: CryptoKey) => {
|
|
return decodeString(await decryptData(decodeFromBase64(ciphertext), iv, dataKey));
|
|
};
|