defmodule Radius.Util do require Logger import Bitwise def encrypt_rfc2865(passwd, secret, auth) do passwd |> pad_to_16() |> hash_xor(auth, secret, []) end def decrypt_rfc2865(passwd, secret, auth) do passwd |> hash_xor(auth, secret, [], reverse: true) |> String.trim_trailing("\0") end def encrypt_rfc2868(passwd, secret, auth) do salt = :crypto.strong_rand_bytes(2) encrypted = passwd |> pad_to_16() |> hash_xor(auth <> salt, secret, []) salt <> encrypted end def decrypt_rfc2868(<>, secret, auth) do passwd |> hash_xor(auth <> salt, secret, [], reverse: true) |> String.trim_trailing("\0") end defp hash_xor(input, hash, secret, acc, opts \\ []) defp hash_xor(<<>>, _, _, acc, _) do acc |> Enum.reverse() |> :erlang.iolist_to_binary() end defp hash_xor(<>, hash, secret, acc, opts) do hash = :crypto.hash(:md5, secret <> hash) xor_block = binary_xor(block, hash) next = if(opts |> Keyword.get(:reverse, false), do: block, else: xor_block) hash_xor(rest, next, secret, [xor_block | acc]) end defp binary_xor(x, y) when byte_size(x) == byte_size(y) do s = byte_size(x) * 8 <> = x <> = y z = bxor(x, y) <> end defp pad_to_16(bin) do pad_to_16(bin, []) |> Enum.reverse() |> :erlang.iolist_to_binary() end defp pad_to_16(bin, acc) when byte_size(bin) == 16, do: [bin | acc] defp pad_to_16(bin, acc) when byte_size(bin) < 16 do bin = <> <> = bin [chunk | acc] end defp pad_to_16(<>, acc), do: pad_to_16(rest, [chunk | acc]) end