Created
March 16, 2024 08:03
-
-
Save composite/e943b5b993b9b329b41bb0092dc21d89 to your computer and use it in GitHub Desktop.
Generate and verify password based on PBKDF2 with SHA-256 using Web Standards. works on modern browser, node(20 or later), and any cloud's edge environment.
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
const encoder = new TextEncoder(); | |
const ITERATIONS = 65535; | |
const LENGTH = 64; | |
const ALGORITHM = 'PBKDF2'; | |
const DIGEST = 'SHA-256'; | |
const DERIVED_KEY = { | |
name: 'AES-CBC', | |
length: 256, | |
} as const; | |
const USAGES = { | |
algorithm: ['deriveBits', 'deriveKey'], | |
digest: ['encrypt', 'decrypt'], | |
} as const; | |
const tob64 = (b: ArrayLike<number> | ArrayBufferLike) => btoa(String.fromCodePoint(...new Uint8Array(b))); | |
const fromb64 = (s: string) => Uint8Array.from(atob(s), (c) => c.charCodeAt(0)); | |
/** | |
* 해시에 필요한 무작위 솔트 생성 | |
*/ | |
export const createSalt = () => crypto.getRandomValues(new Uint8Array(LENGTH)); | |
const keygen = async (passphase: Uint8Array, salt: Uint8Array) => { | |
const key = await crypto.subtle.importKey('raw', passphase, { name: ALGORITHM }, false, USAGES.algorithm); | |
const result = await crypto.subtle.deriveKey( | |
{ | |
name: ALGORITHM, | |
salt, | |
hash: DIGEST, | |
iterations: ITERATIONS, | |
}, | |
key, | |
DERIVED_KEY, | |
true, | |
USAGES.digest | |
); | |
return await crypto.subtle.exportKey('raw', result); | |
}; | |
/** | |
* 비밀번호 해시 생성 | |
* @param password 평문 비밀번호 | |
* @return 해시된 비밀번호 | |
*/ | |
export const createPassword = async (password: string): Promise<{ password: string; salt: string }> => { | |
const salt = createSalt(); | |
return { | |
password: tob64(await keygen(encoder.encode(password), salt))!, | |
salt: tob64(salt)!, | |
}; | |
}; | |
/** | |
* 평문 비밀번호와 실제 비밀번호 비교 | |
* @param hashed 해시된 비밀번호 | |
* @param request 평문 비밀번호 | |
* @param salt 해시에 필요한 솔트 | |
* @return 비교 결과 | |
*/ | |
export const comparePassword = async (hashed: string, request: string, salt: string): Promise<boolean> => { | |
const gensalt = fromb64(salt); | |
return tob64(await keygen(encoder.encode(request), gensalt)) === hashed; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment