deploy_feedback
deploy_feedback copied to clipboard
Deno deploy password hashing.
Is there a way to hash passwords async in deno deploy?
I've tried many modules like bcrypt, argon2, sodium & crypt. Most of them work in local deno environment. But none of them on deno deploy. Unless using a sync method.
For bcrypt there is an issue open: https://github.com/denoland/deploy_feedback/issues/171
Is there a standard non-blocking way of doing password hashing in deno? Maybe through the crypto web API.
https://bradyjoslin.com/blog/encryption-webcrypto/
https://doc.deno.land/deno/stable/~/SubtleCrypto
Encrypt or decrypt passwords on deno deploy async:
const buff_to_base64 = (buff: number[] | Uint8Array) =>
btoa(String.fromCharCode.apply(null, buff));
const base64_to_buf = (b64: string) =>
Uint8Array.from(atob(b64), (c) => c.charCodeAt(null));
const enc = new TextEncoder();
const dec = new TextDecoder();
const getPasswordKey = async (password: any) =>
await window.crypto.subtle.importKey(
"raw",
enc.encode(password),
"PBKDF2",
false,
['deriveBits', "deriveKey"]
);
const deriveKey = async (passwordKey: any, salt: any, keyUsage: any[]) =>
await window.crypto.subtle.deriveKey(
{
name: "PBKDF2",
salt: salt,
iterations: 250000,
hash: "SHA-256",
},
passwordKey,
{ name: "AES-GCM", length: 256 },
false,
keyUsage
);
export async function encryptData(secretData: string | undefined, password: any) {
try {
const salt = window.crypto.getRandomValues(new Uint8Array(16));
const iv = window.crypto.getRandomValues(new Uint8Array(12));
const passwordKey = await getPasswordKey(password);
const aesKey = await deriveKey(passwordKey, salt, ["encrypt"]);
const encryptedContent = await window.crypto.subtle.encrypt(
{
name: "AES-GCM",
iv: iv,
},
aesKey,
enc.encode(secretData)
);
const encryptedContentArr = new Uint8Array(encryptedContent);
let buff = new Uint8Array(
salt.byteLength + iv.byteLength + encryptedContentArr.byteLength
);
buff.set(salt, 0);
buff.set(iv, salt.byteLength);
buff.set(encryptedContentArr, salt.byteLength + iv.byteLength);
const base64Buff = buff_to_base64(buff);
return base64Buff;
} catch (e) {
console.log(`Error - ${e}`);
return "";
}
}
export async function decryptData(
encryptedData: string,
password: string | undefined
) {
try {
const encryptedDataBuff = base64_to_buf(encryptedData);
const salt = encryptedDataBuff.slice(0, 16);
const iv = encryptedDataBuff.slice(16, 16 + 12);
const data = encryptedDataBuff.slice(16 + 12);
const passwordKey = await getPasswordKey(password);
const aesKey = await deriveKey(passwordKey, salt, ["decrypt"]);
const decryptedContent = await window.crypto.subtle.decrypt(
{
name: "AES-GCM",
iv: iv,
},
aesKey,
data
);
return dec.decode(decryptedContent);
} catch (e) {
console.log(`Error - ${e}`);
return "";
}
}
I just ran into the same issue with bcrypt. I also, was trying to hash a password.
I used the synced versions of hash and compare. That worked on Deno Deploy.
I dont know why but, after trying with Sync, it works.
Thank @jarrodu