Packages
pow
1.0.5
1.0.39
1.0.38
1.0.37
1.0.36
1.0.35
1.0.34
1.0.33
1.0.32
1.0.31
1.0.30
1.0.29
1.0.28
1.0.27
1.0.26
1.0.25
1.0.24
1.0.23
1.0.22
1.0.21
1.0.20
1.0.19
1.0.18
1.0.17
1.0.16
1.0.15
1.0.14
1.0.13
1.0.12
1.0.11
1.0.10
1.0.9
1.0.8
1.0.7
1.0.6
1.0.5
1.0.4
1.0.3
1.0.2
1.0.1
1.0.0
1.0.0-rc.4
1.0.0-rc.3
1.0.0-rc.2
1.0.0-rc.1
1.0.0-rc.0
0.1.0-rc.1
0.1.0-alpha.8
0.1.0-alpha.7
retired
0.1.0-alpha.6
0.1.0-alpha.5
0.1.0-alpha.4
0.1.0-alpha.3
0.1.0-alpha.2
0.1.0-alpha.1
0.1.0-alpha
Robust user authentication solution
Security advisory:
This version has known vulnerabilities.
View advisories
Current section
Files
Jump to
Current section
Files
lib/pow/ecto/schema/password/pbkdf2.ex
defmodule Pow.Ecto.Schema.Password.Pbkdf2 do
@moduledoc """
The Pbkdf2 hash generation code is pulled from
[Plug.Crypto.KeyGenerator](https://github.com/elixir-plug/plug/blob/v1.6.1/lib/plug/crypto/key_generator.ex#L1)
and is under Apache 2 license.
"""
use Bitwise
@doc """
Compares the two binaries in constant-time to avoid timing attacks.
"""
@spec compare(binary(), binary()) :: boolean()
def compare(left, right) when byte_size(left) == byte_size(right) do
compare(left, right, 0) == 0
end
def compare(_hash, _secret_hash), do: false
defp compare(<<x, left::binary>>, <<y, right::binary>>, acc) do
xorred = x ^^^ y
compare(left, right, acc ||| xorred)
end
defp compare(<<>>, <<>>, acc) do
acc
end
@max_length bsl(1, 32) - 1
@doc """
Returns a derived key suitable for use.
"""
@spec generate(binary(), binary(), integer(), integer(), atom()) :: binary()
def generate(secret, salt, iterations, length, digest) do
if length > @max_length do
raise ArgumentError, "length must be less than or equal to #{@max_length}"
else
generate(mac_fun(digest, secret), salt, iterations, length, 1, [], 0)
end
end
defp generate(_fun, _salt, _iterations, max_length, _block_index, acc, length)
when length >= max_length do
acc
|> IO.iodata_to_binary()
|> binary_part(0, max_length)
end
defp generate(fun, salt, iterations, max_length, block_index, acc, length) do
initial = fun.(<<salt::binary, block_index::integer-size(32)>>)
block = iterate(fun, iterations - 1, initial, initial)
generate(
fun,
salt,
iterations,
max_length,
block_index + 1,
[acc | block],
byte_size(block) + length
)
end
defp iterate(_fun, 0, _prev, acc), do: acc
defp iterate(fun, iteration, prev, acc) do
next = fun.(prev)
iterate(fun, iteration - 1, next, :crypto.exor(next, acc))
end
defp mac_fun(digest, secret) do
&:crypto.hmac(digest, secret, &1)
end
end