在 C# 中验证 HMACSHA256

Validating HMACSHA256 in C#

我是 asp.net/c# 的新手,我正在尝试在 C# 中重新创建密码验证。我将此哈希存储在数据库中: U2zdbUmZXCeOLs0OuS9bhg==7hQ60TTq0ZiT/z+eu4bdzpmBcp5uYa70ZDxQPncEG0c=

这个散列的密码是 1234567。这是有效的,因为我可以在 web 应用程序中使用这个密码登录。

所以如果我没理解错的话。散列由 base64 编码的盐 U2zdbUmZXCeOLs0OuS9bhg== 和使用此盐散列的密码组成:7hQ60TTq0ZiT/z+eu4bdzpmBcp5uYa70ZDxQPncEG0c=

但是如果我使用我在互联网上找到的这个例子。我没有得到相同的哈希结果。我已经尝试过使用编码(产生不同的哈希值),但没有成功。 hashAlgorithmType 在 web.config 中设置为 HMACSHA256。我做错了什么?

using System;
using System.Security.Cryptography;
using System.Text;

public class Program
{
    public static void Main()
    {

        var base64Salt = "U2zdbUmZXCeOLs0OuS9bhg==";  
        var base64Hash = "7hQ60TTq0ZiT/z+eu4bdzpmBcp5uYa70ZDxQPncEG0c=";
        // Decode the base64 salt to get the salt byte array
        var saltBytes = Convert.FromBase64String(base64Salt);

        // Provide the user's plain password
        var plaintextPassword = "1234567";

        // Salt the plaintext password, prepend to user's provided password, and then hash
        try
        {
            var hmac256 = new HMACSHA256(saltBytes);
            var hash = Convert.ToBase64String(hmac256.ComputeHash(Encoding.UTF8.GetBytes(plaintextPassword)));   
            Console.WriteLine(base64Salt+hash);
            if (hash == base64Hash)
            {
                Console.WriteLine("Success! Both hashes match!");
            }
            else
            {
                Console.WriteLine("Passwords do not match.");
            }
        }
        catch (Exception e)
        {
            Console.WriteLine("Error!", e.Message);
        }
    }
}

您需要知道使用的正确密钥以及密码如何与盐连接。

通常,salt 字节与密码字节连接在一起,如下所示:

var password = "1234567";
var passwordBytes = Encoding.UTF8.GetBytes(password);

var salt = "U2zdbUmZXCeOLs0OuS9bhg==";
var saltBytes = Convert.FromBase64String(salt);

var passwordBytesAndSaltBytes = new byte[passwordBytes.Length + saltBytes.Length];

for (int i = 0; i < passwordBytes.Length; i++)
{
    passwordBytesAndSaltBytes[i] = passwordBytes[i];
}

for (int i = 0; i < saltBytes.Length; i++)
{
    passwordBytesAndSaltBytes[passwordBytes.Length + i] = saltBytes[i];
}

但我们不知道使用的规则是什么。

而且秘密很好,保密,像这样:

var secret = "this must be hidden";
var secretBytes = Encoding.UTF8.GetBytes(secret);

var hmac256 = new HMACSHA256(secretBytes);
var hash = Convert.ToBase64String(hmac256.ComputeHash(passwordBytesAndSaltBytes) );

很遗憾,如果没有看到代码,我认为您无法复制它。

终于成功了!我在 Umbraco 的源代码中找到了答案(我使用 Umbraco 作为 CMS)。我以为它使用的是默认的 membershipprovider 但它不是......另外值得一提的是盐是所需密钥长度的缩写,所以它被扩展了。

根据源代码我做了一个工作示例:

using System;
using System.Security.Cryptography;
using System.Text;

public class Program
{
    public static void Main()
    {
        var bytes = Encoding.Unicode.GetBytes("1234567");
        var saltBytes = Convert.FromBase64String("U2zdbUmZXCeOLs0OuS9bhg==");
        byte[] inArray;
        var hashAlgorithm = HashAlgorithm.Create("HMACSHA256");
        var algorithm = hashAlgorithm as KeyedHashAlgorithm;
                    var keyedHashAlgorithm = algorithm;
                    if (keyedHashAlgorithm.Key.Length == saltBytes.Length)
                    {
                        //if the salt bytes is the required key length for the algorithm, use it as-is
                        keyedHashAlgorithm.Key = saltBytes;
                        Console.WriteLine("length is ok");
                    }
                    else if (keyedHashAlgorithm.Key.Length < saltBytes.Length)
                    {
                        //if the salt bytes is too long for the required key length for the algorithm, reduce it
                        var numArray2 = new byte[keyedHashAlgorithm.Key.Length];
                        Buffer.BlockCopy(saltBytes, 0, numArray2, 0, numArray2.Length);
                        keyedHashAlgorithm.Key = numArray2;
                        Console.WriteLine("salt byte too long");
                    }
                    else
                    {
                        //if the salt bytes is too short for the required key length for the algorithm, extend it
                        Console.WriteLine("salt byte to short");
                        var numArray2 = new byte[keyedHashAlgorithm.Key.Length];
                        var dstOffset = 0;
                        while (dstOffset < numArray2.Length)
                        {
                            var count = Math.Min(saltBytes.Length, numArray2.Length - dstOffset);
                            Buffer.BlockCopy(saltBytes, 0, numArray2, dstOffset, count);
                            dstOffset += count;
                        }
                        keyedHashAlgorithm.Key = numArray2;
                    }
                    inArray = keyedHashAlgorithm.ComputeHash(bytes);

        var hash = Convert.ToBase64String(inArray);
        Console.WriteLine(hash);        
        var base64Hash = "7hQ60TTq0ZiT/z+eu4bdzpmBcp5uYa70ZDxQPncEG0c=";

            if (hash == base64Hash)
            {
                Console.WriteLine("Success! Both hashes match!");
            }
            else
            {
                Console.WriteLine("Passwords do not match.");
            }
    }
}