-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: Change password hashing libraries to not use WASM (for now)
- Loading branch information
1 parent
747f455
commit 26793ee
Showing
4 changed files
with
51 additions
and
116 deletions.
There are no files selected for viewing
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,86 +1,21 @@ | ||
// import { | ||
// hash as hashArgon2, | ||
// Argon2Params, | ||
// Argon2Version, | ||
// Argon2Algorithm, | ||
// } from "https://deno.land/x/[email protected]/mod.ts"; | ||
// import { generateSalt } from "./common.ts"; | ||
// import { timingSafeEqual } from "https://deno.land/[email protected]/crypto/timing_safe_equal.ts"; | ||
// import base64 from "https://deno.land/x/[email protected]/src/base64.js"; | ||
// | ||
// | ||
// // OWASP recommended defaults: | ||
// // https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#argon2id | ||
// const argon2Defaults: Argon2Params = { | ||
// algorithm: "Argon2id", | ||
// version: 19, | ||
// tCost: 2, // 3 iterations | ||
// mCost: 19 * 1024, // 19MiB of memory | ||
// pCost: 1, // 1 thread | ||
// | ||
// secret: undefined, | ||
// outputLength: 32, | ||
// }; | ||
// | ||
// export function createHash(password: string) { | ||
// const salt = generateSalt(); | ||
// const passwordBuffer = new TextEncoder().encode(password); | ||
// const hash = hashArgon2(passwordBuffer, salt, argon2Defaults); | ||
// return packDigest(hash, salt, argon2Defaults); | ||
// } | ||
// | ||
// export function hashMatches(guess: string, digest: string) { | ||
// const { hash, salt, params } = unpackDigest(digest); | ||
// const guessBuffer = new TextEncoder().encode(guess); | ||
// | ||
// const hashGuess = hashArgon2(guessBuffer, salt, params); | ||
// | ||
// return timingSafeEqual(hashGuess, hash); | ||
// } | ||
// | ||
// function packDigest(hash: ArrayBuffer, salt: ArrayBuffer, params: Argon2Params) { | ||
// const headerPart = `$${params.algorithm.toLowerCase()}$v=${params.version}$`; | ||
// const paramPart = `m=${params.mCost},t=${params.tCost},p=${params.pCost}`; | ||
// | ||
// const saltBase64 = base64.fromArrayBuffer(salt); | ||
// const hashBase64 = base64.fromArrayBuffer(hash); | ||
// | ||
// return `${headerPart}${paramPart}$${saltBase64}$${hashBase64}`; | ||
// } | ||
// | ||
// const algorithmMap: Record<string, Argon2Algorithm> = { | ||
// "argon2i": "Argon2i", | ||
// "argon2d": "Argon2d", | ||
// "argon2id": "Argon2id", | ||
// }; | ||
// | ||
// function unpackDigest(digest: string): { hash: ArrayBuffer, salt: ArrayBuffer, params: Argon2Params } { | ||
// const [, algorithmName, versionStr, params, saltStr, hashStr] = digest.split("$"); | ||
// | ||
// const algorithm = algorithmMap[algorithmName]; | ||
// const version = parseInt(versionStr.match(/v=(\d+)/)![1]); | ||
// | ||
// const mCost = parseInt(params.match(/m=(\d+)/)![1]); | ||
// const tCost = parseInt(params.match(/t=(\d+)/)![1]); | ||
// const pCost = parseInt(params.match(/p=(\d+)/)![1]); | ||
// | ||
// const salt = base64.toArrayBuffer(saltStr); | ||
// const hash = base64.toArrayBuffer(hashStr); | ||
// | ||
// | ||
// if (!algorithm || !version || !mCost || !tCost || !pCost || !salt || !hash) { | ||
// throw new Error("Invalid internal hash format"); | ||
// } | ||
// | ||
// return { | ||
// hash, | ||
// salt, | ||
// params: { | ||
// algorithm, | ||
// version: version as Argon2Version, | ||
// mCost, | ||
// tCost, | ||
// pCost, | ||
// }, | ||
// }; | ||
// } | ||
import { hash as hashArgon2, verify, Argon2Params } from "jsr:@blckbrry/[email protected]/polyfill"; | ||
import { generateSalt } from "./common.ts"; | ||
|
||
// OWASP recommended defaults: | ||
// https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#argon2id | ||
const argon2Params: Argon2Params = { | ||
algorithm: "Argon2id", | ||
version: 0x13, | ||
tCost: 2, // 2 iterations | ||
mCost: 19 * 1024, // 19MiB of memory | ||
pCost: 1, // 1 thread | ||
|
||
}; | ||
|
||
export function createHash(password: string) { | ||
return hashArgon2(new TextEncoder().encode(password), generateSalt(), argon2Params); | ||
} | ||
|
||
export function hashMatches(guess: string, hash: string) { | ||
return verify(hash, new TextEncoder().encode(guess)); | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,16 +1,16 @@ | ||
// import { hash as hashBCrypt, verify, BcryptParams } from "jsr:@blackberry/bcrypt@0.15.3"; | ||
// | ||
// // OWASP recommended defaults: | ||
// // https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#bcrypt | ||
// const bcryptParams: BcryptParams = { | ||
// cost: 10, | ||
// version: "2b", // 2b is the newest version of the OpenBSD bcrypt standard. | ||
// }; | ||
// | ||
// export function createHash(password: string) { | ||
// return hashBCrypt(new TextEncoder().encode(password), undefined, bcryptParams); | ||
// } | ||
// | ||
// export function hashMatches(guess: string, hash: string) { | ||
// return verify(new TextEncoder().encode(guess), hash); | ||
// } | ||
import { hash as hashBCrypt, verify, BcryptParams } from "jsr:@blckbrry/bcrypt@0.17.1/polyfill"; | ||
|
||
// OWASP recommended defaults: | ||
// https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#bcrypt | ||
const bcryptParams: BcryptParams = { | ||
cost: 10, | ||
version: "2b", // 2b is the newest version of the OpenBSD bcrypt standard. | ||
}; | ||
|
||
export function createHash(password: string) { | ||
return hashBCrypt(new TextEncoder().encode(password), undefined, bcryptParams); | ||
} | ||
|
||
export function hashMatches(guess: string, hash: string) { | ||
return verify(new TextEncoder().encode(guess), hash); | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,12 @@ | ||
import base64 from "https://deno.land/x/[email protected]/src/base64.js"; | ||
|
||
// import { createHash as hashSCrypt } from "./scrypt.ts"; | ||
// import { createHash as hashBCrypt } from "./bcrypt.ts"; | ||
import { createHash as hashBCrypt } from "./bcrypt.ts"; | ||
import { createHash as hashArgon2 } from "./argon2.ts"; | ||
|
||
// import { hashMatches as matchesSCrypt } from "./scrypt.ts"; | ||
// import { hashMatches as matchesBCrypt } from "./bcrypt.ts"; | ||
|
||
// import { createHash as hashArgon2 } from "./argon2.ts"; | ||
// import { hashMatches as matchesArgon2 } from "./argon2.ts"; | ||
import { hashMatches as matchesBCrypt } from "./bcrypt.ts"; | ||
import { hashMatches as matchesArgon2 } from "./argon2.ts"; | ||
|
||
export function toBase64(buffer: ArrayBufferLike) { | ||
return base64.fromArrayBuffer(new Uint8Array(buffer)); | ||
|
@@ -60,11 +59,11 @@ export const ALGORITHM_DEFAULT: Algorithm = "bcrypt"; | |
export function hash(password: string, algorithm: Algorithm = ALGORITHM_DEFAULT): string { | ||
switch (algorithm) { | ||
case "argon2": | ||
// return hashArgon2(password); | ||
throw new Error("Unimplemented"); | ||
return hashArgon2(password); | ||
// throw new Error("Unimplemented"); | ||
case "bcrypt": | ||
// return hashBCrypt(password); | ||
throw new Error("Unimplemented"); | ||
return hashBCrypt(password); | ||
// throw new Error("Unimplemented"); | ||
case "scrypt": | ||
// return hashSCrypt(password); | ||
throw new Error("Unimplemented"); | ||
|
@@ -74,11 +73,11 @@ export function hash(password: string, algorithm: Algorithm = ALGORITHM_DEFAULT) | |
export function hashMatches(password: string, hash: string, algorithm: Algorithm = ALGORITHM_DEFAULT): boolean { | ||
switch (algorithm) { | ||
case "argon2": | ||
// return matchesArgon2(password, hash); | ||
throw new Error("Unimplemented"); | ||
return matchesArgon2(password, hash); | ||
// throw new Error("Unimplemented"); | ||
case "bcrypt": | ||
// return matchesBCrypt(password, hash); | ||
throw new Error("Unimplemented"); | ||
return matchesBCrypt(password, hash); | ||
// throw new Error("Unimplemented"); | ||
case "scrypt": | ||
// return matchesSCrypt(password, hash); | ||
throw new Error("Unimplemented"); | ||
|