2022年4月16日 星期六

[研究][ASP.NET][C#]PBKDF2計算密碼雜湊試用

[研究][ASP.NET][C#]PBKDF2計算密碼雜湊試用

2022-04-16

PBKDF2簡單而言就是將salted hash進行多次重複計算

PBKDF2 是 Password-Based Key Derivation Function 的縮寫,即「基於密碼的密鑰推導函數」。

Pbkdf2Class.cs
using System;
using System.Security.Cryptography;

namespace WebApplication2
{
    public class Pbkdf2Class
    {
        private const int SaltByteSize = 32;
        private const int HashByteSize = 32;
        private const int Iterations = 4096;

        private static string GetSalt()
        {
            var cryptoProvider = new RNGCryptoServiceProvider();
            byte[] b_salt = new byte[SaltByteSize];
            cryptoProvider.GetBytes(b_salt);
            return Convert.ToBase64String(b_salt);
        }

        public static string GetPasswordHash(string password)
        {
            string salt = GetSalt();

            byte[] saltBytes = Convert.FromBase64String(salt);
            byte[] derived;

            using (var pbkdf2 = new Rfc2898DeriveBytes(
                password,
                saltBytes,
                Iterations,
                HashAlgorithmName.SHA512))
            {
                derived = pbkdf2.GetBytes(HashByteSize);
            }

            return string.Format("{0}:{1}:{2}", Iterations, 
                Convert.ToBase64String(derived), Convert.ToBase64String(saltBytes));
        }

        public static string GetPasswordHash(string password, 
            HashAlgorithmName hashAlgorithmName)
        {
            string salt = GetSalt();

            byte[] saltBytes = Convert.FromBase64String(salt);
            byte[] derived;

            using (var pbkdf2 = new Rfc2898DeriveBytes(
                password,
                saltBytes,
                Iterations,
                hashAlgorithmName))
                //HashAlgorithmName.SHA512))
            {
                derived = pbkdf2.GetBytes(HashByteSize);
            }

            return string.Format("{0}:{1}:{2}", Iterations, 
                Convert.ToBase64String(derived), Convert.ToBase64String(saltBytes));
        }

        public static bool VerifyPasswordHash(string password, string hash)
        {
            try
            {
                string[] parts = hash.Split(new char[] { ':' });

                byte[] saltBytes = Convert.FromBase64String(parts[2]);
                byte[] derived;

                int iterations = Convert.ToInt32(parts[0]);

                using (var pbkdf2 = new Rfc2898DeriveBytes(
                    password,
                    saltBytes,
                    iterations,
                    HashAlgorithmName.SHA512))
                {
                    derived = pbkdf2.GetBytes(HashByteSize);
                }

                string new_hash = string.Format("{0}:{1}:{2}", Iterations, 
                    Convert.ToBase64String(derived), Convert.ToBase64String(saltBytes));

                return hash == new_hash;
            }
            catch
            {
                return false;
            }
        }

        public static bool VerifyPasswordHash(string password, string hash, 
            HashAlgorithmName hashAlgorithmName)
        {
            try
            {
                string[] parts = hash.Split(new char[] { ':' });

                byte[] saltBytes = Convert.FromBase64String(parts[2]);
                byte[] derived;

                int iterations = Convert.ToInt32(parts[0]);

                using (var pbkdf2 = new Rfc2898DeriveBytes(
                    password,
                    saltBytes,
                    iterations,
                    hashAlgorithmName))
                    //HashAlgorithmName.SHA512))
                {
                    derived = pbkdf2.GetBytes(HashByteSize);
                }

                string new_hash = string.Format("{0}:{1}:{2}", Iterations, 
                    Convert.ToBase64String(derived), Convert.ToBase64String(saltBytes));

                return hash == new_hash;
            }
            catch
            {
                return false;
            }
        }
    }
}

Default.aspx

<%@ Page Language="C#" AutoEventWireup="true" 
    CodeBehind="Default.aspx.cs" Inherits="WebApplication2.Default" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
        <div>
            <asp:TextBox ID="TextBox1" runat="server"></asp:TextBox><br />
            <asp:Button ID="Button1" runat="server" Text="Button" 
                OnClick="Button1_Click" /><br />
            <asp:Label ID="Label1" runat="server"></asp:Label><br />
            <asp:Label ID="Label2" runat="server"></asp:Label><br />
        </div>
    </form>
</body>
</html>



Default.aspx.cs

using System;
using System.Security.Cryptography;

namespace WebApplication2
{
    public partial class Default : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {

        }

        protected void Button1_Click(object sender, EventArgs e)
        {
            //Label1.Text= Pbkdf2Class.GetPasswordHash(TextBox1.Text);
            Label1.Text = Pbkdf2Class.GetPasswordHash(TextBox1.Text, 
                HashAlgorithmName.SHA512);
            Label2.Text = Label1.Text.Length.ToString();
        }
    }
}

結果

(完)

相關

KeyDerivation.Pbkdf2(String, Byte[], KeyDerivationPrf, Int32, Int32) 方法 (Microsoft.AspNetCore.Cryptography.KeyDerivation) | Microsoft Docs
https://docs.microsoft.com/zh-tw/dotnet/api/microsoft.aspnetcore.cryptography.keyderivation.keyderivation.pbkdf2?view=aspnetcore-6.0

C#學習網誌: Password hash using PBKDF2 with HMAC SHA256/ SHA512 in .NET Framework 4.7.2 and .NET Core 2.0
http://vegeee-csharp.blogspot.com/2019/05/password-hash-using-pbkdf2-with-hmac.html?m=1

如何安全的加密使用者的密碼 使用 PBKDF2 - HackMD
https://hackmd.io/@Not/Pbkdf2

Information on RFC 2898 » RFC Editor
https://www.rfc-editor.org/info/rfc2898

Rfc2898DeriveBytes 類別 (System.Security.Cryptography) | Microsoft Docs
https://docs.microsoft.com/zh-tw/dotnet/api/system.security.cryptography.rfc2898derivebytes?view=net-6.0



沒有留言:

張貼留言