init commit

This commit is contained in:
2024-01-29 19:22:39 -05:00
commit 1c75b72b82
23 changed files with 1405 additions and 0 deletions

143
src/utils/crypto.ts Normal file
View File

@@ -0,0 +1,143 @@
export async function generateKeyPair(): Promise<CryptoKeyPair> {
return await window.crypto.subtle.generateKey(
{
name: "ECDH",
namedCurve: "P-256",
},
true,
["deriveKey", "deriveBits"]
);
}
export async function deriveSharedSecret(
privateKey: CryptoKey,
publicKey: CryptoKey
): Promise<CryptoKey> {
return await window.crypto.subtle.deriveKey(
{
name: "ECDH",
public: publicKey,
},
privateKey,
{
name: "AES-GCM",
length: 256,
},
true,
["encrypt", "decrypt"]
);
}
export async function retrieveOrGenerateKeyPair(): Promise<CryptoKeyPair> {
let ecdhPublic: CryptoKey;
let ecdhPrivate: CryptoKey;
if (
localStorage.getItem("ecdhPublic") &&
localStorage.getItem("ecdhPrivate")
) {
const ecdhPublicJwk = JSON.parse(localStorage.getItem("ecdhPublic")!);
const ecdhPrivateJwk = JSON.parse(localStorage.getItem("ecdhPrivate")!);
ecdhPrivate = await window.crypto.subtle.importKey(
"jwk",
ecdhPrivateJwk,
{
name: "ECDH",
namedCurve: "P-256",
},
true,
["deriveKey", "deriveBits"]
);
ecdhPublic = await window.crypto.subtle.importKey(
"jwk",
ecdhPublicJwk,
{
name: "ECDH",
namedCurve: "P-256",
},
true,
[]
);
} else {
const keyPair = await generateKeyPair();
ecdhPublic = keyPair.publicKey;
ecdhPrivate = keyPair.privateKey;
saveKeys(ecdhPublic, ecdhPrivate);
}
return { publicKey: ecdhPublic, privateKey: ecdhPrivate };
}
async function saveKeys(ecdhPublic: CryptoKey, ecdhPrivate: CryptoKey) {
const ecdhPublicJwk = await window.crypto.subtle.exportKey("jwk", ecdhPublic);
const ecdhPrivateJwk = await window.crypto.subtle.exportKey(
"jwk",
ecdhPrivate
);
// Store ECDH key pair in local storage
localStorage.setItem("ecdhPublic", JSON.stringify(ecdhPublicJwk));
localStorage.setItem("ecdhPrivate", JSON.stringify(ecdhPrivateJwk));
}
export async function encrypt(
aesKey: CryptoKey,
data: string
): Promise<{ encryptedData: ArrayBuffer; iv: Uint8Array }> {
// Convert the data to a Uint8Array
const dataUint8Array = new TextEncoder().encode(data);
// Generate a random initialization vector (iv)
const iv = window.crypto.getRandomValues(new Uint8Array(12));
// Encrypt the data
const encryptedData = await window.crypto.subtle.encrypt(
{
name: "AES-GCM",
iv: iv,
},
aesKey,
dataUint8Array
);
// Return the combined iv and encrypted data
return { encryptedData, iv };
}
export async function decrypt(
aesKey: CryptoKey,
iv: string,
encryptedData: string
): Promise<string> {
console.log(iv);
// Decode the iv and encryptedData from base64
const ivUint8Array = base64ToUint8Array(iv);
const encryptedDataUint8Array = base64ToUint8Array(encryptedData);
// Decrypt the data
const decryptedData = await window.crypto.subtle.decrypt(
{
name: "AES-GCM",
iv: ivUint8Array,
},
aesKey,
encryptedDataUint8Array
);
// Convert the decrypted data from a Uint8Array to a string
const decryptedString = new TextDecoder().decode(decryptedData);
return decryptedString;
}
function base64ToUint8Array(base64: string): Uint8Array {
const binaryString = atob(base64);
const len = binaryString.length;
const bytes = new Uint8Array(len);
for (let i = 0; i < len; i++) {
bytes[i] = binaryString.charCodeAt(i);
}
return bytes;
}