init commit
This commit is contained in:
143
src/utils/crypto.ts
Normal file
143
src/utils/crypto.ts
Normal 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;
|
||||
}
|
Reference in New Issue
Block a user