141 lines
2.8 KiB
JavaScript
141 lines
2.8 KiB
JavaScript
let encForm = new Form({id: "encryption", tag: document.getElementById("encryption")});
|
|
let encMsg = new FormElement({
|
|
id: "msg",
|
|
type: "textarea",
|
|
label: "Message",
|
|
form: encForm
|
|
});
|
|
let encPass = new FormElement({
|
|
id: "password",
|
|
type: "password",
|
|
label: "Password",
|
|
form: encForm
|
|
});
|
|
let encButton = new FormElement({
|
|
id: "button",
|
|
type: "button",
|
|
label: "Encrypt",
|
|
form: encForm
|
|
});
|
|
let encOut = new FormElement({
|
|
id: "output",
|
|
type: "output",
|
|
label: "Output",
|
|
dataType: "json-b64",
|
|
form: encForm
|
|
});
|
|
|
|
let decForm = new Form({id: "decryption", tag: document.getElementById("decryption")});
|
|
let decMsg = new FormElement({
|
|
id: "msg",
|
|
type: "textarea",
|
|
label: "Encrypted message",
|
|
dataType: "json-b64",
|
|
form: decForm
|
|
});
|
|
let decPass = new FormElement({
|
|
id: "password",
|
|
type: "password",
|
|
label: "Password",
|
|
form: decForm
|
|
});
|
|
let decButton = new FormElement({
|
|
id: "button",
|
|
type: "button",
|
|
label: "Decrypt",
|
|
form: decForm
|
|
});
|
|
let decOut = new FormElement({
|
|
id: "output",
|
|
type: "output",
|
|
label: "Output",
|
|
form: decForm
|
|
});
|
|
|
|
function getKeyMaterial(password) {
|
|
let enc = new TextEncoder();
|
|
return window.crypto.subtle.importKey(
|
|
"raw",
|
|
enc.encode(password),
|
|
"PBKDF2",
|
|
false,
|
|
["deriveKey"]
|
|
);
|
|
}
|
|
|
|
function getKey(keyMaterial, salt) {
|
|
return window.crypto.subtle.deriveKey(
|
|
{
|
|
"name": "PBKDF2",
|
|
"hash": "SHA-256",
|
|
"salt": salt,
|
|
"iterations": 300000
|
|
},
|
|
keyMaterial,
|
|
{
|
|
"name": "AES-GCM",
|
|
"length": 256
|
|
},
|
|
true,
|
|
["encrypt", "decrypt"]
|
|
);
|
|
}
|
|
|
|
async function encrypt() {
|
|
let keyMaterial = await getKeyMaterial(encPass.value);
|
|
let salt = window.crypto.getRandomValues(new Uint8Array(16));
|
|
let key = await getKey(keyMaterial, salt);
|
|
|
|
let iv = window.crypto.getRandomValues(new Uint8Array(16));
|
|
|
|
let enc = new TextEncoder();
|
|
let msgEncoded = enc.encode(encMsg.value);
|
|
|
|
let ciphertext = await window.crypto.subtle.encrypt(
|
|
{
|
|
"name": "AES-GCM",
|
|
"iv": iv
|
|
},
|
|
key,
|
|
msgEncoded
|
|
);
|
|
|
|
encOut.value = {
|
|
"ciphertext": bufToB64(ciphertext),
|
|
"salt": bufToB64(salt),
|
|
"iv": bufToB64(iv)
|
|
}
|
|
}
|
|
|
|
async function decrypt() {
|
|
let msgEncoded = decMsg.value;
|
|
|
|
let ciphertext = new b64ToBuf(msgEncoded.ciphertext);
|
|
let iv = new Uint8Array(b64ToBuf(msgEncoded.iv));
|
|
let salt = new Uint8Array(b64ToBuf(msgEncoded.salt));
|
|
|
|
let keyMaterial = await getKeyMaterial(decPass.value);
|
|
let key = await getKey(keyMaterial, salt);
|
|
|
|
let plaintext;
|
|
|
|
try {
|
|
plaintext = await window.crypto.subtle.decrypt(
|
|
{
|
|
"name": "AES-GCM",
|
|
"iv": iv
|
|
},
|
|
key,
|
|
ciphertext
|
|
);
|
|
} catch (e) {
|
|
decPass.alertBox("alert-error", "Decryption error: incorrect password?");
|
|
}
|
|
|
|
let dec = new TextDecoder();
|
|
decOut.value = `${dec.decode(plaintext)}`;
|
|
}
|
|
|
|
encButton.handle.addEventListener("click", encrypt);
|
|
decButton.handle.addEventListener("click", decrypt);
|