From c7cd9bd5911f8393fa758e329f8786913a5c321f Mon Sep 17 00:00:00 2001 From: lain Date: Wed, 13 Jan 2021 15:09:01 +0100 Subject: Password: Add password module Replaces Pbkdf2. --- lib/pleroma/password.ex | 55 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 lib/pleroma/password.ex (limited to 'lib') diff --git a/lib/pleroma/password.ex b/lib/pleroma/password.ex new file mode 100644 index 000000000..e96249650 --- /dev/null +++ b/lib/pleroma/password.ex @@ -0,0 +1,55 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Password do + @moduledoc """ + This module implements Pleroma.Password passwords in terms of Plug.Crypto. + """ + + alias Plug.Crypto.KeyGenerator + + def decode64(str) do + str + |> String.replace(".", "+") + |> Base.decode64!(padding: false) + end + + def encode64(bin) do + bin + |> Base.encode64(padding: false) + |> String.replace("+", ".") + end + + def verify_pass(password, hash) do + ["pbkdf2-" <> digest, iterations, salt, hash] = String.split(hash, "$", trim: true) + + salt = decode64(salt) + + iterations = String.to_integer(iterations) + + digest = String.to_atom(digest) + + binary_hash = + KeyGenerator.generate(password, salt, digest: digest, iterations: iterations, length: 64) + + encode64(binary_hash) == hash + end + + def hash_pwd_salt(password, opts \\ []) do + salt = + Keyword.get_lazy(opts, :salt, fn -> + :crypto.strong_rand_bytes(16) + end) + + digest = Keyword.get(opts, :digest, :sha512) + + iterations = + Keyword.get(opts, :iterations, Pleroma.Config.get([:password, :iterations], 160_000)) + + binary_hash = + KeyGenerator.generate(password, salt, digest: digest, iterations: iterations, length: 64) + + "$pbkdf2-#{digest}$#{iterations}$#{encode64(salt)}$#{encode64(binary_hash)}" + end +end -- cgit v1.2.3 From 9106048c6191b4b16037980655514d9b5e430023 Mon Sep 17 00:00:00 2001 From: lain Date: Wed, 13 Jan 2021 15:11:11 +0100 Subject: Password: Replace Pbkdf2 with Password. --- lib/pleroma/mfa.ex | 2 +- lib/pleroma/user.ex | 2 +- lib/pleroma/web/plugs/authentication_plug.ex | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/mfa.ex b/lib/pleroma/mfa.ex index f43e03a54..29488c876 100644 --- a/lib/pleroma/mfa.ex +++ b/lib/pleroma/mfa.ex @@ -71,7 +71,7 @@ defmodule Pleroma.MFA do @spec generate_backup_codes(User.t()) :: {:ok, list(binary)} | {:error, String.t()} def generate_backup_codes(%User{} = user) do with codes <- BackupCodes.generate(), - hashed_codes <- Enum.map(codes, &Pbkdf2.hash_pwd_salt/1), + hashed_codes <- Enum.map(codes, &Pleroma.Password.hash_pwd_salt/1), changeset <- Changeset.cast_backup_codes(user, hashed_codes), {:ok, _} <- User.update_and_set_cache(changeset) do {:ok, codes} diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index cd0c64acc..04e6ffd51 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -2187,7 +2187,7 @@ defmodule Pleroma.User do defp put_password_hash( %Ecto.Changeset{valid?: true, changes: %{password: password}} = changeset ) do - change(changeset, password_hash: Pbkdf2.hash_pwd_salt(password)) + change(changeset, password_hash: Pleroma.Password.hash_pwd_salt(password)) end defp put_password_hash(changeset), do: changeset diff --git a/lib/pleroma/web/plugs/authentication_plug.ex b/lib/pleroma/web/plugs/authentication_plug.ex index c3e13858a..f7a2a3ab7 100644 --- a/lib/pleroma/web/plugs/authentication_plug.ex +++ b/lib/pleroma/web/plugs/authentication_plug.ex @@ -48,7 +48,7 @@ defmodule Pleroma.Web.Plugs.AuthenticationPlug do end def checkpw(password, "$pbkdf2" <> _ = password_hash) do - Pbkdf2.verify_pass(password, password_hash) + Pleroma.Password.verify_pass(password, password_hash) end def checkpw(_password, _password_hash) do -- cgit v1.2.3 From 87a31c5c9b903517ec0317d2a331be36f2ea5051 Mon Sep 17 00:00:00 2001 From: Lain Soykaf Date: Thu, 14 Jan 2021 14:49:39 +0100 Subject: Password -> Password.Pbkdf2 --- lib/pleroma/password/pbkdf2.ex | 55 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 lib/pleroma/password/pbkdf2.ex (limited to 'lib') diff --git a/lib/pleroma/password/pbkdf2.ex b/lib/pleroma/password/pbkdf2.ex new file mode 100644 index 000000000..747bc1d1d --- /dev/null +++ b/lib/pleroma/password/pbkdf2.ex @@ -0,0 +1,55 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Password.Pbkdf2 do + @moduledoc """ + This module implements Pleroma.Password.Pbkdf2 passwords in terms of Plug.Crypto. + """ + + alias Plug.Crypto.KeyGenerator + + def decode64(str) do + str + |> String.replace(".", "+") + |> Base.decode64!(padding: false) + end + + def encode64(bin) do + bin + |> Base.encode64(padding: false) + |> String.replace("+", ".") + end + + def verify_pass(password, hash) do + ["pbkdf2-" <> digest, iterations, salt, hash] = String.split(hash, "$", trim: true) + + salt = decode64(salt) + + iterations = String.to_integer(iterations) + + digest = String.to_atom(digest) + + binary_hash = + KeyGenerator.generate(password, salt, digest: digest, iterations: iterations, length: 64) + + encode64(binary_hash) == hash + end + + def hash_pwd_salt(password, opts \\ []) do + salt = + Keyword.get_lazy(opts, :salt, fn -> + :crypto.strong_rand_bytes(16) + end) + + digest = Keyword.get(opts, :digest, :sha512) + + iterations = + Keyword.get(opts, :iterations, Pleroma.Config.get([:password, :iterations], 160_000)) + + binary_hash = + KeyGenerator.generate(password, salt, digest: digest, iterations: iterations, length: 64) + + "$pbkdf2-#{digest}$#{iterations}$#{encode64(salt)}$#{encode64(binary_hash)}" + end +end -- cgit v1.2.3 From 39f3683a06aea3d6aed85c611b0db0f6ea21052a Mon Sep 17 00:00:00 2001 From: Lain Soykaf Date: Thu, 14 Jan 2021 15:06:16 +0100 Subject: Pbkdf2: Use it everywhere. --- lib/pleroma/mfa.ex | 2 +- lib/pleroma/password.ex | 55 ---------------------------- lib/pleroma/password/pbkdf2.ex | 2 +- lib/pleroma/user.ex | 2 +- lib/pleroma/web/plugs/authentication_plug.ex | 2 +- 5 files changed, 4 insertions(+), 59 deletions(-) delete mode 100644 lib/pleroma/password.ex (limited to 'lib') diff --git a/lib/pleroma/mfa.ex b/lib/pleroma/mfa.ex index 29488c876..02dce7d49 100644 --- a/lib/pleroma/mfa.ex +++ b/lib/pleroma/mfa.ex @@ -71,7 +71,7 @@ defmodule Pleroma.MFA do @spec generate_backup_codes(User.t()) :: {:ok, list(binary)} | {:error, String.t()} def generate_backup_codes(%User{} = user) do with codes <- BackupCodes.generate(), - hashed_codes <- Enum.map(codes, &Pleroma.Password.hash_pwd_salt/1), + hashed_codes <- Enum.map(codes, &Pleroma.Password.Pbkdf2.hash_pwd_salt/1), changeset <- Changeset.cast_backup_codes(user, hashed_codes), {:ok, _} <- User.update_and_set_cache(changeset) do {:ok, codes} diff --git a/lib/pleroma/password.ex b/lib/pleroma/password.ex deleted file mode 100644 index e96249650..000000000 --- a/lib/pleroma/password.ex +++ /dev/null @@ -1,55 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2021 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Password do - @moduledoc """ - This module implements Pleroma.Password passwords in terms of Plug.Crypto. - """ - - alias Plug.Crypto.KeyGenerator - - def decode64(str) do - str - |> String.replace(".", "+") - |> Base.decode64!(padding: false) - end - - def encode64(bin) do - bin - |> Base.encode64(padding: false) - |> String.replace("+", ".") - end - - def verify_pass(password, hash) do - ["pbkdf2-" <> digest, iterations, salt, hash] = String.split(hash, "$", trim: true) - - salt = decode64(salt) - - iterations = String.to_integer(iterations) - - digest = String.to_atom(digest) - - binary_hash = - KeyGenerator.generate(password, salt, digest: digest, iterations: iterations, length: 64) - - encode64(binary_hash) == hash - end - - def hash_pwd_salt(password, opts \\ []) do - salt = - Keyword.get_lazy(opts, :salt, fn -> - :crypto.strong_rand_bytes(16) - end) - - digest = Keyword.get(opts, :digest, :sha512) - - iterations = - Keyword.get(opts, :iterations, Pleroma.Config.get([:password, :iterations], 160_000)) - - binary_hash = - KeyGenerator.generate(password, salt, digest: digest, iterations: iterations, length: 64) - - "$pbkdf2-#{digest}$#{iterations}$#{encode64(salt)}$#{encode64(binary_hash)}" - end -end diff --git a/lib/pleroma/password/pbkdf2.ex b/lib/pleroma/password/pbkdf2.ex index 747bc1d1d..2fd5f4491 100644 --- a/lib/pleroma/password/pbkdf2.ex +++ b/lib/pleroma/password/pbkdf2.ex @@ -4,7 +4,7 @@ defmodule Pleroma.Password.Pbkdf2 do @moduledoc """ - This module implements Pleroma.Password.Pbkdf2 passwords in terms of Plug.Crypto. + This module implements Pbkdf2 passwords in terms of Plug.Crypto. """ alias Plug.Crypto.KeyGenerator diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 04e6ffd51..6a81adfd6 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -2187,7 +2187,7 @@ defmodule Pleroma.User do defp put_password_hash( %Ecto.Changeset{valid?: true, changes: %{password: password}} = changeset ) do - change(changeset, password_hash: Pleroma.Password.hash_pwd_salt(password)) + change(changeset, password_hash: Pleroma.Password.Pbkdf2.hash_pwd_salt(password)) end defp put_password_hash(changeset), do: changeset diff --git a/lib/pleroma/web/plugs/authentication_plug.ex b/lib/pleroma/web/plugs/authentication_plug.ex index f7a2a3ab7..8d58169cf 100644 --- a/lib/pleroma/web/plugs/authentication_plug.ex +++ b/lib/pleroma/web/plugs/authentication_plug.ex @@ -48,7 +48,7 @@ defmodule Pleroma.Web.Plugs.AuthenticationPlug do end def checkpw(password, "$pbkdf2" <> _ = password_hash) do - Pleroma.Password.verify_pass(password, password_hash) + Pleroma.Password.Pbkdf2.verify_pass(password, password_hash) end def checkpw(_password, _password_hash) do -- cgit v1.2.3