mirror of
https://github.com/Nathanwoodburn/hnschat-web.git
synced 2025-01-19 04:08:12 +11:00
124 lines
2.4 KiB
JavaScript
124 lines
2.4 KiB
JavaScript
|
export class e2ee {
|
||
|
async generateKeys() {
|
||
|
const keyPair = await window.crypto.subtle.generateKey(
|
||
|
{
|
||
|
name: "ECDH",
|
||
|
namedCurve: "P-256",
|
||
|
},
|
||
|
true,
|
||
|
["deriveKey", "deriveBits"]
|
||
|
);
|
||
|
|
||
|
const publicKeyJwk = await window.crypto.subtle.exportKey(
|
||
|
"jwk",
|
||
|
keyPair.publicKey
|
||
|
);
|
||
|
|
||
|
const privateKeyJwk = await window.crypto.subtle.exportKey(
|
||
|
"jwk",
|
||
|
keyPair.privateKey
|
||
|
);
|
||
|
|
||
|
return { publicKeyJwk, privateKeyJwk };
|
||
|
}
|
||
|
|
||
|
async importKey(x, y, d) {
|
||
|
const privateKey = await window.crypto.subtle.importKey(
|
||
|
"jwk",
|
||
|
{
|
||
|
kty: "EC",
|
||
|
crv: "P-256",
|
||
|
x: x,
|
||
|
y: y,
|
||
|
d: d,
|
||
|
ext: true,
|
||
|
},
|
||
|
{
|
||
|
name: "ECDH",
|
||
|
namedCurve: "P-256",
|
||
|
},
|
||
|
true,
|
||
|
["deriveKey", "deriveBits"]
|
||
|
);
|
||
|
|
||
|
const privateKeyJwk = await window.crypto.subtle.exportKey(
|
||
|
"jwk",
|
||
|
privateKey
|
||
|
);
|
||
|
|
||
|
return privateKeyJwk;
|
||
|
}
|
||
|
|
||
|
async deriveKey(publicKeyJwk, privateKeyJwk) {
|
||
|
const publicKey = await window.crypto.subtle.importKey(
|
||
|
"jwk",
|
||
|
publicKeyJwk,
|
||
|
{
|
||
|
name: "ECDH",
|
||
|
namedCurve: "P-256",
|
||
|
},
|
||
|
true,
|
||
|
[]
|
||
|
);
|
||
|
|
||
|
const privateKey = await window.crypto.subtle.importKey(
|
||
|
"jwk",
|
||
|
privateKeyJwk,
|
||
|
{
|
||
|
name: "ECDH",
|
||
|
namedCurve: "P-256",
|
||
|
},
|
||
|
true,
|
||
|
["deriveKey", "deriveBits"]
|
||
|
);
|
||
|
|
||
|
return await window.crypto.subtle.deriveKey(
|
||
|
{ name: "ECDH", public: publicKey },
|
||
|
privateKey,
|
||
|
{ name: "AES-GCM", length: 256 },
|
||
|
true,
|
||
|
["encrypt", "decrypt"]
|
||
|
);
|
||
|
};
|
||
|
|
||
|
async encryptMessage(text, derivedKey, conversation) {
|
||
|
const encodedText = new TextEncoder().encode(text);
|
||
|
|
||
|
const encryptedData = await window.crypto.subtle.encrypt(
|
||
|
{ name: "AES-GCM", iv: new TextEncoder().encode(conversation) },
|
||
|
derivedKey,
|
||
|
encodedText
|
||
|
);
|
||
|
|
||
|
const uintArray = new Uint8Array(encryptedData);
|
||
|
const string = String.fromCharCode.apply(null, uintArray);
|
||
|
const base64Data = btoa(string);
|
||
|
|
||
|
return base64Data;
|
||
|
};
|
||
|
|
||
|
async decryptMessage(text, derivedKey, conversation) {
|
||
|
try {
|
||
|
const initializationVector = new Uint8Array(new TextEncoder().encode(conversation)).buffer;
|
||
|
|
||
|
const string = atob(text);
|
||
|
const uintArray = new Uint8Array(
|
||
|
[...string].map((char) => char.charCodeAt(0))
|
||
|
);
|
||
|
const algorithm = {
|
||
|
name: "AES-GCM",
|
||
|
iv: initializationVector,
|
||
|
};
|
||
|
const decryptedData = await window.crypto.subtle.decrypt(
|
||
|
algorithm,
|
||
|
derivedKey,
|
||
|
uintArray
|
||
|
);
|
||
|
|
||
|
return new TextDecoder().decode(decryptedData);
|
||
|
}
|
||
|
catch {
|
||
|
return text;
|
||
|
}
|
||
|
};
|
||
|
}
|