Elixir: Cryptography

Because we’re managing sensitive data we do not want to have it spread all over, this is why we decided to encrypt with AES our saved logs to be sure that nobody except us can access it, but to allow others to be sure we authored the data we signed it using RSA.

Thus I’ll explain how you can use the ex_crypto library to do such operations. You may refresh your knowledges by going on some AES and RSA documentation to really understand how we’ll use the library.

First of all we want to encrypt our data, for this we’ll need a private key that you should never give to anyone. For this you can use the ExCrypto.generate_aes_key/2 which allows you to generate raw key or base64 encoded. For simplicity we’ll consider that the key is in base64.

Then we encrypt our data using the ExCrypto.encrypt/3 which will generate an initialization vector and expect a tag that we’ll leave blank.

defp encrypt(key, message) do
  with {:ok, {_ad, {init_vec, cipher_text, cipher_tag}}} <- ExCrypto.encrypt(key, "", message) do
    ExCrypto.encode_payload(init_vec, cipher_text, cipher_tag)

Then we call the ExCrypto.encode_payload/3 which will serialize the three components (initialization vector, ciphered text and ciphered tag) in a base64 string for transportation.

Now that we have our encoded payload we want to sign it to show that we are the author of this generated data. This is done using asymmetric signature. Same as before we need a private key that can be generated using ExPublicKey.generate_key/2. To make it transportable you can use the ExPublicKey.pem_encode/1 function which will generate a PEM string.

Then we’ll sign our base64 payload with our freshly generated private key. Tips: for those who can’t use the key try to unescape line return special characters from the string as it can be escaped on some systems if used as an environment variable.

defp sign(payload) when is_bitstring(payload) do
  with {:ok, private_key} <- ExPublicKey.loads(key),
       {:ok, signature} <- ExPublicKey.sign(payload, private_key) do
    {:ok, Enum.join([payload, Base.url_encode64(signature)], "|")}

Once we have signed the payload we attach the signature (as base64) at the end of the payload separated by a pipe. Note: JWS protocol rather use a dot separator.
Now that we have a signed payload we need to see how to verify it. This could be done by anyone with your public RSA key. But for fun we’ll do it in Elixir, first you’ll need to separate the encoded payload from the signature using
[encoded_payload, signature] = String.split(encoded_payload, "|")

defp verify(encoded_payload, signature) do
  with {:ok, private_key} <- ExPublicKey.loads(key),
       {:ok, public_key} <- ExPublicKey.public_key_from_private_key(private_key) do
    ExPublicKey.verify(encoded_payload, Base.url_decode64!(signature), public_key)

Then you can call the verify/2 function defined above which will load the key as PEM string, get the public key from your private key and verify the provided payload. Note: in real usages you'll provide the public key directly.

Now that you are sure the payload is yours you can safely decrypt it using your private AES key as follow

defp decrypt(key, encoded_payload) do
  with {:ok, {d_init_vec, d_cipher_text, d_cipher_tag}} <-
         ExCrypto.decode_payload(encoded_payload) do
    ExCrypto.decrypt(key, "", d_init_vec, d_cipher_text, d_cipher_tag)

We see that we decode the payload first to load all necessary decryption information, the initialization vector, the tag and the encrypted text using ExCrypto.decode_payload/1. Then we’re ready to decrypt it using ExCrypto.decrypt/5.

And voila, you’re now able to crypt and sign data transportable on the wire if you need to. Another interesting usage would have been to crypt using RSA public key so someone else could decrypt data at the other end. Signature on the other end is done using your private RSA key.

Note that all AES related features are available in ExCrypto module meanwhile all RSA features are in ExPublicKey for a nice separation of concerns. Note that ExCrypto is mainly a sugar around the :crypto Erlang module.

I hope you’ve learn something thanks to this post and that it will make you want to give a try to Elixir.

No comments:

Post a Comment

Merci de votre commentaire. Celui-ci est en cours de modération.

Most seen