Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@ayosec
Created September 8, 2020 02:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ayosec/d4dc24fb8f0965703c023f92b8e9cdf3 to your computer and use it in GitHub Desktop.
Save ayosec/d4dc24fb8f0965703c023f92b8e9cdf3 to your computer and use it in GitHub Desktop.
async function keysFromPassword(salt, password) {
let enc = new TextEncoder().encode(password);
let basekey = await crypto.subtle.importKey("raw", enc, "PBKDF2", false, ["deriveBits"]);
let keys = await crypto.subtle.deriveBits(
{
name: 'PBKDF2',
hash: 'SHA-512',
salt: salt,
iterations: 1e5
},
basekey,
256 /* key */ + 128 /* iv */
);
let iv = new Uint8Array(keys.slice(32));
let key = await crypto.subtle.importKey(
"raw",
new Uint8Array(keys.slice(0, 32)),
{ name: "AES-GCM" },
false,
[ "decrypt", "encrypt" ]
);
return { key: key, iv: iv };
}
async function encrypt(password, plaintext) {
let salt = new Uint8Array(32);
crypto.getRandomValues(salt);
let aesParams = await keysFromPassword(salt, password);
let ciphertext = await window.crypto.subtle.encrypt(
{ name: "AES-GCM", iv: aesParams.iv },
aesParams.key,
new TextEncoder().encode(plaintext)
);
return { salt: bytesToString(salt), ciphertext: bytesToString(ciphertext) };
}
async function decrypt(salt, password, ciphertext) {
let aesParams = await keysFromPassword(stringToBytes(salt), password);
let plaintext = await window.crypto.subtle.decrypt(
{ name: "AES-GCM", iv: aesParams.iv },
aesParams.key,
new Uint8Array(stringToBytes(ciphertext))
);
return new TextDecoder().decode(plaintext);
}
function bytesToString(bytes) {
let array = Array.from(new Uint8Array(bytes));
return btoa(array.map(b => String.fromCharCode(b)).join(''));
}
function stringToBytes(str) {
return new Uint8Array(atob(str).match(/[\s\S]/g).map(c => c.charCodeAt(0)));
}
async function encryptFormField() {
let password = document.getElementById("password").value;
let plaintext = document.getElementById("data").value;
let encrypted = await encrypt(password, plaintext);
document.getElementById("ciphertext").value = JSON.stringify(encrypted);
let decrypted = await decrypt(encrypted.salt, password, encrypted.ciphertext);
if(decrypted !== plaintext) {
alert("encrypt() failed");
}
}
async function runTest() {
let encrypted = await encrypt("p455w0rd", "original text");
console.log("encrypted", encrypted);
let decrypted = await decrypt(encrypted.salt, "p455w0rd", encrypted.ciphertext);
console.log("decrypted", decrypted);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment