C# 使用MD5或sha-256 C哈希密码#

C# 使用MD5或sha-256 C哈希密码#,c#,hash,sha256,C#,Hash,Sha256,我正在为一份申请写一份登记表,但作为c#的新手,我仍然有一些问题 我希望将密码加密/散列到md5或sha-256,最好是sha-256 有好的例子吗?我希望它能够从“stringpassword;”获取信息,然后将其散列并存储在变量“stringhpassword;”中。有什么想法吗?您需要使用名称空间;具体地说,是或 从上面的代码中提取一些信息,并且知道两个类都有相同的基类(),您可以使用如下函数: public string ComputeHash(string input, HashAlg

我正在为一份申请写一份登记表,但作为c#的新手,我仍然有一些问题

我希望将密码加密/散列到md5或sha-256,最好是sha-256


有好的例子吗?我希望它能够从“stringpassword;”获取信息,然后将其散列并存储在变量“stringhpassword;”中。有什么想法吗?

您需要使用名称空间;具体地说,是或

从上面的代码中提取一些信息,并且知道两个类都有相同的基类(),您可以使用如下函数:

public string ComputeHash(string input, HashAlgorithm algorithm)
{
   Byte[] inputBytes = Encoding.UTF8.GetBytes(input);

   Byte[] hashedBytes = algorithm.ComputeHash(inputBytes);

   return BitConverter.ToString(hashedBytes);
}
然后您可以这样称呼它(对于MD5):

或者对于SHA256:

string hPassword = ComputeHash(password, new SHA256CryptoServiceProvider());

编辑:添加盐支持
正如dtb在评论中指出的那样,如果该代码包含添加的功能,那么它将更加强大。如果您不熟悉它,salt是一组随机位,作为哈希函数的输入包含在其中,这对于阻止针对哈希密码的字典攻击(例如,使用密码)有很大帮助。下面是支持salt的
ComputeHash
函数的修改版本:

public static string ComputeHash(string input, HashAlgorithm algorithm, Byte[] salt)
{
   Byte[] inputBytes = Encoding.UTF8.GetBytes(input);

   // Combine salt and input bytes
   Byte[] saltedInput = new Byte[salt.Length + inputBytes.Length];
   salt.CopyTo(saltedInput, 0);
   inputBytes.CopyTo(saltedInput, salt.Length);

   Byte[] hashedBytes = algorithm.ComputeHash(saltedInput);

   return BitConverter.ToString(hashedBytes);
}

希望这有帮助

System.Security.Cryptography.SHA256类应该完成以下任务:


如果要存储哈希密码,请使用SHA-256而不是。问题在于,SHA-256针对速度进行了优化,这使得在有人访问您的数据库时更容易对密码进行暴力攻击

阅读这篇文章:这是一个前一个问题

文章中的一些引语:

问题是MD5速度很快。它的现代竞争对手也是如此,比如SHA1和SH256。速度是现代安全散列的一个设计目标,因为散列是几乎所有密码系统的一个构建块,通常在每个数据包或每个消息的基础上执行请求

速度正是您在密码哈希函数中不想要的。


最后,我们了解到,如果我们想要安全地存储密码,我们有三个合理的选择:PHK的MD5方案、Provos Maziere的Bcrypt方案和SRP。我们知道正确的选择是Bcrypt


不要使用简单的杂烩,甚至盐杂烩。使用一些关键强化技术,如(使用a)或(使用a)

下面是一个使用PBKDF2的示例

要从密码生成密钥

string password = GetPasswordFromUserInput();

// specify that we want to randomly generate a 20-byte salt
using (var deriveBytes = new Rfc2898DeriveBytes(password, 20))
{
    byte[] salt = deriveBytes.Salt;
    byte[] key = deriveBytes.GetBytes(20);  // derive a 20-byte key

    // save salt and key to database
}
然后测试密码是否有效

string password = GetPasswordFromUserInput();

byte[] salt, key;
// load salt and key from database

using (var deriveBytes = new Rfc2898DeriveBytes(password, salt))
{
    byte[] newKey = deriveBytes.GetBytes(20);  // derive a 20-byte key

    if (!newKey.SequenceEqual(key))
        throw new InvalidOperationException("Password is invalid!");
}

在将密码存储到数据库中时,在对其进行哈希运算之前,应始终对其进行加密。

建议的数据库列:

  • 密码salt:int
  • 密码哈希:二进制(20)
你在网上找到的大多数帖子都会谈论对salt和hash进行ASCII编码,但这不是必需的,只会增加不必要的计算。此外,如果使用SHA-1,则输出将仅为20字节,因此数据库中的哈希字段长度仅需为20字节。我理解您询问SHA-256,但除非您有令人信服的理由,否则在大多数商业实践中,使用含盐量的SHA-1就足够了。如果坚持SHA-256,则数据库中的哈希字段长度需要为32字节

下面是一些函数,它们将生成salt、计算散列并根据密码验证散列

下面的salt函数从4个加密创建的随机字节中生成一个加密强salt作为整数

private int GenerateSaltForPassword()
{
    RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
    byte[] saltBytes = new byte[4];
    rng.GetNonZeroBytes(saltBytes);
    return (((int)saltBytes[0]) << 24) + (((int)saltBytes[1]) << 16) + (((int)saltBytes[2]) << 8) + ((int)saltBytes[3]);
}
检查密码只需计算哈希值,然后将其与预期的哈希值进行比较即可


private bool IsPasswordValid(string passwordToValidate, int salt, byte[] correctPasswordHash)
{
    byte[] hashedPassword = ComputePasswordHash(passwordToValidate, salt);

    return hashedPassword.SequenceEqual(correctPasswordHash);
}


PBKDF2正在使用HMACSHA1……。如果您想要更现代的HMACSHA256或HMACSHA512实现,并且仍然希望通过键拉伸来降低算法的速度,我建议您使用以下API:

以下是持久性不敏感的SecuredPassword类的完整实现

using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;


    public class SecuredPassword
    {
        private const int saltSize = 256;
        private readonly byte[] hash;
        private readonly byte[] salt;

        public byte[] Hash
        {
        get { return hash; }
    }

    public byte[] Salt
    {
        get { return salt; }
    }

    public SecuredPassword(string plainPassword)
    {
        if (string.IsNullOrWhiteSpace(plainPassword))
            return; 

        using (var deriveBytes = new Rfc2898DeriveBytes(plainPassword, saltSize))
        {
            salt = deriveBytes.Salt;
            hash = deriveBytes.GetBytes(saltSize);
        }
    }

    public SecuredPassword(byte[] hash, byte[] salt)
    {
        this.hash = hash;
        this.salt = salt;
    }

    public bool Verify(string password)
    {
        if (string.IsNullOrWhiteSpace(password))
            return false; 

        using (var deriveBytes = new Rfc2898DeriveBytes(password, salt))
        {
            byte[] newKey = deriveBytes.GetBytes(saltSize);

            return newKey.SequenceEqual(hash);
        }
    }
}
和测试:

 public class SecuredPasswordTests
{
    [Test]
    public void IsHashed_AsExpected()
    {
        var securedPassword = new SecuredPassword("password");

        Assert.That(securedPassword.Hash, Is.Not.EqualTo("password"));
        Assert.That(securedPassword.Hash.Length, Is.EqualTo(256));
    }

    [Test]
    public void Generates_Unique_Salt()
    {
        var securedPassword = new SecuredPassword("password");
        var securedPassword2 = new SecuredPassword("password");

        Assert.That(securedPassword.Salt, Is.Not.Null);
        Assert.That(securedPassword2.Salt, Is.Not.Null);
        Assert.That(securedPassword.Salt, Is.Not.EqualTo(securedPassword2.Salt));
    }

    [Test]
    public void Generates_Unique_Hash()
    {
        var securedPassword = new SecuredPassword("password");
        var securedPassword2 = new SecuredPassword("password");

        Assert.That(securedPassword.Hash, Is.Not.Null);
        Assert.That(securedPassword2.Hash, Is.Not.Null);
        Assert.That(securedPassword.Hash, Is.Not.EqualTo(securedPassword2.Hash));
    }

    [Test]
    public void Verify_WhenMatching_ReturnsTrue()
    {
        var securedPassword = new SecuredPassword("password");
        var result = securedPassword.Verify("password");
        Assert.That(result, Is.True);
    }

    [Test]
    public void Verify_WhenDifferent_ReturnsFalse()
    {
        var securedPassword = new SecuredPassword("password");
        var result = securedPassword.Verify("Password");
        Assert.That(result, Is.False);
    }

    [Test]
    public void Verify_WhenRehydrated_AndMatching_ReturnsTrue()
    {
        var securedPassword = new SecuredPassword("password123");

        var rehydrated = new SecuredPassword(securedPassword.Hash, securedPassword.Salt);

        var result = rehydrated.Verify("password123");
        Assert.That(result, Is.True);
    }

    [Test]
    public void Constructor_Handles_Null_Password()
    {
        Assert.DoesNotThrow(() => new SecuredPassword(null));
    }

    [Test]
    public void Constructor_Handles_Empty_Password()
    {
        Assert.DoesNotThrow(() => new SecuredPassword(string.Empty));
    }

    [Test]
    public void Verify_Handles_Null_Password()
    {
        Assert.DoesNotThrow(() => new SecuredPassword("password").Verify(null));
    }

    [Test]
    public void Verify_Handles_Empty_Password()
    {
        Assert.DoesNotThrow(() => new SecuredPassword("password").Verify(string.Empty));
    }

    [Test]
    public void Verify_When_Null_Password_ReturnsFalse()
    {
        Assert.That(new SecuredPassword("password").Verify(null), Is.False);
    }
}

请使用这个,因为我以前也有同样的问题,但可以通过litle代码片段解决它

    public static string ComputeHash(string input, HashAlgorithm algorithm, Byte[] salt)
    {
        Byte[] inputBytes = Encoding.UTF8.GetBytes(input);

        // Combine salt and input bytes
        Byte[] saltedInput = new Byte[salt.Length + inputBytes.Length];
        salt.CopyTo(saltedInput, 0);
        inputBytes.CopyTo(saltedInput, salt.Length);

        Byte[] hashedBytes = algorithm.ComputeHash(saltedInput);


        StringBuilder hex = new StringBuilder(hashedBytes.Length * 2);
        foreach (byte b in hashedBytes)
            hex.AppendFormat("{0:X2}", b);

        return hex.ToString();

    }
TL;DR使用,使用SHA-512实现PBKDF2

开始使用密码哈希的好主意是看看你说了什么。推荐的算法列表包括Argon2、PBKDF2、scrypt和bcrypt。所有这些算法都可以调整,以调整散列密码所需的时间,以及相应地,通过蛮力破解密码所需的时间。所有这些算法都利用salt来防止彩虹表攻击

这两种算法都不是很弱,但有一些区别:

  • bcrypt已存在近20年,得到了广泛的应用和推广 经受了时间的考验。它对GPU有很强的抵抗力 攻击,但不针对FPGA
  • Argon2是最新加入的,是2015年密码哈希竞赛的获胜者。它对GPU和FPGA攻击有更好的保护,但对我来说有点太新了
  • 我对斯克里普了解不多。它被设计用来阻止GPU和FPGA加速的攻击,但我听说它并不像最初宣称的那样强大
  • PBKDF2是一系列由不同哈希参数化的算法 功能。它不提供针对GPU或ASIC攻击的特定保护,特别是在使用SHA-1等较弱的哈希函数的情况下,但是,如果它对您很重要,它是经过FIPS认证的,并且如果迭代次数足够大,它仍然是可以接受的
仅基于算法,我可能会选择bcrypt,PBKDF2是最不有利的

然而,这并不是全部,因为即使是最好的算法也可能因为糟糕的实现而变得不安全。让我们看看.NET平台的可用功能:

  • Bcrypt可通过以下途径获得:。他们说该实现基于JavaJBCrypt。目前github上有6个贡献者和8个问题(全部关闭)。总的来说,它看起来不错,但是,我不知道是否有人对代码进行了审核,如果发现漏洞,很难判断是否会很快提供更新版本
     public class SecuredPasswordTests
    {
        [Test]
        public void IsHashed_AsExpected()
        {
            var securedPassword = new SecuredPassword("password");
    
            Assert.That(securedPassword.Hash, Is.Not.EqualTo("password"));
            Assert.That(securedPassword.Hash.Length, Is.EqualTo(256));
        }
    
        [Test]
        public void Generates_Unique_Salt()
        {
            var securedPassword = new SecuredPassword("password");
            var securedPassword2 = new SecuredPassword("password");
    
            Assert.That(securedPassword.Salt, Is.Not.Null);
            Assert.That(securedPassword2.Salt, Is.Not.Null);
            Assert.That(securedPassword.Salt, Is.Not.EqualTo(securedPassword2.Salt));
        }
    
        [Test]
        public void Generates_Unique_Hash()
        {
            var securedPassword = new SecuredPassword("password");
            var securedPassword2 = new SecuredPassword("password");
    
            Assert.That(securedPassword.Hash, Is.Not.Null);
            Assert.That(securedPassword2.Hash, Is.Not.Null);
            Assert.That(securedPassword.Hash, Is.Not.EqualTo(securedPassword2.Hash));
        }
    
        [Test]
        public void Verify_WhenMatching_ReturnsTrue()
        {
            var securedPassword = new SecuredPassword("password");
            var result = securedPassword.Verify("password");
            Assert.That(result, Is.True);
        }
    
        [Test]
        public void Verify_WhenDifferent_ReturnsFalse()
        {
            var securedPassword = new SecuredPassword("password");
            var result = securedPassword.Verify("Password");
            Assert.That(result, Is.False);
        }
    
        [Test]
        public void Verify_WhenRehydrated_AndMatching_ReturnsTrue()
        {
            var securedPassword = new SecuredPassword("password123");
    
            var rehydrated = new SecuredPassword(securedPassword.Hash, securedPassword.Salt);
    
            var result = rehydrated.Verify("password123");
            Assert.That(result, Is.True);
        }
    
        [Test]
        public void Constructor_Handles_Null_Password()
        {
            Assert.DoesNotThrow(() => new SecuredPassword(null));
        }
    
        [Test]
        public void Constructor_Handles_Empty_Password()
        {
            Assert.DoesNotThrow(() => new SecuredPassword(string.Empty));
        }
    
        [Test]
        public void Verify_Handles_Null_Password()
        {
            Assert.DoesNotThrow(() => new SecuredPassword("password").Verify(null));
        }
    
        [Test]
        public void Verify_Handles_Empty_Password()
        {
            Assert.DoesNotThrow(() => new SecuredPassword("password").Verify(string.Empty));
        }
    
        [Test]
        public void Verify_When_Null_Password_ReturnsFalse()
        {
            Assert.That(new SecuredPassword("password").Verify(null), Is.False);
        }
    }
    
        public static string ComputeHash(string input, HashAlgorithm algorithm, Byte[] salt)
        {
            Byte[] inputBytes = Encoding.UTF8.GetBytes(input);
    
            // Combine salt and input bytes
            Byte[] saltedInput = new Byte[salt.Length + inputBytes.Length];
            salt.CopyTo(saltedInput, 0);
            inputBytes.CopyTo(saltedInput, salt.Length);
    
            Byte[] hashedBytes = algorithm.ComputeHash(saltedInput);
    
    
            StringBuilder hex = new StringBuilder(hashedBytes.Length * 2);
            foreach (byte b in hashedBytes)
                hex.AppendFormat("{0:X2}", b);
    
            return hex.ToString();
    
        }