Created
August 11, 2018 19:37
-
-
Save potatosalad/c1a787819b93c5fdb8b77958f00c8723 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule ExampleEncryptor do | |
def encrypt(plain_text, password) do | |
salt = :crypto.strong_rand_bytes(32) | |
iterations = 4096 | |
kek = derive_key_encryption_key(password, salt, iterations, 32, :sha512) | |
kiv = :crypto.strong_rand_bytes(12) | |
cek = :crypto.strong_rand_bytes(32) | |
civ = :crypto.strong_rand_bytes(12) | |
{cek_cipher_text, cek_cipher_tag} = :crypto.block_encrypt(:aes_gcm, kek, kiv, {<<>>, cek}) | |
protected = %{ | |
"alg" => "PBES2-HS512+A256GCMKW", | |
"p2i" => iterations, | |
"p2s" => salt, | |
"iv" => kiv, | |
"tag" => cek_cipher_tag, | |
"enc" => "A256GCM" | |
} | |
aad = :erlang.term_to_binary(protected) | |
{cipher_text, cipher_tag} = :crypto.block_encrypt(:aes_gcm, cek, civ, {aad, plain_text}) | |
:erlang.term_to_binary(%{ | |
"protected" => aad, | |
"encrypted_key" => cek_cipher_text, | |
"iv" => civ, | |
"ciphertext" => cipher_text, | |
"tag" => cipher_tag | |
}) | |
end | |
def decrypt(encrypted, password) do | |
case maybe_binary_to_term(encrypted) do | |
{:ok, | |
%{"protected" => aad, "encrypted_key" => cek_cipher_text, "iv" => civ, "ciphertext" => cipher_text, "tag" => cipher_tag}} -> | |
case maybe_binary_to_term(aad) do | |
{:ok, | |
%{ | |
"alg" => "PBES2-HS512+A256GCMKW", | |
"p2i" => iterations, | |
"p2s" => salt, | |
"iv" => kiv, | |
"tag" => cek_cipher_tag, | |
"enc" => "A256GCM" | |
}} -> | |
kek = derive_key_encryption_key(password, salt, iterations, 32, :sha512) | |
case :crypto.block_decrypt(:aes_gcm, kek, kiv, {<<>>, cek_cipher_text, cek_cipher_tag}) do | |
cek when is_binary(cek) and bit_size(cek) === 256 -> | |
case :crypto.block_decrypt(:aes_gcm, cek, civ, {aad, cipher_text, cipher_tag}) do | |
plain_text when is_binary(plain_text) -> | |
{:ok, plain_text} | |
:error -> | |
:error | |
end | |
_ -> | |
:error | |
end | |
end | |
_ -> | |
:error | |
end | |
end | |
def derive_key_encryption_key(password, salt, iterations, derived_key_length, hash) when hash in [:sha256, :sha384, :sha512] do | |
prf_output_length = byte_size(:crypto.hmac(hash, <<>>, <<>>)) | |
:pubkey_pbe.pbdkdf2(password, salt, iterations, derived_key_length, &:crypto.hmac/4, hash, prf_output_length) | |
end | |
@doc false | |
defp maybe_binary_to_term(binary) do | |
try do | |
term = :erlang.binary_to_term(binary, [:safe]) | |
{:ok, term} | |
catch | |
_, _ -> | |
:error | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment