From 96be1470f29b91c4578ec2b3fc531c73e51976d9 Mon Sep 17 00:00:00 2001 From: Ino Murko Date: Sat, 6 Oct 2018 09:50:56 +0200 Subject: [PATCH 1/2] fix dialyzer issues, dependency upgrade, dialyzer check in circle, asdf tool version file --- .circleci/config.yml | 26 ++++++++++++++++++++--- .tool-versions | 2 ++ lib/aes/aes.ex | 12 +++++------ lib/cipher.ex | 4 ++-- lib/ecies/ecdh.ex | 8 ++++---- lib/ecies/ecies.ex | 2 +- lib/ecies/parameters.ex | 6 +++--- lib/exth_crypto.ex | 1 + lib/hash/hash.ex | 42 +++++++++++++++++++++++++++++--------- lib/hash/keccak.ex | 2 +- lib/key/key.ex | 2 +- lib/mac/mac.ex | 2 +- lib/math/math.ex | 4 ++-- lib/signature/signature.ex | 6 +++--- mix.exs | 12 ++++++++--- mix.lock | 5 +++-- 16 files changed, 94 insertions(+), 42 deletions(-) create mode 100644 .tool-versions diff --git a/.circleci/config.yml b/.circleci/config.yml index 29ee23b..e54ddb0 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -13,9 +13,29 @@ jobs: - run: mix local.hex --force - run: mix local.rebar --force - run: mix deps.get - - run: mix test - - run: mix dialyzer + #- run: mix format --check-formatted + - run: + command: mix compile + environment: + MIX_ENV: test + + - restore_cache: + keys: + - v2-plt-cache-{{ arch }}-{{ checksum "mix.lock" }} + - v2-plt-cache-{{ arch }} + - v2-plt-cache + + - run: mix dialyzer --plt + - save_cache: - key: _build + key: v2-plt-cache-{{ arch }}-{{ checksum "mix.lock" }} paths: - _build + - ~/.mix + + - run: mix dialyzer --halt-exit-status + + - save_cache: + key: _build + paths: + - _build \ No newline at end of file diff --git a/.tool-versions b/.tool-versions new file mode 100644 index 0000000..0b14865 --- /dev/null +++ b/.tool-versions @@ -0,0 +1,2 @@ +erlang 21.1 +elixir 1.7-otp-21 diff --git a/lib/aes/aes.ex b/lib/aes/aes.ex index b266fed..0a7fe1c 100644 --- a/lib/aes/aes.ex +++ b/lib/aes/aes.ex @@ -13,7 +13,7 @@ defmodule ExthCrypto.AES do iex> ExthCrypto.AES.block_size 32 """ - @spec block_size :: integer() + @spec block_size :: 32 def block_size, do: @block_size @doc """ @@ -58,7 +58,7 @@ defmodule ExthCrypto.AES do iex> ExthCrypto.AES.encrypt("jedi knight", :ecb, ExthCrypto.Test.symmetric_key) <<98, 60, 215, 107, 189, 132, 176, 63, 62, 225, 92, 13, 70, 53, 187, 240>> """ - @spec encrypt(ExthCrypto.Cipher.plaintext, ExthCrypto.Cipher.mode, ExthCrypto.symmetric_key, ExthCrypto.Cipher.init_vector) :: ExthCrypto.Cipher.ciphertext + @spec encrypt(ExthCrypto.Cipher.plaintext, ExthCrypto.Cipher.mode, ExthCrypto.Key.symmetric_key, ExthCrypto.Cipher.init_vector) :: ExthCrypto.Cipher.ciphertext def encrypt(plaintext, :cbc, symmetric_key, init_vector) do padding_bits = ( 16 - rem(byte_size(plaintext), 16) ) * 8 @@ -73,7 +73,7 @@ defmodule ExthCrypto.AES do ciphertext end - @spec encrypt(ExthCrypto.Cipher.plaintext, ExthCrypto.Cipher.mode, ExthCrypto.symmetric_key) :: ExthCrypto.Cipher.ciphertext + @spec encrypt(ExthCrypto.Cipher.plaintext, ExthCrypto.Cipher.mode, ExthCrypto.Key.symmetric_key) :: ExthCrypto.Cipher.ciphertext def encrypt(plaintext, :ecb, symmetric_key) do padding_bits = ( 16 - rem(byte_size(plaintext), 16) ) * 8 @@ -130,7 +130,7 @@ defmodule ExthCrypto.AES do iex> ExthCrypto.AES.decrypt(<<98, 60, 215, 107, 189, 132, 176, 63, 62, 225, 92, 13, 70, 53, 187, 240>>, :ecb, ExthCrypto.Test.symmetric_key) <<0, 0, 0, 0, 0>> <> "jedi knight" """ - @spec decrypt(ExthCrypto.Cipher.ciphertext, ExthCrypto.Cipher.mode, ExthCrypto.symmetric_key, ExthCrypto.Cipher.init_vector) :: ExthCrypto.Cipher.plaintext + @spec decrypt(ExthCrypto.Cipher.ciphertext, ExthCrypto.Cipher.mode, ExthCrypto.Key.symmetric_key, ExthCrypto.Cipher.init_vector) :: ExthCrypto.Cipher.plaintext def decrypt(ciphertext, :cbc, symmetric_key, init_vector) do :crypto.block_decrypt(:aes_cbc, symmetric_key, init_vector, ciphertext) end @@ -143,7 +143,7 @@ defmodule ExthCrypto.AES do plaintext end - @spec decrypt(ExthCrypto.Cipher.ciphertext, ExthCrypto.Cipher.mode, ExthCrypto.symmetric_key) :: ExthCrypto.Cipher.plaintext + @spec decrypt(ExthCrypto.Cipher.ciphertext, ExthCrypto.Cipher.mode, ExthCrypto.Key.symmetric_key) :: ExthCrypto.Cipher.plaintext def decrypt(ciphertext, :ecb, symmetric_key) do :crypto.block_decrypt(:aes_ecb, symmetric_key, ciphertext) end @@ -192,7 +192,7 @@ defmodule ExthCrypto.AES do iex> plaintext "hello" """ - @spec stream_decrypt(ExthCrypto.Cipher.ciphertext, ExthCrypto.Cipher.stream) :: { ExthCrypto.Cipher.stream, ExthCrypto.Cipher.plaintrxt } + @spec stream_decrypt(ExthCrypto.Cipher.ciphertext, ExthCrypto.Cipher.stream) :: { ExthCrypto.Cipher.stream, ExthCrypto.Cipher.plaintext } def stream_decrypt(plaintext, stream) do :crypto.stream_decrypt(stream, plaintext) end diff --git a/lib/cipher.ex b/lib/cipher.ex index 07b3280..85cb93a 100644 --- a/lib/cipher.ex +++ b/lib/cipher.ex @@ -8,7 +8,7 @@ defmodule ExthCrypto.Cipher do @type plaintext :: iodata() @type ciphertext :: binary() @type init_vector :: binary() - @opaque stream :: :crypto.ctr_state + @type stream :: :crypto.stream_state() @doc """ Encrypts the given plaintext for the given block cipher. @@ -75,7 +75,7 @@ defmodule ExthCrypto.Cipher do iex> ExthCrypto.Cipher.generate_init_vector(32) == ExthCrypto.Cipher.generate_init_vector(32) false """ - @spec generate_init_vector(integer()) :: init_vector + @spec generate_init_vector(non_neg_integer()) :: init_vector def generate_init_vector(block_size) do :crypto.strong_rand_bytes(block_size) end diff --git a/lib/ecies/ecdh.ex b/lib/ecies/ecdh.ex index 646c375..d53ce3e 100644 --- a/lib/ecies/ecdh.ex +++ b/lib/ecies/ecdh.ex @@ -6,13 +6,13 @@ defmodule ExthCrypto.ECIES.ECDH do @default_curve :secp256k1 @doc """ - Generates a new keypair for elliptic curve diffie-hellman. + Generates a new key_pair for elliptic curve diffie-hellman. These keys should be used as ephemeral keys in the key-exchange protocol. ## Examples - iex> {public_key, private_key} = ExthCrypto.ECIES.ECDH.new_ecdh_keypair() + iex> {public_key, private_key} = ExthCrypto.ECIES.ECDH.new_ecdh_key_pair() iex> byte_size(public_key) 65 iex> byte_size(private_key) @@ -20,8 +20,8 @@ defmodule ExthCrypto.ECIES.ECDH do iex> {public_key, private_key} == :crypto.generate_key(:ecdh, :secp256k1, private_key) true """ - @spec new_ecdh_keypair(ExthCrypto.named_curve) :: ExthCrypto.Key.keypair - def new_ecdh_keypair(curve \\ @default_curve) when is_atom(curve) do + @spec new_ecdh_key_pair(ExthCrypto.named_curve) :: ExthCrypto.Key.key_pair + def new_ecdh_key_pair(curve \\ @default_curve) when is_atom(curve) do :crypto.generate_key(:ecdh, curve) end diff --git a/lib/ecies/ecies.ex b/lib/ecies/ecies.ex index 426c4e4..55d37db 100644 --- a/lib/ecies/ecies.ex +++ b/lib/ecies/ecies.ex @@ -46,7 +46,7 @@ defmodule ExthCrypto.ECIES do # First, create a new ephemeral key pair (SEC1 - §5.1.3 - Step 1) {my_ephemeral_public_key, my_ephemeral_private_key} = case my_ephemeral_key_pair do {my_ephemeral_public_key, my_ephemeral_private_key} -> {my_ephemeral_public_key, my_ephemeral_private_key} - nil -> ECDH.new_ecdh_keypair(@curve_name) + nil -> ECDH.new_ecdh_key_pair(@curve_name) end init_vector = if init_vector, do: init_vector, else: Cipher.generate_init_vector(key_len) diff --git a/lib/ecies/parameters.ex b/lib/ecies/parameters.ex index 8bea600..5b9b8cd 100644 --- a/lib/ecies/parameters.ex +++ b/lib/ecies/parameters.ex @@ -16,9 +16,9 @@ defmodule ExthCrypto.ECIES.Parameters do ] @type t :: %__MODULE__{ - mac: :crypto.hash_algorithms, - hasher: ExthCrypto.hash_type, - cipher: ExthCrypto.cipher, + mac: ExthCrypto.Hash.hash_algorithm(), + hasher: ExthCrypto.Hash.hash_type(), + cipher: ExthCrypto.Cipher.cipher(), key_len: integer() } diff --git a/lib/exth_crypto.ex b/lib/exth_crypto.ex index 4fab21f..a93ec7b 100644 --- a/lib/exth_crypto.ex +++ b/lib/exth_crypto.ex @@ -5,5 +5,6 @@ defmodule ExthCrypto do @type curve :: nil @type curve_params :: nil + @type named_curve :: :crypto.ec_named_curve() end diff --git a/lib/hash/hash.ex b/lib/hash/hash.ex index 0e93000..9b5178b 100644 --- a/lib/hash/hash.ex +++ b/lib/hash/hash.ex @@ -4,7 +4,21 @@ defmodule ExthCrypto.Hash do defined by Ethereum. """ - @type hash_algorithm :: atom() + # @type hash_algorithm :: :md4 | :md5 | :sha | :sha224 | :sha256 | :sha384 | :sha512 | :sha3_224 | :sha3_256 | :sha3_384 | :sha3_512 + # @type hash_algorithms :: [:md4 | :md5 | :sha | :sha224 | :sha256 | :sha384 | :sha512 | :sha3_224 | :sha3_256 | :sha3_384 | :sha3_512] + @type hash_algorithm :: + :md4 + | :md5 + | :sha + | :sha224 + | :sha256 + | :sha384 + | :sha3_224 + | :sha3_256 + | :sha3_384 + | :sha3_512 + | :sha512 + @type hash_algorithms :: [hash_algorithm] @type hash :: binary() @type hasher :: (binary() -> binary()) @type hash_type :: {hasher, integer() | nil, integer()} @@ -12,36 +26,44 @@ defmodule ExthCrypto.Hash do @doc """ Returns a list of supported hash algorithms. """ - @hash_algorithms [ :md5, :ripemd160, :sha, :sha224, :sha256, :sha384, :sha512 ] - @spec hash_algorithms() :: [hash_algorithm] + @hash_algorithms [ + :md4, + :md5, + :sha, + :sha224, + :sha256, + :sha384, + :sha512, + :sha3_224, + :sha3_256, + :sha3_384, + :sha3_512 + ] + @spec hash_algorithms() :: nonempty_list(hash_algorithm) def hash_algorithms, do: @hash_algorithms @doc """ The SHA1 hasher. """ - @spec sha1() :: ExthCrypto.hash_type + @spec sha1() :: hash_type def sha1, do: {&ExthCrypto.Hash.SHA.sha1/1, nil, 20} @doc """ The KECCAK hasher, as defined by Ethereum. """ - @spec kec() :: ExCrpyto.hash_type + @spec kec() :: hash_type def kec, do: {&ExthCrypto.Hash.Keccak.kec/1, nil, 256} @doc """ Runs the specified hash type on the given data. - ## Examples - iex> ExthCrypto.Hash.hash("hello world", ExthCrypto.Hash.kec) |> ExthCrypto.Math.bin_to_hex "47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad" - iex> ExthCrypto.Hash.hash("hello world", ExthCrypto.Hash.sha1) |> ExthCrypto.Math.bin_to_hex "2aae6c35c94fcfb415dbe95f408b9ce91ee846ed" """ @spec hash(iodata(), hash_type) :: hash - def hash(data, {hash_fun, _, _}=_hasher) do + def hash(data, {hash_fun, _, _} = _hasher) do hash_fun.(data) end - end \ No newline at end of file diff --git a/lib/hash/keccak.ex b/lib/hash/keccak.ex index 2324c85..abd0c89 100644 --- a/lib/hash/keccak.ex +++ b/lib/hash/keccak.ex @@ -7,7 +7,7 @@ defmodule ExthCrypto.Hash.Keccak do been changed prior to adoption by NIST, but after adoption by Ethereum. """ - @type keccak_hash :: ExthCrypto.hash + @type keccak_hash :: ExthCrypto.Hash.hash() @type keccak_mac :: {atom(), binary()} @doc """ diff --git a/lib/key/key.ex b/lib/key/key.ex index d7fd9f0..a0dc52b 100644 --- a/lib/key/key.ex +++ b/lib/key/key.ex @@ -5,7 +5,7 @@ defmodule ExthCrypto.Key do @type symmetric_key :: binary() @type public_key_der :: binary() - @type public_key :: binary() + @type public_key :: <<_::8, _::_*8>> @type private_key_der :: binary() @type private_key :: binary() @type key_pair :: {public_key, private_key} diff --git a/lib/mac/mac.ex b/lib/mac/mac.ex index 8928757..ee1d74c 100644 --- a/lib/mac/mac.ex +++ b/lib/mac/mac.ex @@ -24,7 +24,7 @@ defmodule ExthCrypto.MAC do iex> ExthCrypto.MAC.mac("The quick brown fox jumps over the lazy dog", "key", :sha256, 8) <<247, 188, 131, 244, 48, 83, 132, 36>> """ - @spec mac(iodata(), iodata(), Hash.hash_algorithm, integer()) :: mac + @spec mac(iodata(), iodata(), Hash.hash_algorithm, integer() | nil) :: mac def mac(data, key, hash_algorithm, length \\ nil) when is_atom(hash_algorithm) do cond do Enum.member?(Hash.hash_algorithms, hash_algorithm) -> diff --git a/lib/math/math.ex b/lib/math/math.ex index c04dc67..d36b7c8 100644 --- a/lib/math/math.ex +++ b/lib/math/math.ex @@ -61,7 +61,7 @@ defmodule ExthCrypto.Math do iex> ExthCrypto.Math.pad(<<>>, 0) <<>> """ - @spec pad(binary(), integer()) :: binary() + @spec pad(binary(), non_neg_integer()) :: binary() def pad(bin, length) do padding_bits = ( length - byte_size(bin) ) * 8 @@ -90,7 +90,7 @@ defmodule ExthCrypto.Math do iex> ExthCrypto.Math.nonce(32) == ExthCrypto.Math.nonce(32) false """ - @spec nonce(integer()) :: binary() + @spec nonce(non_neg_integer()) :: binary() def nonce(nonce_size) do :crypto.strong_rand_bytes(nonce_size) end diff --git a/lib/signature/signature.ex b/lib/signature/signature.ex index 9924e8b..f8b5756 100644 --- a/lib/signature/signature.ex +++ b/lib/signature/signature.ex @@ -8,9 +8,9 @@ defmodule ExthCrypto.Signature do functionality. """ - @type signature :: binary() - @type r :: integer() - @type s :: integer() + @type signature :: <<_::512>> + @type r :: non_neg_integer() + @type s :: non_neg_integer() @type recovery_id :: integer() @doc """ diff --git a/mix.exs b/mix.exs index 8e6ec1b..08fe38b 100644 --- a/mix.exs +++ b/mix.exs @@ -13,7 +13,13 @@ defmodule ExthCrypto.Mixfile do ], build_embedded: Mix.env == :prod, start_permanent: Mix.env == :prod, - deps: deps()] + deps: deps(), + dialyzer: [ + flags: [:underspecs, :unknown, :unmatched_returns], + plt_add_apps: [:mix, :iex, :logger], + plt_add_deps: :transitive + ] + ] end # Configuration for the OTP application @@ -37,9 +43,9 @@ defmodule ExthCrypto.Mixfile do [ {:libsecp256k1, "~> 0.1.9"}, {:keccakf1600, "~> 2.0.0", hex: :keccakf1600_orig}, - {:credo, "~> 0.8", only: [:dev, :test], runtime: false}, + {:credo, "~> 0.10.2", only: [:dev, :test], runtime: false}, {:ex_doc, "~> 0.17", only: :dev, runtime: false}, - {:dialyxir, "~> 0.5", only: [:dev], runtime: false}, + {:dialyxir, "~> 1.0.0-rc.3", only: [:dev], runtime: false}, {:binary, "~> 0.0.4"}, ] end diff --git a/mix.lock b/mix.lock index ffdd341..fa53470 100644 --- a/mix.lock +++ b/mix.lock @@ -1,10 +1,11 @@ %{ "binary": {:hex, :binary, "0.0.4", "dd077db70c0ded3e85c132b802338e14b80694684a7e2277666bfa4004b7fa66", [:mix], [], "hexpm"}, "bunt": {:hex, :bunt, "0.2.0", "951c6e801e8b1d2cbe58ebbd3e616a869061ddadcc4863d0a2182541acae9a38", [:mix], [], "hexpm"}, - "credo": {:hex, :credo, "0.8.6", "335f723772d35da499b5ebfdaf6b426bfb73590b6fcbc8908d476b75f8cbca3f", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}], "hexpm"}, - "dialyxir": {:hex, :dialyxir, "0.5.1", "b331b091720fd93e878137add264bac4f644e1ddae07a70bf7062c7862c4b952", [:mix], [], "hexpm"}, + "credo": {:hex, :credo, "0.10.2", "03ad3a1eff79a16664ed42fc2975b5e5d0ce243d69318060c626c34720a49512", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm"}, + "dialyxir": {:hex, :dialyxir, "1.0.0-rc.3", "774306f84973fc3f1e2e8743eeaa5f5d29b117f3916e5de74c075c02f1b8ef55", [:mix], [], "hexpm"}, "earmark": {:hex, :earmark, "1.2.5", "4d21980d5d2862a2e13ec3c49ad9ad783ffc7ca5769cf6ff891a4553fbaae761", [:mix], [], "hexpm"}, "ex_doc": {:hex, :ex_doc, "0.19.1", "519bb9c19526ca51d326c060cb1778d4a9056b190086a8c6c115828eaccea6cf", [:mix], [{:earmark, "~> 1.1", [hex: :earmark, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.7", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm"}, + "jason": {:hex, :jason, "1.1.1", "d3ccb840dfb06f2f90a6d335b536dd074db748b3e7f5b11ab61d239506585eb2", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm"}, "keccakf1600": {:hex, :keccakf1600_orig, "2.0.0", "0a7217ddb3ee8220d449bbf7575ec39d4e967099f220a91e3dfca4dbaef91963", [:rebar3], [], "hexpm"}, "libsecp256k1": {:hex, :libsecp256k1, "0.1.9", "e725f31364cda7b554d56ce2bb976241303dde5ffd1ad59598513297bf1f2af6", [:make, :mix], [{:mix_erlang_tasks, "0.1.0", [hex: :mix_erlang_tasks, repo: "hexpm", optional: false]}], "hexpm"}, "makeup": {:hex, :makeup, "0.5.1", "966c5c2296da272d42f1de178c1d135e432662eca795d6dc12e5e8787514edf7", [:mix], [{:nimble_parsec, "~> 0.2.2", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm"}, From 5af072d846fb135cbdad1e7f19554a645878804b Mon Sep 17 00:00:00 2001 From: Ino Murko Date: Sat, 6 Oct 2018 09:57:50 +0200 Subject: [PATCH 2/2] formatter file, formatted all files and enabled circle formatter check --- .circleci/config.yml | 2 +- .formatter.exs | 3 + lib/aes/aes.ex | 54 +++++++++++---- lib/cipher.ex | 10 +-- lib/ecies/ecdh.ex | 13 ++-- lib/ecies/ecies.ex | 110 ++++++++++++++++++++++-------- lib/ecies/parameters.ex | 38 +++++------ lib/exth_crypto.ex | 1 - lib/hash/fake.ex | 3 +- lib/hash/hash.ex | 2 +- lib/hash/keccak.ex | 3 +- lib/hash/sha.ex | 2 +- lib/kdf/nist_sp_800_56.ex | 40 +++++++---- lib/key/key.ex | 3 +- lib/mac/mac.ex | 9 +-- lib/math/math.ex | 13 ++-- lib/signature/signature.ex | 16 +++-- lib/test.ex | 68 ++++++++++-------- mix.exs | 19 +++--- test/aes/aes_test.exs | 3 +- test/cipher_test.exs | 3 +- test/ecies/ecdh_test.exs | 3 +- test/ecies/ecies_test.exs | 3 +- test/ecies/parameters_test.exs | 3 +- test/hash/fake_test.exs | 3 +- test/hash/keccak_test.exs | 3 +- test/hash/sha_test.exs | 3 +- test/hash_test.exs | 3 +- test/kdf/nist_sp_800_65_test.exs | 3 +- test/mac/mac_test.exs | 3 +- test/math/math_test.exs | 3 +- test/signature/signature_test.exs | 3 +- 32 files changed, 274 insertions(+), 174 deletions(-) create mode 100644 .formatter.exs diff --git a/.circleci/config.yml b/.circleci/config.yml index e54ddb0..95ef043 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -13,7 +13,7 @@ jobs: - run: mix local.hex --force - run: mix local.rebar --force - run: mix deps.get - #- run: mix format --check-formatted + - run: mix format --check-formatted - run: command: mix compile environment: diff --git a/.formatter.exs b/.formatter.exs new file mode 100644 index 0000000..55d3bcc --- /dev/null +++ b/.formatter.exs @@ -0,0 +1,3 @@ +[ + inputs: ["mix.exs", "{config,lib,test}/**/*.{ex,exs}"] +] \ No newline at end of file diff --git a/lib/aes/aes.ex b/lib/aes/aes.ex index 0a7fe1c..3ad92d4 100644 --- a/lib/aes/aes.ex +++ b/lib/aes/aes.ex @@ -58,11 +58,21 @@ defmodule ExthCrypto.AES do iex> ExthCrypto.AES.encrypt("jedi knight", :ecb, ExthCrypto.Test.symmetric_key) <<98, 60, 215, 107, 189, 132, 176, 63, 62, 225, 92, 13, 70, 53, 187, 240>> """ - @spec encrypt(ExthCrypto.Cipher.plaintext, ExthCrypto.Cipher.mode, ExthCrypto.Key.symmetric_key, ExthCrypto.Cipher.init_vector) :: ExthCrypto.Cipher.ciphertext + @spec encrypt( + ExthCrypto.Cipher.plaintext(), + ExthCrypto.Cipher.mode(), + ExthCrypto.Key.symmetric_key(), + ExthCrypto.Cipher.init_vector() + ) :: ExthCrypto.Cipher.ciphertext() def encrypt(plaintext, :cbc, symmetric_key, init_vector) do - padding_bits = ( 16 - rem(byte_size(plaintext), 16) ) * 8 - - :crypto.block_encrypt(:aes_cbc, symmetric_key, init_vector, <<0::size(padding_bits)>> <> plaintext) + padding_bits = (16 - rem(byte_size(plaintext), 16)) * 8 + + :crypto.block_encrypt( + :aes_cbc, + symmetric_key, + init_vector, + <<0::size(padding_bits)>> <> plaintext + ) end def encrypt(plaintext, :ctr, symmetric_key, init_vector) do @@ -73,9 +83,13 @@ defmodule ExthCrypto.AES do ciphertext end - @spec encrypt(ExthCrypto.Cipher.plaintext, ExthCrypto.Cipher.mode, ExthCrypto.Key.symmetric_key) :: ExthCrypto.Cipher.ciphertext + @spec encrypt( + ExthCrypto.Cipher.plaintext(), + ExthCrypto.Cipher.mode(), + ExthCrypto.Key.symmetric_key() + ) :: ExthCrypto.Cipher.ciphertext() def encrypt(plaintext, :ecb, symmetric_key) do - padding_bits = ( 16 - rem(byte_size(plaintext), 16) ) * 8 + padding_bits = (16 - rem(byte_size(plaintext), 16)) * 8 :crypto.block_encrypt(:aes_ecb, symmetric_key, <<0::size(padding_bits)>> <> plaintext) end @@ -130,7 +144,12 @@ defmodule ExthCrypto.AES do iex> ExthCrypto.AES.decrypt(<<98, 60, 215, 107, 189, 132, 176, 63, 62, 225, 92, 13, 70, 53, 187, 240>>, :ecb, ExthCrypto.Test.symmetric_key) <<0, 0, 0, 0, 0>> <> "jedi knight" """ - @spec decrypt(ExthCrypto.Cipher.ciphertext, ExthCrypto.Cipher.mode, ExthCrypto.Key.symmetric_key, ExthCrypto.Cipher.init_vector) :: ExthCrypto.Cipher.plaintext + @spec decrypt( + ExthCrypto.Cipher.ciphertext(), + ExthCrypto.Cipher.mode(), + ExthCrypto.Key.symmetric_key(), + ExthCrypto.Cipher.init_vector() + ) :: ExthCrypto.Cipher.plaintext() def decrypt(ciphertext, :cbc, symmetric_key, init_vector) do :crypto.block_decrypt(:aes_cbc, symmetric_key, init_vector, ciphertext) end @@ -143,7 +162,11 @@ defmodule ExthCrypto.AES do plaintext end - @spec decrypt(ExthCrypto.Cipher.ciphertext, ExthCrypto.Cipher.mode, ExthCrypto.Key.symmetric_key) :: ExthCrypto.Cipher.plaintext + @spec decrypt( + ExthCrypto.Cipher.ciphertext(), + ExthCrypto.Cipher.mode(), + ExthCrypto.Key.symmetric_key() + ) :: ExthCrypto.Cipher.plaintext() def decrypt(ciphertext, :ecb, symmetric_key) do :crypto.block_decrypt(:aes_ecb, symmetric_key, ciphertext) end @@ -158,7 +181,11 @@ defmodule ExthCrypto.AES do iex> is_nil(stream) false """ - @spec stream_init(ExthCrypto.Cipher.mode, ExthCrypto.Key.symmetric_key, ExthCrypto.Cipher.init_vector) :: ExthCrypto.Cipher.stream + @spec stream_init( + ExthCrypto.Cipher.mode(), + ExthCrypto.Key.symmetric_key(), + ExthCrypto.Cipher.init_vector() + ) :: ExthCrypto.Cipher.stream() def stream_init(:ctr, symmetric_key, init_vector) do # IO.inspect(["Have symm key: ", symmetric_key]) :crypto.stream_init(:aes_ctr, symmetric_key, init_vector) @@ -175,7 +202,8 @@ defmodule ExthCrypto.AES do iex> ciphertext "'d plaintext "hello" """ - @spec stream_decrypt(ExthCrypto.Cipher.ciphertext, ExthCrypto.Cipher.stream) :: { ExthCrypto.Cipher.stream, ExthCrypto.Cipher.plaintext } + @spec stream_decrypt(ExthCrypto.Cipher.ciphertext(), ExthCrypto.Cipher.stream()) :: + {ExthCrypto.Cipher.stream(), ExthCrypto.Cipher.plaintext()} def stream_decrypt(plaintext, stream) do :crypto.stream_decrypt(stream, plaintext) end - -end \ No newline at end of file +end diff --git a/lib/cipher.ex b/lib/cipher.ex index 85cb93a..bc9efd7 100644 --- a/lib/cipher.ex +++ b/lib/cipher.ex @@ -24,12 +24,12 @@ defmodule ExthCrypto.Cipher do iex> ExthCrypto.Cipher.encrypt("execute order 66", ExthCrypto.Test.symmetric_key, {ExthCrypto.AES, ExthCrypto.AES.block_size, :ecb}) |> ExthCrypto.Math.bin_to_hex "a73c5576667b7b43a23a9fd930b5465d637a44d08bf702881a8d4e6a5d4944b5" """ - @spec encrypt(plaintext, ExthCrypto.Key.symmetric_key, init_vector, cipher) :: ciphertext + @spec encrypt(plaintext, ExthCrypto.Key.symmetric_key(), init_vector, cipher) :: ciphertext def encrypt(plaintext, symmetric_key, init_vector, {mod, _block_size, mode} = _cipher) do mod.encrypt(plaintext, mode, symmetric_key, init_vector) end - @spec encrypt(plaintext, ExthCrypto.Key.symmetric_key, cipher) :: ciphertext + @spec encrypt(plaintext, ExthCrypto.Key.symmetric_key(), cipher) :: ciphertext def encrypt(plaintext, symmetric_key, {mod, _block_size, mode} = _cipher) do mod.encrypt(plaintext, mode, symmetric_key) end @@ -54,12 +54,12 @@ defmodule ExthCrypto.Cipher do ...> |> ExthCrypto.Cipher.decrypt(ExthCrypto.Test.symmetric_key, {ExthCrypto.AES, ExthCrypto.AES.block_size, :ecb}) <<0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0>> <> "execute order 66" """ - @spec decrypt(ciphertext, ExthCrypto.Key.symmetric_key, init_vector, cipher) :: plaintext + @spec decrypt(ciphertext, ExthCrypto.Key.symmetric_key(), init_vector, cipher) :: plaintext def decrypt(ciphertext, symmetric_key, init_vector, {mod, _block_size, mode} = _cipher) do mod.decrypt(ciphertext, mode, symmetric_key, init_vector) end - @spec decrypt(ciphertext, ExthCrypto.Key.symmetric_key, cipher) :: plaintext + @spec decrypt(ciphertext, ExthCrypto.Key.symmetric_key(), cipher) :: plaintext def decrypt(ciphertext, symmetric_key, {mod, _block_size, mode} = _cipher) do mod.decrypt(ciphertext, mode, symmetric_key) end @@ -79,4 +79,4 @@ defmodule ExthCrypto.Cipher do def generate_init_vector(block_size) do :crypto.strong_rand_bytes(block_size) end -end \ No newline at end of file +end diff --git a/lib/ecies/ecdh.ex b/lib/ecies/ecdh.ex index d53ce3e..c6081f2 100644 --- a/lib/ecies/ecdh.ex +++ b/lib/ecies/ecdh.ex @@ -20,7 +20,7 @@ defmodule ExthCrypto.ECIES.ECDH do iex> {public_key, private_key} == :crypto.generate_key(:ecdh, :secp256k1, private_key) true """ - @spec new_ecdh_key_pair(ExthCrypto.named_curve) :: ExthCrypto.Key.key_pair + @spec new_ecdh_key_pair(ExthCrypto.named_curve()) :: ExthCrypto.Key.key_pair() def new_ecdh_key_pair(curve \\ @default_curve) when is_atom(curve) do :crypto.generate_key(:ecdh, curve) end @@ -37,8 +37,13 @@ defmodule ExthCrypto.ECIES.ECDH do iex> ExthCrypto.ECIES.ECDH.generate_shared_secret(ExthCrypto.Test.private_key(:key_a), ExthCrypto.Test.public_key(:key_b), :secp256k1) <<68, 139, 102, 172, 32, 159, 198, 236, 33, 216, 132, 22, 62, 46, 163, 215, 53, 40, 177, 14, 51, 94, 155, 151, 21, 226, 9, 254, 153, 48, 112, 226>> """ - @spec generate_shared_secret(ExthCrypto.Key.private_key, ExthCrypto.Key.public_key, ExthCrypto.named_curve) :: binary() - def generate_shared_secret(local_private_key, remote_public_key, curve \\ @default_curve) when is_atom(curve) do + @spec generate_shared_secret( + ExthCrypto.Key.private_key(), + ExthCrypto.Key.public_key(), + ExthCrypto.named_curve() + ) :: binary() + def generate_shared_secret(local_private_key, remote_public_key, curve \\ @default_curve) + when is_atom(curve) do :crypto.compute_key(:ecdh, remote_public_key, local_private_key, curve) end -end \ No newline at end of file +end diff --git a/lib/ecies/ecies.ex b/lib/ecies/ecies.ex index 55d37db..37b4876 100644 --- a/lib/ecies/ecies.ex +++ b/lib/ecies/ecies.ex @@ -38,16 +38,35 @@ defmodule ExthCrypto.ECIES do # TODO: More tests """ - @spec encrypt(ExthCrypto.Key.public_key, Cipher.plaintext, binary(), binary(), {ExthCrypto.Key.public_key, ExthCrypto.Key.private_key} | nil, Cipher.init_vector | nil) :: {:ok, binary()} | {:error, String.t} - def encrypt(her_static_public_key, message, shared_info_1 \\ <<>>, shared_info_2 \\ <<>>, my_ephemeral_key_pair \\ nil, init_vector \\ nil) do - params = Parameters.ecies_aes128_sha256() # Question, is this always the parameters? If not, how do we choose? + @spec encrypt( + ExthCrypto.Key.public_key(), + Cipher.plaintext(), + binary(), + binary(), + {ExthCrypto.Key.public_key(), ExthCrypto.Key.private_key()} | nil, + Cipher.init_vector() | nil + ) :: {:ok, binary()} | {:error, String.t()} + def encrypt( + her_static_public_key, + message, + shared_info_1 \\ <<>>, + shared_info_2 \\ <<>>, + my_ephemeral_key_pair \\ nil, + init_vector \\ nil + ) do + # Question, is this always the parameters? If not, how do we choose? + params = Parameters.ecies_aes128_sha256() key_len = params.key_len # First, create a new ephemeral key pair (SEC1 - §5.1.3 - Step 1) - {my_ephemeral_public_key, my_ephemeral_private_key} = case my_ephemeral_key_pair do - {my_ephemeral_public_key, my_ephemeral_private_key} -> {my_ephemeral_public_key, my_ephemeral_private_key} - nil -> ECDH.new_ecdh_key_pair(@curve_name) - end + {my_ephemeral_public_key, my_ephemeral_private_key} = + case my_ephemeral_key_pair do + {my_ephemeral_public_key, my_ephemeral_private_key} -> + {my_ephemeral_public_key, my_ephemeral_private_key} + + nil -> + ECDH.new_ecdh_key_pair(@curve_name) + end init_vector = if init_vector, do: init_vector, else: Cipher.generate_init_vector(key_len) @@ -56,11 +75,18 @@ defmodule ExthCrypto.ECIES do # SEC1 - §5.1.3 - Steps 3, 4 # Next, generate our ECDH shared secret (no co-factor) - shared_secret = ECDH.generate_shared_secret(my_ephemeral_private_key, her_static_public_key, @curve_name) + shared_secret = + ECDH.generate_shared_secret(my_ephemeral_private_key, her_static_public_key, @curve_name) # Next, derive a KDF twice the length as needed, with shared_info_1 as the extra_data # SEC1 - §5.1.3 - Step 5 - kdf = ExthCrypto.KDF.NistSp80056.single_step_kdf(shared_secret, 2 * params.key_len, params.hasher, shared_info_1) + kdf = + ExthCrypto.KDF.NistSp80056.single_step_kdf( + shared_secret, + 2 * params.key_len, + params.hasher, + shared_info_1 + ) # The first half becomes the encoded key, the second half becomes a mac with {:ok, derived_keys} <- kdf do @@ -75,13 +101,15 @@ defmodule ExthCrypto.ECIES do key_mac_hashed = Hash.hash(key_mac, params.hasher) # Tag the messsage and shared_info_2 data - message_tag = MAC.mac(init_vector <> encoded_message <> shared_info_2, key_mac_hashed, params.mac) + message_tag = + MAC.mac(init_vector <> encoded_message <> shared_info_2, key_mac_hashed, params.mac) # Remove DER encoding byte my_ephemeral_public_key_raw = ExthCrypto.Key.der_to_raw(my_ephemeral_public_key) # return 0x04 || R || AsymmetricEncrypt(shared-secret, plaintext) || tag - {:ok, <<0x04>> <> my_ephemeral_public_key_raw <> init_vector <> encoded_message <> message_tag} + {:ok, + <<0x04>> <> my_ephemeral_public_key_raw <> init_vector <> encoded_message <> message_tag} end end @@ -104,9 +132,16 @@ defmodule ExthCrypto.ECIES do iex> ExthCrypto.ECIES.decrypt(ExthCrypto.Test.private_key(:key_a), ecies_encoded_msg, "shared_info_1", "shared_info_2") {:ok, "hello"} """ - @spec decrypt(ExthCrypto.Key.private_key, binary(), binary(), binary()) :: {:ok, Cipher.plaintext} | {:error, String.t} - def decrypt(my_static_private_key, ecies_encoded_msg, shared_info_1 \\ <<>>, shared_info_2 \\ <<>>) do - params = Parameters.ecies_aes128_sha256() # Question, is this always the parameters? If not, how do we choose? + @spec decrypt(ExthCrypto.Key.private_key(), binary(), binary(), binary()) :: + {:ok, Cipher.plaintext()} | {:error, String.t()} + def decrypt( + my_static_private_key, + ecies_encoded_msg, + shared_info_1 \\ <<>>, + shared_info_2 \\ <<>> + ) do + # Question, is this always the parameters? If not, how do we choose? + params = Parameters.ecies_aes128_sha256() # Get size of key len, block size and hash len, all in bits header_size = 1 @@ -115,34 +150,51 @@ defmodule ExthCrypto.ECIES do private_key_len = byte_size(my_static_private_key) public_key_len = private_key_len * 2 hash_len = Parameters.hash_len(params) - encoded_message_len = byte_size(ecies_encoded_msg) - header_size - public_key_len - key_len - hash_len + + encoded_message_len = + byte_size(ecies_encoded_msg) - header_size - public_key_len - key_len - hash_len # Decode the ECIES encoded message case ecies_encoded_msg do # SEC1 - §5.1.4 - Step 1 # Note, we only allow 0x04 as the header byte << - 0x04::size(header_size_bits), # header - her_ephemeral_public_key_raw::binary-size(public_key_len), # public key - cipher_iv::binary-size(key_len), # cipher iv - encoded_message::binary-size(encoded_message_len), # encoded_message - message_tag::binary-size(hash_len)>> -> # message tag - + # header + 0x04::size(header_size_bits), + # public key + her_ephemeral_public_key_raw::binary-size(public_key_len), + # cipher iv + cipher_iv::binary-size(key_len), + # encoded_message + encoded_message::binary-size(encoded_message_len), + # message tag + message_tag::binary-size(hash_len) + >> -> # TODO: SEC1 - §5.1.4 - Steps 2, 3 - Verify curve # SEC1 - §5.1.4 - Steps 4, 5 # Generate a shared secret based on our ephemeral private key and the ephemeral public key from the message her_ephemeral_public_key = ExthCrypto.Key.raw_to_der(her_ephemeral_public_key_raw) - shared_secret = ECDH.generate_shared_secret(my_static_private_key, her_ephemeral_public_key, @curve_name) + shared_secret = + ECDH.generate_shared_secret( + my_static_private_key, + her_ephemeral_public_key, + @curve_name + ) # SEC1 - §5.1.4 - Step 6 # Geneate our KDF as before - kdf = ExthCrypto.KDF.NistSp80056.single_step_kdf(shared_secret, 2 * params.key_len, params.hasher, shared_info_1) + kdf = + ExthCrypto.KDF.NistSp80056.single_step_kdf( + shared_secret, + 2 * params.key_len, + params.hasher, + shared_info_1 + ) # The first half becomes the encoded key, the second half becomes a mac with {:ok, derived_keys} <- kdf do - # SEC1 - §5.1.4 - Step 7 <> = derived_keys @@ -151,7 +203,8 @@ defmodule ExthCrypto.ECIES do # SEC1 - §5.1.4 - Step 8 # Tag the messsage and shared_info_2 data - generated_message_tag = MAC.mac(cipher_iv <> encoded_message <> shared_info_2, key_mac_hashed, params.mac) + generated_message_tag = + MAC.mac(cipher_iv <> encoded_message <> shared_info_2, key_mac_hashed, params.mac) unless message_tag == generated_message_tag do {:error, "Invalid message tag"} @@ -163,8 +216,9 @@ defmodule ExthCrypto.ECIES do {:ok, message} end end - _els -> {:error, "Invalid ECIES encoded message"} + + _els -> + {:error, "Invalid ECIES encoded message"} end end - -end \ No newline at end of file +end diff --git a/lib/ecies/parameters.ex b/lib/ecies/parameters.ex index 5b9b8cd..0da024a 100644 --- a/lib/ecies/parameters.ex +++ b/lib/ecies/parameters.ex @@ -8,19 +8,17 @@ defmodule ExthCrypto.ECIES.Parameters do * ECIES using AES256 and HMAC-SHA-512-64 """ - defstruct [ - mac: nil, - hasher: nil, - cipher: nil, - key_len: nil - ] + defstruct mac: nil, + hasher: nil, + cipher: nil, + key_len: nil @type t :: %__MODULE__{ - mac: ExthCrypto.Hash.hash_algorithm(), - hasher: ExthCrypto.Hash.hash_type(), - cipher: ExthCrypto.Cipher.cipher(), - key_len: integer() - } + mac: ExthCrypto.Hash.hash_algorithm(), + hasher: ExthCrypto.Hash.hash_type(), + cipher: ExthCrypto.Cipher.cipher(), + key_len: integer() + } @doc """ Returns curve parameters for ECIES with AES-256 symmetric @@ -31,8 +29,8 @@ defmodule ExthCrypto.ECIES.Parameters do %__MODULE__{ mac: :sha256, hasher: {&ExthCrypto.Hash.SHA.sha256/1, nil, 32}, - cipher: {ExthCrypto.AES, ExthCrypto.AES.block_size, :ctr}, - key_len: 16, + cipher: {ExthCrypto.AES, ExthCrypto.AES.block_size(), :ctr}, + key_len: 16 } end @@ -45,8 +43,8 @@ defmodule ExthCrypto.ECIES.Parameters do %__MODULE__{ mac: :sha256, hasher: {&ExthCrypto.Hash.SHA.sha256/1, nil, 32}, - cipher: {ExthCrypto.AES, ExthCrypto.AES.block_size, :ctr}, - key_len: 32, + cipher: {ExthCrypto.AES, ExthCrypto.AES.block_size(), :ctr}, + key_len: 32 } end @@ -59,8 +57,8 @@ defmodule ExthCrypto.ECIES.Parameters do %__MODULE__{ mac: :sha256, hasher: {&ExthCrypto.Hash.SHA.sha384/1, nil, 48}, - cipher: {ExthCrypto.AES, ExthCrypto.AES.block_size, :ctr}, - key_len: 32, + cipher: {ExthCrypto.AES, ExthCrypto.AES.block_size(), :ctr}, + key_len: 32 } end @@ -73,8 +71,8 @@ defmodule ExthCrypto.ECIES.Parameters do %__MODULE__{ mac: :sha256, hasher: {&ExthCrypto.Hash.SHA.sha512/1, nil, 64}, - cipher: {ExthCrypto.AES, ExthCrypto.AES.block_size, :ctr}, - key_len: 32, + cipher: {ExthCrypto.AES, ExthCrypto.AES.block_size(), :ctr}, + key_len: 32 } end @@ -111,4 +109,4 @@ defmodule ExthCrypto.ECIES.Parameters do hash_len end -end \ No newline at end of file +end diff --git a/lib/exth_crypto.ex b/lib/exth_crypto.ex index a93ec7b..e35157b 100644 --- a/lib/exth_crypto.ex +++ b/lib/exth_crypto.ex @@ -6,5 +6,4 @@ defmodule ExthCrypto do @type curve :: nil @type curve_params :: nil @type named_curve :: :crypto.ec_named_curve() - end diff --git a/lib/hash/fake.ex b/lib/hash/fake.ex index 18a79a6..a7bddfb 100644 --- a/lib/hash/fake.ex +++ b/lib/hash/fake.ex @@ -51,5 +51,4 @@ defmodule ExthCrypto.Hash.Fake do def final_mac({:fake_mac, mac}) do mac end - -end \ No newline at end of file +end diff --git a/lib/hash/hash.ex b/lib/hash/hash.ex index 9b5178b..c27b86c 100644 --- a/lib/hash/hash.ex +++ b/lib/hash/hash.ex @@ -66,4 +66,4 @@ defmodule ExthCrypto.Hash do def hash(data, {hash_fun, _, _} = _hasher) do hash_fun.(data) end -end \ No newline at end of file +end diff --git a/lib/hash/keccak.ex b/lib/hash/keccak.ex index abd0c89..ae304e5 100644 --- a/lib/hash/keccak.ex +++ b/lib/hash/keccak.ex @@ -76,5 +76,4 @@ defmodule ExthCrypto.Hash.Keccak do def final_mac(mac) do :keccakf1600.final(mac) end - -end \ No newline at end of file +end diff --git a/lib/hash/sha.ex b/lib/hash/sha.ex index 0ee92b5..ed6a0b4 100644 --- a/lib/hash/sha.ex +++ b/lib/hash/sha.ex @@ -57,4 +57,4 @@ defmodule ExthCrypto.Hash.SHA do def sha512(data) do :crypto.hash(:sha512, data) end -end \ No newline at end of file +end diff --git a/lib/kdf/nist_sp_800_56.ex b/lib/kdf/nist_sp_800_56.ex index 14a7124..048b6e8 100644 --- a/lib/kdf/nist_sp_800_56.ex +++ b/lib/kdf/nist_sp_800_56.ex @@ -36,28 +36,44 @@ defmodule ExthCrypto.KDF.NistSp80056 do iex> ExthCrypto.Math.bin_to_hex(key) "23e991a801f83685ea6999e23eb528d199eff129109dd8db0f844474ce981462fca2dc108bde378d83d9e714a9964d9cd9b1364a167d98fbfe1f94bc6f606879f9150be2979fe27812b7de86546e1994672038b9493abfb4b959676b5927c75dd9f33489f865a71905100633412d9ae93677ca6b4b3646310550252cf1c30da0f9014c72728a66ce20489ec89c718231f163a359a282ff8f73b65e129a1980e130d58cb88d3b041eb29ea69561f0b24b80cb7f421042edf07374bfa553be44ee6b5bf4459de8ef2a" """ - @spec single_step_kdf(binary(), integer(), ExthCrypto.Hash.hash_type, binary()) :: {:ok, binary()} | {:error, String.t} - def single_step_kdf(shared_secret, key_data_len, {hasher, hash_in_max_len, hash_out_len}, extra_data \\ <<>>) do + @spec single_step_kdf(binary(), integer(), ExthCrypto.Hash.hash_type(), binary()) :: + {:ok, binary()} | {:error, String.t()} + def single_step_kdf( + shared_secret, + key_data_len, + {hasher, hash_in_max_len, hash_out_len}, + extra_data \\ <<>> + ) do # ((key_len + 7) * 8) / (hash_blocksize * 8) reps = round(:math.ceil(key_data_len / hash_out_len)) key_data_len_bits = key_data_len * 8 cond do - key_data_len_bits > hash_out_len * @max_32_int -> {:error, "Key data is too large"} - reps > @max_32_int -> {:error, "Too many reps required"} - not is_nil(hash_in_max_len) and byte_size(shared_secret <> extra_data) + 4 > hash_in_max_len -> {:error, "Concatenation of counter, shared_secret and extra_data too large"} + key_data_len_bits > hash_out_len * @max_32_int -> + {:error, "Key data is too large"} + + reps > @max_32_int -> + {:error, "Too many reps required"} + + not is_nil(hash_in_max_len) and byte_size(shared_secret <> extra_data) + 4 > hash_in_max_len -> + {:error, "Concatenation of counter, shared_secret and extra_data too large"} + true -> - derived_keying_material_padded = Enum.reduce(1..reps, <<>>, fn counter, results -> - counter_enc = :binary.encode_unsigned(counter |> mod(@two_power_32), :big) |> ExthCrypto.Math.pad(4) + derived_keying_material_padded = + Enum.reduce(1..reps, <<>>, fn counter, results -> + counter_enc = + :binary.encode_unsigned(counter |> mod(@two_power_32), :big) + |> ExthCrypto.Math.pad(4) - result = hasher.(counter_enc <> shared_secret <> extra_data) + result = hasher.(counter_enc <> shared_secret <> extra_data) - results <> result - end) + results <> result + end) - <> = derived_keying_material_padded + <> = + derived_keying_material_padded {:ok, derived_keying_material} end end -end \ No newline at end of file +end diff --git a/lib/key/key.ex b/lib/key/key.ex index a0dc52b..6d5757e 100644 --- a/lib/key/key.ex +++ b/lib/key/key.ex @@ -37,5 +37,4 @@ defmodule ExthCrypto.Key do def raw_to_der(public_key) do <<0x04>> <> public_key end - -end \ No newline at end of file +end diff --git a/lib/mac/mac.ex b/lib/mac/mac.ex index ee1d74c..d784437 100644 --- a/lib/mac/mac.ex +++ b/lib/mac/mac.ex @@ -24,15 +24,16 @@ defmodule ExthCrypto.MAC do iex> ExthCrypto.MAC.mac("The quick brown fox jumps over the lazy dog", "key", :sha256, 8) <<247, 188, 131, 244, 48, 83, 132, 36>> """ - @spec mac(iodata(), iodata(), Hash.hash_algorithm, integer() | nil) :: mac + @spec mac(iodata(), iodata(), Hash.hash_algorithm(), integer() | nil) :: mac def mac(data, key, hash_algorithm, length \\ nil) when is_atom(hash_algorithm) do cond do - Enum.member?(Hash.hash_algorithms, hash_algorithm) -> + Enum.member?(Hash.hash_algorithms(), hash_algorithm) -> case length do nil -> :crypto.hmac(hash_algorithm, key, data) _ -> :crypto.hmac(hash_algorithm, key, data, length) end - # TODO: Implement CMAC + + # TODO: Implement CMAC end end @@ -80,4 +81,4 @@ defmodule ExthCrypto.MAC do def final({mac_type, mac}) do mac_module(mac_type).final_mac(mac) end -end \ No newline at end of file +end diff --git a/lib/math/math.ex b/lib/math/math.ex index d36b7c8..5fe9adb 100644 --- a/lib/math/math.ex +++ b/lib/math/math.ex @@ -20,8 +20,8 @@ defmodule ExthCrypto.Math do iex> ExthCrypto.Math.mod(0, 1337) 0 """ - def mod(x, n) when x > 0, do: rem x, n - def mod(x, n) when x < 0, do: rem n + x, n + def mod(x, n) when x > 0, do: rem(x, n) + def mod(x, n) when x < 0, do: rem(n + x, n) def mod(0, _n), do: 0 @doc """ @@ -32,7 +32,7 @@ defmodule ExthCrypto.Math do iex> ExthCrypto.Math.hex_to_bin("01020a0d") <<0x01, 0x02, 0x0a, 0x0d>> """ - @spec hex_to_bin(String.t) :: binary() + @spec hex_to_bin(String.t()) :: binary() def hex_to_bin(hex) do {:ok, bin} = Base.decode16(hex, case: :lower) @@ -63,7 +63,7 @@ defmodule ExthCrypto.Math do """ @spec pad(binary(), non_neg_integer()) :: binary() def pad(bin, length) do - padding_bits = ( length - byte_size(bin) ) * 8 + padding_bits = (length - byte_size(bin)) * 8 <<0x00::size(padding_bits)>> <> bin end @@ -76,7 +76,7 @@ defmodule ExthCrypto.Math do iex> ExthCrypto.Math.bin_to_hex(<<0x01, 0x02, 0x0a, 0x0d>>) "01020a0d" """ - @spec bin_to_hex(binary()) :: String.t + @spec bin_to_hex(binary()) :: String.t() def bin_to_hex(bin), do: Base.encode16(bin, case: :lower) @doc """ @@ -107,5 +107,4 @@ defmodule ExthCrypto.Math do def xor(a, b) when byte_size(a) == byte_size(b) do :crypto.exor(a, b) end - -end \ No newline at end of file +end diff --git a/lib/signature/signature.ex b/lib/signature/signature.ex index f8b5756..f304c0f 100644 --- a/lib/signature/signature.ex +++ b/lib/signature/signature.ex @@ -27,7 +27,8 @@ defmodule ExthCrypto.Signature do iex> ExthCrypto.Signature.get_public_key(<<1>>) {:error, "Private key size not 32 bytes"} """ - @spec get_public_key(ExthCrypto.Key.private_key) :: {:ok, ExthCrypto.Key.public_key} | {:error, String.t} + @spec get_public_key(ExthCrypto.Key.private_key()) :: + {:ok, ExthCrypto.Key.public_key()} | {:error, String.t()} def get_public_key(private_key) do case :libsecp256k1.ec_pubkey_create(private_key, :uncompressed) do {:ok, public_key} -> {:ok, public_key} @@ -47,9 +48,10 @@ defmodule ExthCrypto.Signature do iex> ExthCrypto.Signature.verify("12345", signature, ExthCrypto.Test.public_key) true """ - @spec sign_digest(binary(), ExthCrypto.Key.private_key) :: {signature, r, s, recovery_id} + @spec sign_digest(binary(), ExthCrypto.Key.private_key()) :: {signature, r, s, recovery_id} def sign_digest(digest, private_key) do - {:ok, <>=signature, recovery_id} = :libsecp256k1.ecdsa_sign_compact(digest, private_key, :default, <<>>) + {:ok, <> = signature, recovery_id} = + :libsecp256k1.ecdsa_sign_compact(digest, private_key, :default, <<>>) {signature, r, s, recovery_id} end @@ -74,7 +76,7 @@ defmodule ExthCrypto.Signature do iex> ExthCrypto.Signature.verify(msg |> Binary.drop(1), signature, ExthCrypto.Test.public_key(:key_a)) false """ - @spec verify(binary(), signature, ExthCrypto.Key.public_key) :: boolean() + @spec verify(binary(), signature, ExthCrypto.Key.public_key()) :: boolean() def verify(digest, signature, public_key) do case :libsecp256k1.ecdsa_verify_compact(digest, signature, public_key) do :ok -> true @@ -105,12 +107,12 @@ defmodule ExthCrypto.Signature do 171, 255, 26, 163, 160, 158, 227, 196, 92, 62, 119, 84, 156, 99, 224, 155, 120, 250, 153, 134, 180, 218, 177, 186, 200, 199, 106, 97, 103, 50, 215, 114>>} """ - @spec recover(binary(), signature, recovery_id) :: {:ok, ExthCrypto.Key.public_key} | {:error, String.t} + @spec recover(binary(), signature, recovery_id) :: + {:ok, ExthCrypto.Key.public_key()} | {:error, String.t()} def recover(digest, signature, recovery_id) do case :libsecp256k1.ecdsa_recover_compact(digest, signature, :uncompressed, recovery_id) do {:ok, public_key} -> {:ok, public_key} {:error, reason} -> {:error, to_string(reason)} end end - -end \ No newline at end of file +end diff --git a/lib/test.ex b/lib/test.ex index c40bcd7..f657302 100644 --- a/lib/test.ex +++ b/lib/test.ex @@ -5,40 +5,50 @@ defmodule ExthCrypto.Test do """ @public_keys %{ - key_a: <<4, 54, 241, 224, 126, 85, 135, 69, 213, 129, 115, 3, 41, 161, 217, 87, 215, - 159, 64, 17, 167, 128, 113, 172, 232, 46, 34, 145, 136, 72, 160, 207, 161, - 171, 255, 26, 163, 160, 158, 227, 196, 92, 62, 119, 84, 156, 99, 224, 155, - 120, 250, 153, 134, 180, 218, 177, 186, 200, 199, 106, 97, 103, 50, 215, 114>>, - key_b: <<4, 152, 113, 235, 8, 21, 103, 130, 50, 103, 89, 42, 186, 200, 236, 158, 159, - 221, 253, 236, 231, 144, 26, 21, 242, 51, 181, 63, 48, 77, 120, 96, 104, 108, - 33, 96, 27, 161, 167, 245, 102, 128, 226, 45, 10, 192, 62, 204, 208, 142, 73, - 100, 105, 81, 76, 37, 174, 29, 94, 85, 243, 145, 193, 149, 111>>, - key_c: <<4, 146, 201, 161, 205, 19, 177, 147, 33, 107, 190, 144, 81, 145, 173, 83, 20, - 105, 150, 114, 196, 249, 143, 167, 152, 63, 225, 96, 184, 86, 203, 38, 134, - 241, 40, 152, 74, 34, 68, 233, 204, 91, 240, 208, 254, 62, 169, 53, 201, 248, - 156, 236, 34, 203, 156, 75, 18, 121, 162, 104, 3, 164, 156, 46, 186>>, - key_d: <<4, 205, 208, 163, 120, 32, 181, 60, 4, 225, 235, 149, 145, 233, 130, 114, - 254, 250, 181, 166, 76, 124, 6, 241, 169, 49, 36, 251, 61, 166, 127, 63, 10, - 171, 21, 243, 26, 250, 157, 62, 224, 19, 31, 127, 12, 29, 32, 146, 191, 9, - 168, 124, 96, 120, 236, 233, 81, 8, 23, 61, 48, 4, 9, 213, 31>> + key_a: + <<4, 54, 241, 224, 126, 85, 135, 69, 213, 129, 115, 3, 41, 161, 217, 87, 215, 159, 64, 17, + 167, 128, 113, 172, 232, 46, 34, 145, 136, 72, 160, 207, 161, 171, 255, 26, 163, 160, 158, + 227, 196, 92, 62, 119, 84, 156, 99, 224, 155, 120, 250, 153, 134, 180, 218, 177, 186, 200, + 199, 106, 97, 103, 50, 215, 114>>, + key_b: + <<4, 152, 113, 235, 8, 21, 103, 130, 50, 103, 89, 42, 186, 200, 236, 158, 159, 221, 253, + 236, 231, 144, 26, 21, 242, 51, 181, 63, 48, 77, 120, 96, 104, 108, 33, 96, 27, 161, 167, + 245, 102, 128, 226, 45, 10, 192, 62, 204, 208, 142, 73, 100, 105, 81, 76, 37, 174, 29, 94, + 85, 243, 145, 193, 149, 111>>, + key_c: + <<4, 146, 201, 161, 205, 19, 177, 147, 33, 107, 190, 144, 81, 145, 173, 83, 20, 105, 150, + 114, 196, 249, 143, 167, 152, 63, 225, 96, 184, 86, 203, 38, 134, 241, 40, 152, 74, 34, + 68, 233, 204, 91, 240, 208, 254, 62, 169, 53, 201, 248, 156, 236, 34, 203, 156, 75, 18, + 121, 162, 104, 3, 164, 156, 46, 186>>, + key_d: + <<4, 205, 208, 163, 120, 32, 181, 60, 4, 225, 235, 149, 145, 233, 130, 114, 254, 250, 181, + 166, 76, 124, 6, 241, 169, 49, 36, 251, 61, 166, 127, 63, 10, 171, 21, 243, 26, 250, 157, + 62, 224, 19, 31, 127, 12, 29, 32, 146, 191, 9, 168, 124, 96, 120, 236, 233, 81, 8, 23, 61, + 48, 4, 9, 213, 31>> } @private_keys %{ - key_a: <<94, 217, 126, 139, 193, 247, 132, 35, 174, 8, 191, 12, 133, 229, 115, 237, - 78, 81, 160, 114, 73, 118, 207, 206, 98, 114, 27, 62, 25, 29, 219, 206>>, - key_b: <<226, 137, 30, 163, 26, 230, 61, 203, 158, 81, 58, 4, 197, 149, 169, 80, 34, - 11, 157, 221, 132, 75, 78, 202, 254, 8, 94, 254, 229, 98, 104, 5>>, - key_c: <<178, 68, 134, 194, 0, 187, 118, 35, 33, 220, 4, 3, 50, 96, 97, 91, 96, 14, - 71, 239, 7, 102, 33, 187, 194, 221, 152, 36, 95, 22, 121, 48>>, - key_d: <<157, 39, 212, 230, 12, 119, 100, 92, 134, 157, 151, 31, 151, 234, 63, 46, - 213, 201, 34, 95, 208, 141, 55, 74, 2, 59, 121, 174, 7, 243, 230, 46>> + key_a: + <<94, 217, 126, 139, 193, 247, 132, 35, 174, 8, 191, 12, 133, 229, 115, 237, 78, 81, 160, + 114, 73, 118, 207, 206, 98, 114, 27, 62, 25, 29, 219, 206>>, + key_b: + <<226, 137, 30, 163, 26, 230, 61, 203, 158, 81, 58, 4, 197, 149, 169, 80, 34, 11, 157, 221, + 132, 75, 78, 202, 254, 8, 94, 254, 229, 98, 104, 5>>, + key_c: + <<178, 68, 134, 194, 0, 187, 118, 35, 33, 220, 4, 3, 50, 96, 97, 91, 96, 14, 71, 239, 7, + 102, 33, 187, 194, 221, 152, 36, 95, 22, 121, 48>>, + key_d: + <<157, 39, 212, 230, 12, 119, 100, 92, 134, 157, 151, 31, 151, 234, 63, 46, 213, 201, 34, + 95, 208, 141, 55, 74, 2, 59, 121, 174, 7, 243, 230, 46>> } @symmetric_keys %{ - key_a: <<1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, - 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32>>, - key_b: <<11, 22, 33, 44, 55, 66, 77, 88, 99, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, - 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32>>, + key_a: + <<1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32>>, + key_b: + <<11, 22, 33, 44, 55, 66, 77, 88, 99, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, + 23, 24, 25, 26, 27, 28, 29, 30, 31, 32>> } @doc """ @@ -74,4 +84,4 @@ defmodule ExthCrypto.Test do def init_vector(base \\ 1, block_size \\ 16) do for i <- base..(base + block_size - 1), do: <>, into: <<>> end -end \ No newline at end of file +end diff --git a/mix.exs b/mix.exs index 08fe38b..0765e53 100644 --- a/mix.exs +++ b/mix.exs @@ -2,19 +2,20 @@ defmodule ExthCrypto.Mixfile do use Mix.Project def project do - [app: :exth_crypto, - version: "0.1.6", - elixir: "~> 1.4", - description: "Exthereum's Crypto Suite.", + [ + app: :exth_crypto, + version: "0.1.6", + elixir: "~> 1.4", + description: "Exthereum's Crypto Suite.", package: [ maintainers: ["Geoffrey Hayes", "Mason Fischer"], licenses: ["MIT"], links: %{"GitHub" => "https://github.com/exthereum/exth_crypto"} ], - build_embedded: Mix.env == :prod, - start_permanent: Mix.env == :prod, - deps: deps(), - dialyzer: [ + build_embedded: Mix.env() == :prod, + start_permanent: Mix.env() == :prod, + deps: deps(), + dialyzer: [ flags: [:underspecs, :unknown, :unmatched_returns], plt_add_apps: [:mix, :iex, :logger], plt_add_deps: :transitive @@ -46,7 +47,7 @@ defmodule ExthCrypto.Mixfile do {:credo, "~> 0.10.2", only: [:dev, :test], runtime: false}, {:ex_doc, "~> 0.17", only: :dev, runtime: false}, {:dialyxir, "~> 1.0.0-rc.3", only: [:dev], runtime: false}, - {:binary, "~> 0.0.4"}, + {:binary, "~> 0.0.4"} ] end end diff --git a/test/aes/aes_test.exs b/test/aes/aes_test.exs index 7fffb97..5fd011d 100644 --- a/test/aes/aes_test.exs +++ b/test/aes/aes_test.exs @@ -1,5 +1,4 @@ defmodule ExthCrypto.AESTest do use ExUnit.Case doctest ExthCrypto.AES - -end \ No newline at end of file +end diff --git a/test/cipher_test.exs b/test/cipher_test.exs index 05a81e0..7337d2f 100644 --- a/test/cipher_test.exs +++ b/test/cipher_test.exs @@ -1,5 +1,4 @@ defmodule ExthCrypto.CipherTest do use ExUnit.Case doctest ExthCrypto.Cipher - -end \ No newline at end of file +end diff --git a/test/ecies/ecdh_test.exs b/test/ecies/ecdh_test.exs index 51322da..7164b47 100644 --- a/test/ecies/ecdh_test.exs +++ b/test/ecies/ecdh_test.exs @@ -1,5 +1,4 @@ defmodule ExthCrypto.ECIES.ECDHTest do use ExUnit.Case doctest ExthCrypto.ECIES.ECDH - -end \ No newline at end of file +end diff --git a/test/ecies/ecies_test.exs b/test/ecies/ecies_test.exs index fa18535..f5b0c83 100644 --- a/test/ecies/ecies_test.exs +++ b/test/ecies/ecies_test.exs @@ -1,5 +1,4 @@ defmodule ExthCrypto.ECIESTest do use ExUnit.Case doctest ExthCrypto.ECIES - -end \ No newline at end of file +end diff --git a/test/ecies/parameters_test.exs b/test/ecies/parameters_test.exs index 7a98ed6..4943590 100644 --- a/test/ecies/parameters_test.exs +++ b/test/ecies/parameters_test.exs @@ -1,5 +1,4 @@ defmodule ExthCrypto.ECIES.ParametersTest do use ExUnit.Case doctest ExthCrypto.ECIES.Parameters - -end \ No newline at end of file +end diff --git a/test/hash/fake_test.exs b/test/hash/fake_test.exs index bba585c..554fa42 100644 --- a/test/hash/fake_test.exs +++ b/test/hash/fake_test.exs @@ -1,5 +1,4 @@ defmodule ExthCrypto.Hash.FakeTest do use ExUnit.Case doctest ExthCrypto.Hash.Fake - -end \ No newline at end of file +end diff --git a/test/hash/keccak_test.exs b/test/hash/keccak_test.exs index 635b42a..e17d739 100644 --- a/test/hash/keccak_test.exs +++ b/test/hash/keccak_test.exs @@ -1,5 +1,4 @@ defmodule ExthCrypto.Hash.KeccakTest do use ExUnit.Case doctest ExthCrypto.Hash.Keccak - -end \ No newline at end of file +end diff --git a/test/hash/sha_test.exs b/test/hash/sha_test.exs index 00f9ff6..100aab1 100644 --- a/test/hash/sha_test.exs +++ b/test/hash/sha_test.exs @@ -1,5 +1,4 @@ defmodule ExthCrypto.Hash.SHATest do use ExUnit.Case doctest ExthCrypto.Hash.SHA - -end \ No newline at end of file +end diff --git a/test/hash_test.exs b/test/hash_test.exs index 02e0775..076b79d 100644 --- a/test/hash_test.exs +++ b/test/hash_test.exs @@ -1,5 +1,4 @@ defmodule ExthCrypto.HashTest do use ExUnit.Case doctest ExthCrypto.Hash - -end \ No newline at end of file +end diff --git a/test/kdf/nist_sp_800_65_test.exs b/test/kdf/nist_sp_800_65_test.exs index 7a9f748..f4677e7 100644 --- a/test/kdf/nist_sp_800_65_test.exs +++ b/test/kdf/nist_sp_800_65_test.exs @@ -1,5 +1,4 @@ defmodule ExthCrypto.KDF.NistSp80056Test do use ExUnit.Case doctest ExthCrypto.KDF.NistSp80056 - -end \ No newline at end of file +end diff --git a/test/mac/mac_test.exs b/test/mac/mac_test.exs index 2f1ef80..ceb572b 100644 --- a/test/mac/mac_test.exs +++ b/test/mac/mac_test.exs @@ -1,5 +1,4 @@ defmodule ExthCrypto.MACTest do use ExUnit.Case doctest ExthCrypto.MAC - -end \ No newline at end of file +end diff --git a/test/math/math_test.exs b/test/math/math_test.exs index 46cdbc0..f32f880 100644 --- a/test/math/math_test.exs +++ b/test/math/math_test.exs @@ -1,5 +1,4 @@ defmodule ExthCrypto.MathTest do use ExUnit.Case doctest ExthCrypto.Math - -end \ No newline at end of file +end diff --git a/test/signature/signature_test.exs b/test/signature/signature_test.exs index a9ba541..430e8ba 100644 --- a/test/signature/signature_test.exs +++ b/test/signature/signature_test.exs @@ -1,5 +1,4 @@ defmodule ExthCrypto.SignatureTest do use ExUnit.Case doctest ExthCrypto.Signature - -end \ No newline at end of file +end