Last active
August 9, 2024 00:25
-
-
Save arvati/9a06e80e421c62dee530a428a9817f10 to your computer and use it in GitHub Desktop.
This module provides BCrypt hashing support for deno and the web by providing simple bindings using bcrypt compiled to webassembly.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//https://jsr.io/@blackberry/bcrypt | |
import { hash, verify } from "jsr:@blackberry/bcrypt"; | |
const encoder = new TextEncoder(); | |
const password = encoder.encode("very-cool-password"); | |
const salt = encoder.encode("salty salt woo!!"); | |
const hashed = hash(password, salt); | |
console.log(hashed); | |
// $2b$12$a0DqbFiea0DqbA/1Z06fGOZcRMnat359MTbqezYI1qXvLuOL16Eve | |
const verified = verify(password, hashed); | |
console.log(verified); | |
// true |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// https://github.com/JamesBroadberry/deno-bcrypt/issues/26#issuecomment-1268090590 | |
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 ""; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment