Created
August 20, 2021 03:32
-
-
Save bluzky/68e3c0e698e74e9b54edbeccf9ebb735 to your computer and use it in GitHub Desktop.
Elixir encrypt/decrypt using Erlang :crypto module
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 Magik.Crypto do | |
@moduledoc """ | |
Provide some basic encrypt/decrypt function | |
""" | |
@aad "AES256GCM" | |
@block_size 16 | |
@doc """ | |
`generate_secret` | |
Generates a random 16 byte and encode base64 secret key. | |
""" | |
def generate_secret do | |
:crypto.strong_rand_bytes(@block_size) | |
|> :base64.encode() | |
end | |
@doc """ | |
Encrypt data using `:aes_128_cbc` mode, and return base64 encrypted string | |
key = generate_secret() | |
encrypt("hello", key) | |
""" | |
@spec encrypt(String.t(), String.t()) :: String.t() | |
def encrypt(plaintext, secret_key) do | |
secret_key = :base64.decode(secret_key) | |
iv = :crypto.strong_rand_bytes(@block_size) | |
plaintext = pad(plaintext, @block_size) | |
ciphertext = :crypto.crypto_one_time(:aes_128_cbc, secret_key, iv, plaintext, true) | |
:base64.encode(iv <> ciphertext) | |
end | |
@doc """ | |
Decode cipher data which encrypted using `encrypt/2` | |
key = generate_secret() | |
cipher = encrypt("hello", key) | |
decrypt(cipher, key) | |
""" | |
def decrypt(ciphertext, secret_key) do | |
secret_key = :base64.decode(secret_key) | |
ciphertext = :base64.decode(ciphertext) | |
<<iv::binary-@block_size, ciphertext::binary>> = ciphertext | |
:crypto.crypto_one_time(:aes_128_cbc, secret_key, iv, ciphertext, false) | |
|> unpad | |
end | |
@doc """ | |
Encrypt data using `:aes_128_cbc` mode, and return base64 encrypted string | |
key = generate_secret() | |
encrypt_aead("hello", key) | |
""" | |
def encrypt_aead(plaintext, secret_key) do | |
secret_key = :base64.decode(secret_key) | |
iv = :crypto.strong_rand_bytes(@block_size) | |
{ciphertext, ciphertag} = | |
:crypto.crypto_one_time_aead(:aes_128_gcm, secret_key, iv, plaintext, @aad, true) | |
(iv <> ciphertag <> ciphertext) | |
|> :base64.encode() | |
end | |
@doc """ | |
Decode cipher data which encrypted using `encrypt/2` | |
key = generate_secret() | |
cipher = encrypt_aead("hello", key) | |
decrypt_aead(cipher, key) | |
""" | |
def decrypt_aead(ciphertext, secret_key) do | |
secret_key = :base64.decode(secret_key) | |
ciphertext = :base64.decode(ciphertext) | |
<<iv::binary-@block_size, tag::binary-@block_size, ciphertext::binary>> = ciphertext | |
:crypto.crypto_one_time_aead(:aes_128_gcm, secret_key, iv, ciphertext, @aad, tag, false) | |
end | |
defp pad(data, block_size) do | |
to_add = block_size - rem(byte_size(data), block_size) | |
data <> :binary.copy(<<to_add>>, to_add) | |
end | |
defp unpad(data) do | |
to_remove = :binary.last(data) | |
:binary.part(data, 0, byte_size(data) - to_remove) | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment