defmodule ExthCrypto.AES do @moduledoc """ Defines standard functions for use with AES symmetric cryptography in block mode. """ @type mode :: :cbc | :ctr @block_size 32 @doc """ Returns the blocksize for AES encryption when used as block mode encryption. ## Examples iex> ExthCrypto.AES.block_size 32 """ @spec block_size :: integer() def block_size, do: @block_size @doc """ Encrypts a given binary with the given public key. For block mode, this is the standard encrypt operation. For streaming mode, this will return the final block of the stream. Note: for streaming modes, `init_vector` is the same as ICB. ## Examples iex> ExthCrypto.AES.encrypt("obi wan", :cbc, ExthCrypto.Test.symmetric_key, ExthCrypto.Test.init_vector) <<86, 16, 7, 47, 97, 219, 8, 46, 16, 170, 70, 100, 131, 140, 241, 28>> iex> ExthCrypto.AES.encrypt("obi wan", :cbc, ExthCrypto.Test.symmetric_key(:key_b), ExthCrypto.Test.init_vector) <<219, 181, 173, 235, 88, 139, 229, 61, 172, 142, 36, 195, 83, 203, 237, 39>> iex> ExthCrypto.AES.encrypt("obi wan", :cbc, ExthCrypto.Test.symmetric_key, ExthCrypto.Test.init_vector(2)) <<134, 126, 59, 64, 83, 197, 85, 40, 155, 178, 52, 165, 27, 190, 60, 170>> iex> ExthCrypto.AES.encrypt("jedi knight", :cbc, ExthCrypto.Test.symmetric_key, ExthCrypto.Test.init_vector) <<54, 252, 188, 111, 221, 182, 65, 54, 77, 143, 127, 188, 176, 178, 50, 160>> iex> ExthCrypto.AES.encrypt("Did you ever hear the story of Darth Plagueis The Wise? I thought not.", :cbc, ExthCrypto.Test.symmetric_key, ExthCrypto.Test.init_vector) |> ExthCrypto.Math.bin_to_hex "3ee326e03303a303df6eac828b0bdc8ed67254b44a6a79cd0082bc245977b0e7d4283d63a346744d2f1ecaafca8be906d9f3d27db914d80b601d7e0c598418380e5fe2b48c0e0b8454c6d251f577f28f" iex> ExthCrypto.AES.encrypt("obi wan", :ctr, ExthCrypto.Test.symmetric_key, ExthCrypto.Test.init_vector) <<32, 99, 57, 7, 64, 82, 28>> iex> ExthCrypto.AES.encrypt("obi wan", :ctr, ExthCrypto.Test.symmetric_key(:key_b), ExthCrypto.Test.init_vector) <<156, 176, 33, 64, 69, 16, 173>> iex> ExthCrypto.AES.encrypt("obi wan", :ctr, ExthCrypto.Test.symmetric_key, ExthCrypto.Test.init_vector(2)) <<214, 99, 7, 241, 219, 189, 178>> iex> ExthCrypto.AES.encrypt("jedi knight", :ctr, ExthCrypto.Test.symmetric_key, ExthCrypto.Test.init_vector) <<37, 100, 52, 78, 23, 88, 28, 22, 254, 47, 32>> iex> ExthCrypto.AES.encrypt("Did you ever hear the story of Darth Plagueis The Wise? I thought not.", :ctr, ExthCrypto.Test.symmetric_key, ExthCrypto.Test.init_vector) |> ExthCrypto.Math.bin_to_hex "0b6834074e5c075ffc31318cc03cba1fe35648a6f149a74952661473b73570fb98332e31870c111d3ae5ccff2154bd4083a7ee4bfd19bc85eba77835aac4cea881ada2630cdd" """ @spec encrypt(ExthCrypto.Cipher.plaintext, mode, ExthCrypto.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) end def encrypt(plaintext, :ctr, symmetric_key, init_vector) do {_state, ciphertext} = :crypto.stream_init(:aes_ctr, symmetric_key, init_vector) |> :crypto.stream_encrypt(plaintext) ciphertext end @doc """ Decrypts the given binary with the given private key. ## Examples iex> <<86, 16, 7, 47, 97, 219, 8, 46, 16, 170, 70, 100, 131, 140, 241, 28>> ...> |> ExthCrypto.AES.decrypt(:cbc, ExthCrypto.Test.symmetric_key, ExthCrypto.Test.init_vector) <<0, 0, 0, 0, 0, 0, 0, 0, 0>> <> "obi wan" iex> <<219, 181, 173, 235, 88, 139, 229, 61, 172, 142, 36, 195, 83, 203, 237, 39>> ...> |> ExthCrypto.AES.decrypt(:cbc, ExthCrypto.Test.symmetric_key(:key_b), ExthCrypto.Test.init_vector) <<0, 0, 0, 0, 0, 0, 0, 0, 0>> <> "obi wan" iex> <<134, 126, 59, 64, 83, 197, 85, 40, 155, 178, 52, 165, 27, 190, 60, 170>> ...> |> ExthCrypto.AES.decrypt(:cbc, ExthCrypto.Test.symmetric_key, ExthCrypto.Test.init_vector(2)) <<0, 0, 0, 0, 0, 0, 0, 0, 0>> <> "obi wan" iex> <<54, 252, 188, 111, 221, 182, 65, 54, 77, 143, 127, 188, 176, 178, 50, 160>> ...> |> ExthCrypto.AES.decrypt(:cbc, ExthCrypto.Test.symmetric_key, ExthCrypto.Test.init_vector) <<0, 0, 0, 0, 0>> <> "jedi knight" iex> "3ee326e03303a303df6eac828b0bdc8ed67254b44a6a79cd0082bc245977b0e7d4283d63a346744d2f1ecaafca8be906d9f3d27db914d80b601d7e0c598418380e5fe2b48c0e0b8454c6d251f577f28f" ...> |> ExthCrypto.Math.hex_to_bin ...> |> ExthCrypto.AES.decrypt(:cbc, ExthCrypto.Test.symmetric_key, ExthCrypto.Test.init_vector) <<0, 0, 0, 0, 0, 0, 0, 0, 0, 0>> <> "Did you ever hear the story of Darth Plagueis The Wise? I thought not." iex> <<32, 99, 57, 7, 64, 82, 28>> ...> |> ExthCrypto.AES.decrypt(:ctr, ExthCrypto.Test.symmetric_key, ExthCrypto.Test.init_vector) "obi wan" iex> <<156, 176, 33, 64, 69, 16, 173>> ...> |> ExthCrypto.AES.decrypt(:ctr, ExthCrypto.Test.symmetric_key(:key_b), ExthCrypto.Test.init_vector) "obi wan" iex> <<214, 99, 7, 241, 219, 189, 178>> ...> |> ExthCrypto.AES.decrypt(:ctr, ExthCrypto.Test.symmetric_key, ExthCrypto.Test.init_vector(2)) "obi wan" iex> <<37, 100, 52, 78, 23, 88, 28, 22, 254, 47, 32>> ...> |> ExthCrypto.AES.decrypt(:ctr, ExthCrypto.Test.symmetric_key, ExthCrypto.Test.init_vector) "jedi knight" iex> "0b6834074e5c075ffc31318cc03cba1fe35648a6f149a74952661473b73570fb98332e31870c111d3ae5ccff2154bd4083a7ee4bfd19bc85eba77835aac4cea881ada2630cdd" ...> |> ExthCrypto.Math.hex_to_bin ...> |> ExthCrypto.AES.decrypt(:ctr, ExthCrypto.Test.symmetric_key, ExthCrypto.Test.init_vector) "Did you ever hear the story of Darth Plagueis The Wise? I thought not." """ @spec decrypt(ExthCrypto.Cipher.ciphertext, mode, ExthCrypto.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 def decrypt(ciphertext, :ctr, symmetric_key, init_vector) do {_state, plaintext} = :crypto.stream_init(:aes_ctr, symmetric_key, init_vector) |> :crypto.stream_decrypt(ciphertext) plaintext end end