Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 14 additions & 3 deletions lib/plug_rails_cookie_session_store/message_encryptor.ex
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ defmodule PlugRailsCookieSessionStore.MessageEncryptor do
{:ok, verified} ->
[encrypted, iv] = String.split(verified, "--") |> Enum.map(&Base.decode64!/1)
encrypted |> decrypt(cipher, secret, iv) |> unpad_message

:error ->
:error
end
Expand All @@ -60,6 +61,7 @@ defmodule PlugRailsCookieSessionStore.MessageEncryptor do
iv = :crypto.strong_rand_bytes(16)

{message, auth_tag} = encrypt_aead(pad_message(message), cipher, secret, iv)

message
|> Base.encode64()
|> Kernel.<>("--#{Base.encode64(iv)}")
Expand All @@ -71,9 +73,16 @@ defmodule PlugRailsCookieSessionStore.MessageEncryptor do
"""
def authenticate_and_decrypt(encrypted, secret, cipher \\ :aes_gcm)
when is_binary(encrypted) and is_binary(secret) do
[encrypted, iv, auth_tag] = String.split(encrypted, "--") |> Enum.map(&Base.decode64!/1)
result = decrypt_aead(encrypted, cipher, secret, iv, auth_tag)
{:ok, result}
case String.split(encrypted, "--") |> Enum.map(&Base.decode64/1) do
[{:ok, encrypted}, {:ok, iv}, {:ok, auth_tag}] ->
case decrypt_aead(encrypted, cipher, secret, iv, auth_tag) do
:error -> :error
result -> {:ok, result}
end

_ ->
:error
end
end

defp encrypt(message, cipher, secret, iv) do
Expand Down Expand Up @@ -104,8 +113,10 @@ defmodule PlugRailsCookieSessionStore.MessageEncryptor do

defp unpad_message(msg) do
padding_size = :binary.last(msg)

if padding_size <= 16 do
msg_size = byte_size(msg)

if binary_part(msg, msg_size, -padding_size) == :binary.copy(<<padding_size>>, padding_size) do
{:ok, binary_part(msg, 0, msg_size - padding_size)}
else
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,28 +63,45 @@ defmodule PlugRailsCookieSessionStore.MessageEncryptorTest do
assert decrypted == :error

decrypted = ME.authenticate_and_decrypt(encrypted, @right)
assert decrypted == {:ok, data}
padding = <<2, 2>>
assert decrypted == {:ok, data <> padding}
end

test "it uses only the first 32 bytes to authenticate and encrypt/decrypt" do
data = <<0, "helloworld", 0>>
padding = <<4, 4, 4, 4>>
encrypted = ME.encrypt_and_authenticate(<<0, "helloworld", 0>>, @large)

decrypted = ME.authenticate_and_decrypt(encrypted, @large)
assert decrypted == {:ok, data}
assert decrypted == {:ok, data <> padding}

decrypted = ME.authenticate_and_decrypt(encrypted, @right)
assert decrypted == {:ok, data}
assert decrypted == {:ok, data <> padding}

decrypted = ME.verify_and_decrypt(encrypted, @right, @right)
assert decrypted == :error

encrypted = ME.encrypt_and_authenticate(<<0, "helloworld", 0>>, @right)

decrypted = ME.authenticate_and_decrypt(encrypted, @large)
assert decrypted == {:ok, data}
assert decrypted == {:ok, data <> padding}

decrypted = ME.authenticate_and_decrypt(encrypted, @right)
assert decrypted == {:ok, data}
assert decrypted == {:ok, data <> padding}
Comment on lines +66 to +90
Copy link
Author

@guisehn guisehn Dec 16, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Those tests were failing, padding-removal code was removed on 541b0c5 but tests were not updated

end

test "it returns :error when decrypting an invalid rails 6 message" do
encrypted =
ME.encrypt_and_authenticate(<<0, "helloworld", 0>>, @large)
# make it invalid but still base64 valid
|> String.replace(~r/[abcdef]/, "x")

decrypted = ME.authenticate_and_decrypt(encrypted, @right)
assert decrypted == :error
end

test "it returns :error when parts are not valid base64" do
decrypted = ME.authenticate_and_decrypt("a--b--c", @right)
assert decrypted == :error
end
end