Files
arkvault/src/lib/modules/crypto.ts
2024-12-31 06:34:35 +09:00

103 lines
2.6 KiB
TypeScript

export type RSAKeyPurpose = "encryption" | "signature";
export type RSAKeyType = "public" | "private";
export const encodeToBase64 = (data: ArrayBuffer) => {
return btoa(String.fromCharCode(...new Uint8Array(data)));
};
export const decodeFromBase64 = (data: string) => {
return Uint8Array.from(atob(data), (c) => c.charCodeAt(0)).buffer;
};
export const generateRSAKeyPair = async (purpose: RSAKeyPurpose) => {
return await window.crypto.subtle.generateKey(
{
name: purpose === "encryption" ? "RSA-OAEP" : "RSA-PSS",
modulusLength: 4096,
publicExponent: new Uint8Array([1, 0, 1]),
hash: "SHA-256",
} satisfies RsaHashedKeyGenParams,
true,
purpose === "encryption" ? ["encrypt", "decrypt"] : ["sign", "verify"],
);
};
export const makeRSAKeyNonextractable = async (key: CryptoKey) => {
const { format, key: exportedKey } = await exportRSAKey(key);
return await window.crypto.subtle.importKey(
format,
exportedKey,
key.algorithm,
false,
key.usages,
);
};
export const exportRSAKey = async (key: CryptoKey) => {
const format = key.type === "public" ? ("spki" as const) : ("pkcs8" as const);
return {
format,
key: await window.crypto.subtle.exportKey(format, key),
};
};
export const exportRSAKeyToBase64 = async (key: CryptoKey) => {
return encodeToBase64((await exportRSAKey(key)).key);
};
export const encryptRSAPlaintext = async (plaintext: ArrayBuffer, publicKey: CryptoKey) => {
return await window.crypto.subtle.encrypt(
{
name: "RSA-OAEP",
} satisfies RsaOaepParams,
publicKey,
plaintext,
);
};
export const decryptRSACiphertext = async (ciphertext: ArrayBuffer, privateKey: CryptoKey) => {
return await window.crypto.subtle.decrypt(
{
name: "RSA-OAEP",
} satisfies RsaOaepParams,
privateKey,
ciphertext,
);
};
export const signRSAMessage = async (message: ArrayBuffer, privateKey: CryptoKey) => {
return await window.crypto.subtle.sign(
{
name: "RSA-PSS",
saltLength: 32,
} satisfies RsaPssParams,
privateKey,
message,
);
};
export const generateAESKey = async () => {
return await window.crypto.subtle.generateKey(
{
name: "AES-GCM",
length: 256,
} satisfies AesKeyGenParams,
true,
["encrypt", "decrypt"],
);
};
export const makeAESKeyNonextractable = async (key: CryptoKey) => {
return await window.crypto.subtle.importKey(
"raw",
await exportAESKey(key),
key.algorithm,
false,
key.usages,
);
};
export const exportAESKey = async (key: CryptoKey) => {
return await window.crypto.subtle.exportKey("raw", key);
};