Current section
Files
Jump to
Current section
Files
src/pinkdf2.gleam
//// Gleam bindings to fast_pbkdf2 NIF of PBKDF2 (Password-Based Key Derivation Function 2) for Erlang.
import gleam/bit_array
pub type Pbkdf2Keys {
Pbkdf2Keys(raw: BitArray, base64: String)
}
pub type ShaDigestSize {
Bits224
Bits256
Bits384
Bits512
}
pub type Pbkdf2Algorithm {
Sha2(ShaDigestSize)
Sha3(ShaDigestSize)
Sha224
Sha256
Sha384
Sha512
}
pub type Pbkdf2Error {
AllocFailed
BadBlockCounter
BadHash
BadIterationCount
BadPassword
BadSalt
CtxAllocationFailed
CtxCopyFailed
DigestFinalFailed
DigestInitFailed
DigestInitEx2Failed
DigestUpdateFailed
HmacInitFailed
}
/// Derives a key from a password and salt with default settings based on the
/// (OWASP recommendations)[https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#pbkdf2].
pub fn with_defaults(
password: String,
salt: String,
) -> Result(Pbkdf2Keys, Pbkdf2Error) {
case fp_defaults(password, salt) {
Ok(raw) -> Ok(Pbkdf2Keys(raw, bit_array.base64_encode(raw, False)))
Error(e) -> Error(e)
}
}
/// Derives a key using the provided configuration.
///
/// `iterations` is the number of times to run the algorithm. Must be a positive integer.
/// `d_len` is the target derived key length in bytes. Must be a positive integer.
///
/// ## Examples
///
/// ```gleam
/// import pinkdf2.{Bits512,Sha2}
///
/// let salt = pinkdf2.get_salt()
/// let assert Ok(key) = pinkdf2.with_config(Sha2(Bits512), "password", salt, 210_000, 32)
/// ```
pub fn with_config(
alg: Pbkdf2Algorithm,
password: String,
salt: String,
iterations: Int,
d_len: Int,
) -> Result(Pbkdf2Keys, Pbkdf2Error) {
case fp_config(alg, password, salt, iterations, d_len) {
Ok(raw) -> Ok(Pbkdf2Keys(raw, bit_array.base64_encode(raw, False)))
Error(e) -> Error(e)
}
}
/// Generates a base64-encoded salt with a minimum size of 64 bytes.
/// It is provided here for convenience, but it is based on the same underlying Erlang function as `crypto.strong_rand_bytes`.
@external(erlang, "extern", "get_salt")
pub fn get_salt() -> String
@external(erlang, "extern", "fp_with_defaults")
fn fp_defaults(password: String, salt: String) -> Result(BitArray, Pbkdf2Error)
@external(erlang, "extern", "fp_with_config")
fn fp_config(
alg: Pbkdf2Algorithm,
password: String,
salt: String,
iterations: Int,
d_len: Int,
) -> Result(BitArray, Pbkdf2Error)