Skip to content

Commit

Permalink
Removed Warnings with Elixir 1.6.1 (#19)
Browse files Browse the repository at this point in the history
* Removed warnings with Elixir 1.6.1 and Erlang/OTP 20

* Removed warnings from tests and Fixed testing new random function

* Used formater from Elixir 1.6.1
  • Loading branch information
quatermain authored and ntrepid8 committed Feb 5, 2018
1 parent 1fdbffd commit 6c8f694
Show file tree
Hide file tree
Showing 15 changed files with 355 additions and 262 deletions.
104 changes: 58 additions & 46 deletions lib/ex_crypto.ex
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,24 @@ defmodule ExCrypto do

defp normalize_error(kind, error, key_and_iv \\ nil) do
key_error = test_key_and_iv_bitlength(key_and_iv)

cond do
key_error ->
key_error

%{message: message} = Exception.normalize(kind, error) ->
{:error, message}

x = Exception.normalize(kind, error) ->
{kind, x, System.stacktrace}
{kind, x, System.stacktrace()}
end
end

defp test_key_and_iv_bitlength(nil), do: nil
defp test_key_and_iv_bitlength({_key, iv}) when bit_size(iv) != @iv_bit_length, do: {:error, @bitlength_error}

defp test_key_and_iv_bitlength({_key, iv}) when bit_size(iv) != @iv_bit_length,
do: {:error, @bitlength_error}

defp test_key_and_iv_bitlength({key, _iv}) when rem(bit_size(key), 128) == 0, do: nil
defp test_key_and_iv_bitlength({key, _iv}) when rem(bit_size(key), 192) == 0, do: nil
defp test_key_and_iv_bitlength({key, _iv}) when rem(bit_size(key), 256) == 0, do: nil
Expand All @@ -56,17 +62,19 @@ defmodule ExCrypto do
iex> assert(String.length(rand_string) == 44)
true
"""
@spec rand_chars(integer) :: String.t
@spec rand_chars(integer) :: String.t()
def rand_chars(num_chars) do
block_bytes = 3
block_chars = 4
block_count = div(num_chars, block_chars)
block_partial = rem(num_chars, block_chars)

block_count =
case block_partial > 0 do
true -> block_count + 1
false -> block_count
end

rand_string = Base.url_encode64(:crypto.strong_rand_bytes(block_count * block_bytes))
String.slice(rand_string, 0, num_chars)
end
Expand Down Expand Up @@ -99,7 +107,7 @@ defmodule ExCrypto do
"""
@spec rand_int(integer, integer) :: integer
def rand_int(low, high) do
:crypto.rand_uniform(low, high)
low + :rand.uniform(high - low + 1) - 1
end

@doc """
Expand Down Expand Up @@ -204,22 +212,22 @@ defmodule ExCrypto do
iex> auth_data = "my-auth-data"
iex> {:ok, aes_256_key} = ExCrypto.generate_aes_key(:aes_256, :bytes)
iex> {:ok, iv} = ExCrypto.rand_bytes(16)
iex> {:ok, {ad, payload}} = ExCrypto.encrypt(aes_256_key, auth_data, iv, clear_text)
iex> {iv, cipher_text, cipher_tag} = payload
iex> {:ok, {_ad, payload}} = ExCrypto.encrypt(aes_256_key, auth_data, iv, clear_text)
iex> {_iv, cipher_text, cipher_tag} = payload
iex> assert(is_bitstring(cipher_text))
true
iex> assert(bit_size(cipher_tag) == 128)
true
"""
@spec encrypt(binary, binary, binary, binary) :: {:ok, {binary, {binary, binary, binary}}} | {:error, binary}
@spec encrypt(binary, binary, binary, binary) ::
{:ok, {binary, {binary, binary, binary}}} | {:error, binary}
def encrypt(key, authentication_data, initialization_vector, clear_text) do
_encrypt(key, initialization_vector, {authentication_data, clear_text}, :aes_gcm)
catch
kind, error -> normalize_error(kind, error)
end


@doc """
Encrypt a `binary` with AES in CBC mode.
Expand All @@ -233,22 +241,22 @@ defmodule ExCrypto do
iex> clear_text = "my-clear-text"
iex> {:ok, aes_256_key} = ExCrypto.generate_aes_key(:aes_256, :bytes)
iex> {:ok, {iv, cipher_text}} = ExCrypto.encrypt(aes_256_key, clear_text)
iex> {:ok, {_iv, cipher_text}} = ExCrypto.encrypt(aes_256_key, clear_text)
iex> assert(is_bitstring(cipher_text))
true
"""
@spec encrypt(binary, binary) :: {:ok, {binary, binary}} | {:error, binary}
def encrypt(key, clear_text) do
{:ok, initialization_vector} = rand_bytes(16) # new 128 bit random initialization_vector
# new 128 bit random initialization_vector
{:ok, initialization_vector} = rand_bytes(16)
_encrypt(key, initialization_vector, pad(clear_text, @aes_block_size), :aes_cbc256)
catch
kind, error ->
{:ok, initialization_vector} = rand_bytes(16)
normalize_error(kind, error, {key, initialization_vector})
end


@doc """
Encrypt a `binary` with AES in CBC mode providing explicit IV via map.
Expand All @@ -263,41 +271,21 @@ defmodule ExCrypto do
iex> clear_text = "my-clear-text"
iex> {:ok, aes_256_key} = ExCrypto.generate_aes_key(:aes_256, :bytes)
iex> {:ok, init_vec} = ExCrypto.rand_bytes(16)
iex> {:ok, {iv, cipher_text}} = ExCrypto.encrypt(aes_256_key, clear_text, %{initialization_vector: init_vec})
iex> {:ok, {_iv, cipher_text}} = ExCrypto.encrypt(aes_256_key, clear_text, %{initialization_vector: init_vec})
iex> assert(is_bitstring(cipher_text))
true
"""
@spec encrypt(binary, binary, %{initialization_vector: binary}) :: {:ok, {binary, {binary, binary, binary}}} |
{:ok, {binary, binary}} |
{:error, any}
@spec encrypt(binary, binary, %{initialization_vector: binary}) ::
{:ok, {binary, {binary, binary, binary}}}
| {:ok, {binary, binary}}
| {:error, any}
def encrypt(key, clear_text, %{initialization_vector: initialization_vector}) do
_encrypt(key, initialization_vector, pad(clear_text, @aes_block_size), :aes_cbc256)
catch
kind, error -> normalize_error(kind, error, {key, initialization_vector})
end

defp _encrypt(key, initialization_vector, encryption_payload, algorithm) do
case :crypto.block_encrypt(algorithm, key, initialization_vector, encryption_payload) do
{cipher_text, cipher_tag} ->
{authentication_data, _clear_text} = encryption_payload
{:ok, {authentication_data, {initialization_vector, cipher_text, cipher_tag}}}
<<cipher_text::binary>> ->
{:ok, {initialization_vector, cipher_text }}
x -> {:error, x}
end
end

def pad(data, block_size) do
to_add = block_size - rem(byte_size(data), block_size)
data <> to_string(:string.chars(to_add, to_add))
end

def unpad(data) do
to_remove = :binary.last(data)
:binary.part(data, 0, byte_size(data) - to_remove)
end

@doc """
Same as `encrypt/4` except the `initialization_vector` is automatically generated.
Expand All @@ -309,20 +297,46 @@ defmodule ExCrypto do
iex> clear_text = "my-clear-text"
iex> auth_data = "my-auth-data"
iex> {:ok, aes_256_key} = ExCrypto.generate_aes_key(:aes_256, :bytes)
iex> {:ok, {ad, payload}} = ExCrypto.encrypt(aes_256_key, auth_data, clear_text)
iex> {init_vec, cipher_text, cipher_tag} = payload
iex> {:ok, {_ad, payload}} = ExCrypto.encrypt(aes_256_key, auth_data, clear_text)
iex> {_init_vec, cipher_text, cipher_tag} = payload
iex> assert(is_bitstring(cipher_text))
true
iex> assert(bit_size(cipher_tag) == 128)
true
"""
@spec encrypt(binary, binary, binary) :: {:ok, {binary, {binary, binary, binary}}} | {:error, binary}
@spec encrypt(binary, binary, binary) ::
{:ok, {binary, {binary, binary, binary}}} | {:error, binary}
def encrypt(key, authentication_data, clear_text) do
{:ok, initialization_vector} = rand_bytes(16) # new 128 bit random initialization_vector
# new 128 bit random initialization_vector
{:ok, initialization_vector} = rand_bytes(16)
_encrypt(key, initialization_vector, {authentication_data, clear_text}, :aes_gcm)
end

defp _encrypt(key, initialization_vector, encryption_payload, algorithm) do
case :crypto.block_encrypt(algorithm, key, initialization_vector, encryption_payload) do
{cipher_text, cipher_tag} ->
{authentication_data, _clear_text} = encryption_payload
{:ok, {authentication_data, {initialization_vector, cipher_text, cipher_tag}}}

<<cipher_text::binary>> ->
{:ok, {initialization_vector, cipher_text}}

x ->
{:error, x}
end
end

def pad(data, block_size) do
to_add = block_size - rem(byte_size(data), block_size)
data <> to_string(:string.chars(to_add, to_add))
end

def unpad(data) do
to_remove = :binary.last(data)
:binary.part(data, 0, byte_size(data) - to_remove)
end

@doc """
Returns a clear-text string decrypted with AES in GCM mode.
Expand All @@ -335,7 +349,7 @@ defmodule ExCrypto do
iex> clear_text = "my-clear-text"
iex> auth_data = "my-auth-data"
iex> {:ok, aes_256_key} = ExCrypto.generate_aes_key(:aes_256, :bytes)
iex> {:ok, {ad, payload}} = ExCrypto.encrypt(aes_256_key, auth_data, clear_text)
iex> {:ok, {_ad, payload}} = ExCrypto.encrypt(aes_256_key, auth_data, clear_text)
iex> {init_vec, cipher_text, cipher_tag} = payload
iex> {:ok, val} = ExCrypto.decrypt(aes_256_key, auth_data, init_vec, cipher_text, cipher_tag)
iex> assert(val == clear_text)
Expand All @@ -346,7 +360,6 @@ defmodule ExCrypto do
_decrypt(key, initialization_vector, {authentication_data, cipher_text, cipher_tag}, :aes_gcm)
end


@doc """
Returns a clear-text string decrypted with AES256 in CBC mode.
Expand Down Expand Up @@ -392,7 +405,7 @@ defmodule ExCrypto do
iex> clear_text = "my-clear-text"
iex> auth_data = "my-auth-data"
iex> {:ok, aes_256_key} = ExCrypto.generate_aes_key(:aes_256, :bytes)
iex> {:ok, {ad, {init_vec, cipher_text, cipher_tag}}} = ExCrypto.encrypt(aes_256_key, auth_data, clear_text)
iex> {:ok, {_ad, {init_vec, cipher_text, cipher_tag}}} = ExCrypto.encrypt(aes_256_key, auth_data, clear_text)
iex> {:ok, encoded_payload} = ExCrypto.encode_payload(init_vec, cipher_text, cipher_tag)
iex> assert(String.valid?(encoded_payload))
true
Expand All @@ -410,7 +423,7 @@ defmodule ExCrypto do
iex> clear_text = "my-clear-text"
iex> auth_data = "my-auth-data"
iex> {:ok, aes_256_key} = ExCrypto.generate_aes_key(:aes_256, :bytes)
iex> {:ok, {ad, {init_vec, cipher_text, cipher_tag}}} = ExCrypto.encrypt(aes_256_key, auth_data, clear_text)
iex> {:ok, {_ad, {init_vec, cipher_text, cipher_tag}}} = ExCrypto.encrypt(aes_256_key, auth_data, clear_text)
iex> {:ok, encoded_payload} = ExCrypto.encode_payload(init_vec, cipher_text, cipher_tag)
iex> assert(String.valid?(encoded_payload))
true
Expand All @@ -427,7 +440,7 @@ defmodule ExCrypto do
{:ok, decoded_parts} = Base.url_decode64(encoded_parts)
decoded_length = byte_size(decoded_parts)
iv = Kernel.binary_part(decoded_parts, 0, 16)
cipher_text = Kernel.binary_part(decoded_parts, 16, (decoded_length-32))
cipher_text = Kernel.binary_part(decoded_parts, 16, decoded_length - 32)
cipher_tag = Kernel.binary_part(decoded_parts, decoded_length, -16)
{:ok, {iv, cipher_text, cipher_tag}}
end
Expand All @@ -436,5 +449,4 @@ defmodule ExCrypto do
def universal_time(:unix) do
:calendar.datetime_to_gregorian_seconds(:calendar.universal_time()) - @epoch
end

end
47 changes: 31 additions & 16 deletions lib/ex_crypto/ex_entropy.ex
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
defmodule ExEntropy do

@doc """
Compute the Shannon entropy of a binary value.
Expand All @@ -13,7 +12,7 @@ defmodule ExEntropy do
# convert the binary value into a list with exponent as one of [1, 8]
val_list = gen_val_list(value, exponent)

val_range = round :math.pow(2, exponent) - 1
val_range = round(:math.pow(2, exponent) - 1)
val_accumulator = for x <- 0..val_range, into: %{}, do: {x, 0}

# accumulate occurrence counts
Expand All @@ -27,19 +26,22 @@ defmodule ExEntropy do
end

def shannon_entropy(value) when is_binary(value) do
shannon_entropy(value, 8) # byte blocks by default
# byte blocks by default
shannon_entropy(value, 8)
end

defp shannon_entropy_0(entropy, _block_count, _block_range, []) do
entropy
end

defp shannon_entropy_0(entropy, block_count, block_range, [h|t]) do
defp shannon_entropy_0(entropy, block_count, block_range, [h | t]) do
case h do
0 -> shannon_entropy_0(entropy, block_count, block_range, t)
_ ->
0 ->
shannon_entropy_0(entropy, block_count, block_range, t)

_ ->
p = 1.0 * h / block_count
udpated_entropy = entropy - (p * (:math.log(p) / :math.log(block_range)))
udpated_entropy = entropy - p * (:math.log(p) / :math.log(block_range))
shannon_entropy_0(udpated_entropy, block_count, block_range, t)
end
end
Expand All @@ -48,19 +50,32 @@ defmodule ExEntropy do
accumulator
end

defp count_occurances(accumulator, [h|t]) do
defp count_occurances(accumulator, [h | t]) do
c_0 = Map.get(accumulator, h, 0)
count_occurances(Map.put(accumulator, h, c_0+1), t)
count_occurances(Map.put(accumulator, h, c_0 + 1), t)
end

defp gen_val_list(value, exponent) do
case exponent do
1 -> for << x::1 <- value >>, do: x # bits
8 -> for << x::8 <- value >>, do: x # bytes
10 -> for << x::10 <- value >>, do: x # kilobytes
16 -> for << x::16 <- value >>, do: x # hex
20 -> for << x::20 <- value >>, do: x # megabytes
# bits
1 ->
for <<x::1 <- value>>, do: x

# bytes
8 ->
for <<x::8 <- value>>, do: x

# kilobytes
10 ->
for <<x::10 <- value>>, do: x

# hex
16 ->
for <<x::16 <- value>>, do: x

# megabytes
20 ->
for <<x::20 <- value>>, do: x
end
end

end
end
4 changes: 2 additions & 2 deletions lib/ex_crypto/hash.ex
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ defmodule ExCrypto.Hash do
def sha256!(data) do
case sha256(data) do
{:ok, digest} -> digest
{:error, reason} -> raise "sha256 error: #{inspect reason}"
{:error, reason} -> raise "sha256 error: #{inspect(reason)}"
end
end

Expand All @@ -25,7 +25,7 @@ defmodule ExCrypto.Hash do
def sha512!(data) do
case sha512(data) do
{:ok, digest} -> digest
{:error, reason} -> raise "sha512 error: #{inspect reason}"
{:error, reason} -> raise "sha512 error: #{inspect(reason)}"
end
end
end
Loading

0 comments on commit 6c8f694

Please sign in to comment.