From a634c97342d7b4bf208c251a3f44a805492312d3 Mon Sep 17 00:00:00 2001 From: Dominic Letz Date: Thu, 20 Feb 2025 23:44:31 +0100 Subject: [PATCH 1/2] Fallback if native hash_equals is not available. --- lib/plug/crypto.ex | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/lib/plug/crypto.ex b/lib/plug/crypto.ex index 65e9d14..d3ec11a 100644 --- a/lib/plug/crypto.ex +++ b/lib/plug/crypto.ex @@ -130,25 +130,32 @@ defmodule Plug.Crypto do byte_size(left) == byte_size(right) and crypto_hash_equals(left, right) end - # TODO: remove when we require OTP 25.0 if Code.ensure_loaded?(:crypto) and function_exported?(:crypto, :hash_equals, 2) do defp crypto_hash_equals(x, y) do - :crypto.hash_equals(x, y) + # Depending on the linked OpenSSL library hash_equals is available. + # If not, we fall back to the legacy implementation. + try do + :crypto.hash_equals(x, y) + rescue + # Still can throw "Unsupported CRYPTO_memcmp" + ErlangError -> + legacy_secure_compare(x, y, 0) + end end else defp crypto_hash_equals(x, y) do legacy_secure_compare(x, y, 0) end + end - defp legacy_secure_compare(<>, <>, acc) do - import Bitwise - xorred = bxor(x, y) - legacy_secure_compare(left, right, acc ||| xorred) - end + defp legacy_secure_compare(<>, <>, acc) do + import Bitwise + xorred = bxor(x, y) + legacy_secure_compare(left, right, acc ||| xorred) + end - defp legacy_secure_compare(<<>>, <<>>, acc) do - acc === 0 - end + defp legacy_secure_compare(<<>>, <<>>, acc) do + acc === 0 end @doc """ From 3f964c2a69003b605ecc24309de53105fb30b47b Mon Sep 17 00:00:00 2001 From: Dominic Letz Date: Wed, 2 Apr 2025 15:45:19 +0200 Subject: [PATCH 2/2] Readd comment --- lib/plug/crypto.ex | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/plug/crypto.ex b/lib/plug/crypto.ex index d3ec11a..682ec05 100644 --- a/lib/plug/crypto.ex +++ b/lib/plug/crypto.ex @@ -130,6 +130,7 @@ defmodule Plug.Crypto do byte_size(left) == byte_size(right) and crypto_hash_equals(left, right) end + # TODO: remove when we require OTP 25.0 if Code.ensure_loaded?(:crypto) and function_exported?(:crypto, :hash_equals, 2) do defp crypto_hash_equals(x, y) do # Depending on the linked OpenSSL library hash_equals is available.