Files
arkvault/src/lib/modules/crypto.ts

137 lines
3.4 KiB
TypeScript

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 generateRSAEncKeyPair = async () => {
const keyPair = await window.crypto.subtle.generateKey(
{
name: "RSA-OAEP",
modulusLength: 4096,
publicExponent: new Uint8Array([1, 0, 1]),
hash: "SHA-256",
} satisfies RsaHashedKeyGenParams,
true,
["encrypt", "decrypt"],
);
return keyPair;
};
export const generateRSASigKeyPair = async () => {
const keyPair = await window.crypto.subtle.generateKey(
{
name: "RSA-PSS",
modulusLength: 4096,
publicExponent: new Uint8Array([1, 0, 1]),
hash: "SHA-256",
} satisfies RsaHashedKeyGenParams,
true,
["sign", "verify"],
);
return keyPair;
};
export const makeRSAEncKeyNonextractable = async (key: CryptoKey, type: RSAKeyType) => {
const { format, key: exportedKey } = await exportRSAKey(key, type);
return await window.crypto.subtle.importKey(
format,
exportedKey,
{
name: "RSA-OAEP",
hash: "SHA-256",
} satisfies RsaHashedImportParams,
false,
[type === "public" ? "encrypt" : "decrypt"],
);
};
export const makeRSASigKeyNonextractable = async (key: CryptoKey, type: RSAKeyType) => {
const { format, key: exportedKey } = await exportRSAKey(key, type);
return await window.crypto.subtle.importKey(
format,
exportedKey,
{
name: "RSA-PSS",
hash: "SHA-256",
} satisfies RsaHashedImportParams,
false,
[type === "public" ? "verify" : "sign"],
);
};
const exportRSAKey = async (key: CryptoKey, type: RSAKeyType) => {
const format = type === "public" ? ("spki" as const) : ("pkcs8" as const);
return {
format,
key: await window.crypto.subtle.exportKey(format, key),
};
};
export const exportRSAKeyToBase64 = async (key: CryptoKey, type: RSAKeyType) => {
return encodeToBase64((await exportRSAKey(key, type)).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),
{
name: "AES-GCM",
length: 256,
} satisfies AesKeyAlgorithm,
false,
["encrypt", "decrypt"],
);
};
export const exportAESKey = async (key: CryptoKey) => {
return await window.crypto.subtle.exportKey("raw", key);
};