changed README.md
 
@@ -1,39 +1,39 @@
1
- # HKDF
2
-
3
- Provides a simple Hashed Message Authentication Code (HMAC)-based
4
- key derivation function (HKDF).
5
-
6
- Based on the algorithm defined in [rfc 5859](https://tools.ietf.org/html/rfc5869).
7
-
8
- ## Usage
9
-
10
- Derive key:
11
- ```elixir
12
- HKDF.derive(:sha256, "some input", 42, "optional salt", "optional secret message")
13
- ```
14
-
15
- Expand pseudorandom key:
16
- ```elixir
17
- HKDF.extract(:sha256, "some input", "optional salt")
18
- ```
19
-
20
- Extract output key material:
21
- ```elixir
22
- prk = HKDF.extract(:sha256, "some input", "optional salt")
23
- HKDF.expand(:sha256, prk, 16, "optional secret message")
24
- ```
25
-
26
- ## Installation
27
-
28
- If [available in Hex](https://hex.pm/docs/publish), the package can be installed
29
- by adding `hkdf` to your list of dependencies in `mix.exs`:
30
-
31
- ```elixir
32
- def deps do
33
- [{:hkdf, "~> 0.1.0"}]
34
- end
35
- ```
36
-
37
- Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc)
38
- and published on [HexDocs](https://hexdocs.pm). Once published, the docs can
39
- be found at [https://hexdocs.pm/hkdf](https://hexdocs.pm/hkdf).
1
+ # HKDF
2
+
3
+ Provides a simple Hashed Message Authentication Code (HMAC)-based
4
+ key derivation function (HKDF).
5
+
6
+ Based on the algorithm defined in [rfc 5859](https://tools.ietf.org/html/rfc5869).
7
+
8
+ ## Usage
9
+
10
+ Derive key:
11
+ ```elixir
12
+ HKDF.derive(:sha256, "some input", 42, "optional salt", "optional secret message")
13
+ ```
14
+
15
+ Expand pseudorandom key:
16
+ ```elixir
17
+ HKDF.extract(:sha256, "some input", "optional salt")
18
+ ```
19
+
20
+ Extract output key material:
21
+ ```elixir
22
+ prk = HKDF.extract(:sha256, "some input", "optional salt")
23
+ HKDF.expand(:sha256, prk, 16, "optional secret message")
24
+ ```
25
+
26
+ ## Installation
27
+
28
+ If [available in Hex](https://hex.pm/docs/publish), the package can be installed
29
+ by adding `hkdf` to your list of dependencies in `mix.exs`:
30
+
31
+ ```elixir
32
+ def deps do
33
+ [{:hkdf, "~> 0.2.0"}]
34
+ end
35
+ ```
36
+
37
+ Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc)
38
+ and published on [HexDocs](https://hexdocs.pm). Once published, the docs can
39
+ be found at [https://hexdocs.pm/hkdf](https://hexdocs.pm/hkdf).
changed hex_metadata.config
 
@@ -1,11 +1,11 @@
1
1
{<<"app">>,<<"hkdf">>}.
2
2
{<<"build_tools">>,[<<"mix">>]}.
3
3
{<<"description">>,<<"HMAC-based key derivation function.">>}.
4
- {<<"elixir">>,<<"~> 1.4">>}.
5
- {<<"files">>,[<<"lib/hkdf.ex">>,<<"mix.exs">>,<<"README.md">>,<<"LICENSE">>]}.
4
+ {<<"elixir">>,<<"~> 1.13">>}.
5
+ {<<"files">>,
6
+ [<<"lib">>,<<"lib/hkdf.ex">>,<<"mix.exs">>,<<"README.md">>,<<"LICENSE">>]}.
6
7
{<<"licenses">>,[<<"MIT">>]}.
7
- {<<"links">>,[{<<"GitHub">>,<<"https://github.com/sschneider1207/hkdf">>}]}.
8
- {<<"maintainers">>,[<<"Sam Schneider">>]}.
8
+ {<<"links">>,[{<<"GitHub">>,<<"https://github.com/jschneider1207/hkdf">>}]}.
9
9
{<<"name">>,<<"hkdf">>}.
10
10
{<<"requirements">>,[]}.
11
- {<<"version">>,<<"0.1.0">>}.
11
+ {<<"version">>,<<"0.2.0">>}.
changed lib/hkdf.ex
 
@@ -1,101 +1,99 @@
1
- defmodule HKDF do
2
- @moduledoc """
3
- Provides a simple Hashed Message Authentication Code (HMAC)-based
4
- key derivation function (HKDF).
5
-
6
- ## Process
7
-
8
- Keys are derived in two steps:
9
-
10
- 1. Extract - a pseudorandom key is extracted from an input key material
11
- and optional salt.
12
- 2. Expand - an output key material of a specific length is expanded from
13
- hashes of the pseudorandom key and an optional info message.
14
-
15
- ## Source
16
-
17
- Defined in [rfc 5859](https://tools.ietf.org/html/rfc5869)
18
- """
19
- @type hash_fun :: :md5 | :sha | :sha224 | :sha256 | :sha384 | :sha512
20
- @type input_key_material :: binary
21
- @type salt :: binary
22
- @type pseudorandom_key :: binary
23
- @type length :: non_neg_integer
24
- @type info :: binary
25
- @type output_key_material :: binary
26
-
27
- @doc """
28
- Dervice a key of a specific length using the specified hash function.
29
-
30
- An optional salt (extract phase) and/or info message (expand phase)
31
- can be supplied.
32
-
33
- ## Example
34
-
35
- iex> HKDF.derive(:sha256, "some input", 16)
36
- <<47, 231, 129, 75, 82, 47, 198, 78, 55, 31, 167, 66, 15, 128, 63, 243>>
37
-
38
- iex> HKDF.derive(:sha256, "some input", 16, "salt", "secret message")
39
- <<28, 213, 201, 204, 16, 226, 160, 120, 69, 47, 46, 58, 15, 255, 54, 52>>
40
-
41
- """
42
- @spec derive(hash_fun, input_key_material, length, salt, info) :: output_key_material
43
- def derive(hash_fun, ikm, len, salt \\ "", info \\ "") do
44
- prk = extract(hash_fun, ikm, salt)
45
- expand(hash_fun, prk, len, info)
46
- end
47
-
48
- @doc """
49
- Extract a psuedorandom key from an input key material.
50
-
51
- ## Example
52
-
53
- iex> HKDF.extract(:sha256, "some input")
54
- <<130, 6, 35, 29, 160, 13, 100, 90, 127, 71, 104, 2, 139, 88, 204, 124, 201,
55
- 141, 22, 223, 95, 189, 60, 4, 147, 6, 19, 196, 66, 139, 65, 153>>
56
-
57
- iex> HKDF.extract(:sha256, "some input", "salt")
58
- <<165, 68, 136, 223, 19, 149, 73, 161, 172, 133, 175, 129, 14, 46, 132, 27, 219,
59
- 137, 155, 191, 199, 9, 251, 100, 155, 173, 33, 97, 201, 250, 19, 92>>
60
-
61
- """
62
- @spec extract(hash_fun, input_key_material, salt) :: pseudorandom_key
63
- def extract(hash_fun, ikm, salt \\ "") do
64
- :crypto.hmac(hash_fun, salt, ikm)
65
- end
66
-
67
- @doc """
68
- Expands a pseudorandom key to an output key material of a defined length.
69
-
70
- ## Example
71
-
72
- iex(1)> prk = HKDF.extract(:sha256, "some input", "salt")
73
- iex(2)> HKDF.expand(:sha256, prk, 16)
74
- <<227, 13, 8, 99, 198, 12, 203, 171, 124, 253, 132, 131, 59, 202, 95, 24>>
75
-
76
- iex(1)> prk = HKDF.extract(:sha256, "some input", "salt")
77
- iex(2)> HKDF.expand(:sha256, prk, 16, "secret message")
78
- <<28, 213, 201, 204, 16, 226, 160, 120, 69, 47, 46, 58, 15, 255, 54, 52>>
79
-
80
- """
81
- @spec expand(hash_fun, pseudorandom_key, length, info) :: output_key_material
82
- def expand(hash_fun, prk, len, info \\ "") do
83
- hash_len = hash_length(hash_fun)
84
- n = Float.ceil(len/hash_len) |> round()
85
- full =
86
- Enum.scan(1..n, "", fn index, prev ->
87
- data = prev <> info <> <<index>>
88
- :crypto.hmac(hash_fun, prk, data)
89
- end)
90
- |> Enum.reduce("", &Kernel.<>(&2, &1))
91
- <<output :: unit(8)-size(len), _ :: binary>> = full
92
- <<output :: unit(8)-size(len)>>
93
- end
94
-
95
- for fun <- ~w(md5 sha sha224 sha256 sha384 sha512)a do
96
- len = fun |> :crypto.hash("") |> byte_size()
97
- defp hash_length(unquote(fun)) do
98
- unquote(len)
99
- end
100
- end
101
- end
1
+ defmodule HKDF do
2
+ @moduledoc """
3
+ Provides a simple Hashed Message Authentication Code (HMAC)-based
4
+ key derivation function (HKDF).
5
+
6
+ ## Process
7
+
8
+ Keys are derived in two steps:
9
+
10
+ 1. Extract - a pseudorandom key is extracted from an input key material and optional salt.
11
+ 2. Expand - an output key material of a specific length is expanded from hashes of the pseudorandom key and an optional info message.
12
+
13
+ ## Source
14
+
15
+ Defined in [rfc 5859](https://tools.ietf.org/html/rfc5869)
16
+ """
17
+ @type hash_fun :: :md5 | :sha | :sha224 | :sha256 | :sha384 | :sha512
18
+ @type input_key_material :: binary
19
+ @type salt :: binary
20
+ @type pseudorandom_key :: binary
21
+ @type length :: non_neg_integer
22
+ @type info :: binary
23
+ @type output_key_material :: binary
24
+
25
+ @doc """
26
+ Derives a key of a specific length using the specified hash function.
27
+
28
+ An optional salt (extract phase) and/or info message (expand phase)
29
+ can be supplied.
30
+
31
+ ## Example
32
+
33
+ iex> HKDF.derive(:sha256, "some input", 16)
34
+ <<47, 231, 129, 75, 82, 47, 198, 78, 55, 31, 167, 66, 15, 128, 63, 243>>
35
+
36
+ iex> HKDF.derive(:sha256, "some input", 16, "salt", "secret message")
37
+ <<28, 213, 201, 204, 16, 226, 160, 120, 69, 47, 46, 58, 15, 255, 54, 52>>
38
+
39
+ """
40
+ @spec derive(hash_fun, input_key_material, length, salt, info) :: output_key_material
41
+ def derive(hash_fun, ikm, len, salt \\ "", info \\ "") do
42
+ prk = extract(hash_fun, ikm, salt)
43
+ expand(hash_fun, prk, len, info)
44
+ end
45
+
46
+ @doc """
47
+ Extract a psuedorandom key from an input key material.
48
+
49
+ ## Example
50
+
51
+ iex> HKDF.extract(:sha256, "some input")
52
+ <<130, 6, 35, 29, 160, 13, 100, 90, 127, 71, 104, 2, 139, 88, 204, 124, 201,
53
+ 141, 22, 223, 95, 189, 60, 4, 147, 6, 19, 196, 66, 139, 65, 153>>
54
+
55
+ iex> HKDF.extract(:sha256, "some input", "salt")
56
+ <<165, 68, 136, 223, 19, 149, 73, 161, 172, 133, 175, 129, 14, 46, 132, 27, 219,
57
+ 137, 155, 191, 199, 9, 251, 100, 155, 173, 33, 97, 201, 250, 19, 92>>
58
+
59
+ """
60
+ @spec extract(hash_fun, input_key_material, salt) :: pseudorandom_key
61
+ def extract(hash_fun, ikm, salt \\ "") do
62
+ :crypto.mac(:hmac, hash_fun, salt, ikm)
63
+ end
64
+
65
+ @doc """
66
+ Expands a pseudorandom key to an output key material of a defined length.
67
+
68
+ ## Example
69
+
70
+ iex(1)> prk = HKDF.extract(:sha256, "some input", "salt")
71
+ iex(2)> HKDF.expand(:sha256, prk, 16)
72
+ <<227, 13, 8, 99, 198, 12, 203, 171, 124, 253, 132, 131, 59, 202, 95, 24>>
73
+
74
+ iex(1)> prk = HKDF.extract(:sha256, "some input", "salt")
75
+ iex(2)> HKDF.expand(:sha256, prk, 16, "secret message")
76
+ <<28, 213, 201, 204, 16, 226, 160, 120, 69, 47, 46, 58, 15, 255, 54, 52>>
77
+
78
+ """
79
+ @spec expand(hash_fun, pseudorandom_key, length, info) :: output_key_material
80
+ def expand(hash_fun, prk, len, info \\ "") do
81
+ hash_len = hash_length(hash_fun)
82
+ n = Float.ceil(len/hash_len) |> round()
83
+ full =
84
+ Enum.scan(1..n, "", fn index, prev ->
85
+ data = prev <> info <> <<index>>
86
+ :crypto.mac(:hmac, hash_fun, prk, data)
87
+ end)
88
+ |> Enum.reduce("", &Kernel.<>(&2, &1))
89
+ <<output :: unit(8)-size(len), _ :: binary>> = full
90
+ <<output :: unit(8)-size(len)>>
91
+ end
92
+
93
+ for fun <- ~w(md5 sha sha224 sha256 sha384 sha512)a do
94
+ len = fun |> :crypto.hash("") |> byte_size()
95
+ defp hash_length(unquote(fun)) do
96
+ unquote(len)
97
+ end
98
+ end
99
+ end
changed mix.exs
 
@@ -1,40 +1,40 @@
1
- defmodule HKDF.Mixfile do
2
- use Mix.Project
3
-
4
- def project do
5
- [app: :hkdf,
6
- version: "0.1.0",
7
- build_path: "../../_build",
8
- config_path: "../../config/config.exs",
9
- deps_path: "../../deps",
10
- lockfile: "../../mix.lock",
11
- elixir: "~> 1.4",
12
- build_embedded: Mix.env == :prod,
13
- start_permanent: Mix.env == :prod,
14
- description: description(),
15
- package: package(),
16
- deps: deps()]
17
- end
18
-
19
- def application do
20
- [extra_applications: [:logger]]
21
- end
22
-
23
- defp deps do
24
- [{:ex_doc, "~> 0.14.5", only: :dev}]
25
- end
26
-
27
- defp description do
28
- """
29
- HMAC-based key derivation function.
30
- """
31
- end
32
-
33
- defp package do
34
- [name: :hkdf,
35
- files: ["lib", "mix.exs", "README*", "LICENSE*"],
36
- maintainers: ["Sam Schneider"],
37
- licenses: ["MIT"],
38
- links: %{"GitHub" => "https://github.com/sschneider1207/hkdf"}]
39
- end
40
- end
1
+ defmodule HKDF.Mixfile do
2
+ use Mix.Project
3
+
4
+ def project do
5
+ [app: :hkdf,
6
+ version: "0.2.0",
7
+ build_path: "_build",
8
+ config_path: "config/config.exs",
9
+ deps_path: "deps",
10
+ lockfile: "mix.lock",
11
+ elixir: "~> 1.13",
12
+ build_embedded: Mix.env == :prod,
13
+ start_permanent: Mix.env == :prod,
14
+ description: description(),
15
+ package: package(),
16
+ deps: deps()]
17
+ end
18
+
19
+ def application do
20
+ [extra_applications: [:logger, :crypto]]
21
+ end
22
+
23
+ defp deps do
24
+ [{:ex_doc, ">= 0.0.0", only: :dev, runtime: false}]
25
+ end
26
+
27
+ defp description do
28
+ """
29
+ HMAC-based key derivation function.
30
+ """
31
+ end
32
+
33
+ defp package do
34
+ [name: :hkdf,
35
+ files: ["lib", "mix.exs", "README*", "LICENSE*"],
36
+ maintainers: ["Jessica Schneider"],
37
+ licenses: ["MIT"],
38
+ links: %{"GitHub" => "https://github.com/jschneider1207/hkdf"}]
39
+ end
40
+ end