From 05fc94dc6e3b49fb3bce0965d9e96cba07659fa1 Mon Sep 17 00:00:00 2001 From: Riadh Date: Tue, 24 May 2022 19:53:25 +0200 Subject: [PATCH 1/2] Return errors from decode_payload Making the return type compatible with the method's typespec, also stopping raising exceptions when base64 decoding fails or in case the decoded payload is too small. --- lib/ex_crypto.ex | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/lib/ex_crypto.ex b/lib/ex_crypto.ex index c8c3f46..2ec7127 100644 --- a/lib/ex_crypto.ex +++ b/lib/ex_crypto.ex @@ -461,12 +461,16 @@ defmodule ExCrypto do """ @spec decode_payload(binary) :: {:ok, {binary, binary, binary}} | {:error, binary} def decode_payload(encoded_parts) 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_tag = Kernel.binary_part(decoded_parts, decoded_length, -16) - {:ok, {iv, cipher_text, cipher_tag}} + with {:ok, decoded_parts} <- Base.url_decode64(encoded_parts), + decoded_length when decoded_length >= 32 <- byte_size(decoded_parts) do + iv = Kernel.binary_part(decoded_parts, 0, 16) + 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}} + else + :error -> {:error, "invalid base64 payload"} + _ -> {:error, "invalid decoded payload length"} + end end @doc false From d783285daaa6b5848f37f3df3a5ad7b57c740a21 Mon Sep 17 00:00:00 2001 From: Riadh Date: Tue, 14 Jun 2022 22:14:12 +0200 Subject: [PATCH 2/2] Include test case for the payload decoding fix --- test/ex_crypto_test.exs | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/test/ex_crypto_test.exs b/test/ex_crypto_test.exs index ecc55e8..b095692 100644 --- a/test/ex_crypto_test.exs +++ b/test/ex_crypto_test.exs @@ -140,6 +140,13 @@ defmodule ExCryptoTest do assert(cipher_tag == pc_tag) end + test "errors decoding invalid payloads" do + assert {:error, "invalid base64 payload"} = ExCrypto.decode_payload(".") + + assert {:error, "invalid decoded payload length"} = + Base.url_encode64("AAAAAAAAAAAAAAAA") |> ExCrypto.decode_payload() + end + test "test aes_cbc encrypt with auto-IV (256 bit key)" do {:ok, aes_256_key} = ExCrypto.generate_aes_key(:aes_256, :bytes) @@ -185,7 +192,8 @@ defmodule ExCryptoTest do {:ok, {_ad, payload}} = ExCrypto.encrypt(aes_256_key, a_data, iv, clear_text) {_c_iv, cipher_text, cipher_tag} = payload # decrypt - assert {:error, :decrypt_failed} = ExCrypto.decrypt(aes_256_key, "wrong ad", iv, cipher_text, cipher_tag) + assert {:error, :decrypt_failed} = + ExCrypto.decrypt(aes_256_key, "wrong ad", iv, cipher_text, cipher_tag) end test "errors decrypting with argument error (cipher_text)" do @@ -203,9 +211,11 @@ defmodule ExCryptoTest do txt_joined = IO.iodata_to_binary(txt) aad = "Some bytes" - cipher_text = <<240, 130, 38, 96, 130, 241, 189, 52, 3, 190, 179, 213, 132, 1, 72, 192, 103, - 176, 90, 104, 15, 71, 158>> - cipher_tag = <<131, 47, 45, 91, 142, 85, 9, 244, 21, 141, 214, 71, 31, 135, 2, 155>> + cipher_text = + <<240, 130, 38, 96, 130, 241, 189, 52, 3, 190, 179, 213, 132, 1, 72, 192, 103, 176, 90, 104, + 15, 71, 158>> + + cipher_tag = <<131, 47, 45, 91, 142, 85, 9, 244, 21, 141, 214, 71, 31, 135, 2, 155>> # encrypt {:ok, {^aad, {^iv, ^cipher_text, ^cipher_tag}}} = ExCrypto.encrypt(key, aad, iv, txt)