RNGCryptoServiceProvider不会为相同的PWD,Salt,迭代组合生成相同的哈希值

Vip*_*esh 4 c# hash cryptography pbkdf2

Oki所以我想通过在.Net中添加随机盐来哈希我的密码.我用于此目的的内置类是RNGCryptoServiceProvider - 生成随机盐和Rfc2898DeriveBytes - 来散列实际密码.

但是当我调用Rfc2898DeriveBytes的GetBytes()函数以获得相同的passwordString,SaltBytes和Iteration计数组合时,结果会有所不同.我粘贴我的代码以供参考

    public class PBKDF2Implementation
    {
        int minSaltSize = 32;
        int maxSaltSize = 64;


        public string CreateHash(string plainText , out string  salt)
        {
            Random random = new Random();
            int saltSize = random.Next(minSaltSize, maxSaltSize);

            // Allocate a byte array, which will hold the salt.
            byte[] saltBytes = new byte[saltSize];

            // Initialize a random number generator.
            RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
            // Fill the salt with cryptographically strong byte values.
            rng.GetNonZeroBytes(saltBytes);

            string strSalt = System.Text.Encoding.ASCII.GetString(saltBytes);
            //string strSalt = System.Convert.ToBase64String(saltBytes);
            salt = strSalt;

            Console.WriteLine(saltBytes.Count());
            Console.WriteLine(strSalt);

            Rfc2898DeriveBytes pwdGen = new Rfc2898DeriveBytes(plainText, saltBytes, 1000);

            // generate an RC2 key
            byte[] key = pwdGen.GetBytes(32);

            Console.WriteLine(System.Convert.ToBase64String(key));
            return System.Convert.ToBase64String(key);
        }

        public bool CompareHash(string plainText, string salt, string hashValue)
        {

            byte[] saltBytes = System.Text.Encoding.ASCII.GetBytes(salt);
            //byte[] saltBytes = System.Convert.FromBase64String(salt);

            Console.WriteLine(saltBytes.Count());
            Console.WriteLine(System.Text.Encoding.ASCII.GetString(saltBytes));

            Rfc2898DeriveBytes pwdGen = new Rfc2898DeriveBytes(plainText, saltBytes, 1000);

            // generate an RC2 key
            byte[] key = pwdGen.GetBytes(32);

            Console.WriteLine(System.Convert.ToBase64String(key));
            return System.Convert.ToBase64String(key) == hashValue;
        }
    }
Run Code Online (Sandbox Code Playgroud)

在我的测试课中,我有这个功能

    [Test]
    public void shouldGenerateConsistentHash()
    {
        PBKDF2Implementation cPbkdf2Implementation = new PBKDF2Implementation();
        string salt;
        string hashValue = cPbkdf2Implementation.CreateHash("password", out salt);

        bool result = cPbkdf2Implementation.CompareHash("password", salt, hashValue);
        Assert.IsTrue(result) ;
    }
Run Code Online (Sandbox Code Playgroud)

测试失败.
但是如果在上面的类PBKDF2Implementation中,如果我用System.Text.Encoding.Unicode.GetString和System.Text.Encoding.ASCII.GetBytes用System.Text.Encoding.Unicode替换System.Text.Encoding.ASCII.GetString行. GetBytes会

测试通过.知道为什么会这样吗?我想让它与ASCII编码一起工作的原因是因为存储这个哈希值的同一个DB也将被PHP应用程序使用,并且由PBKDF2实现的PHP生成的哈希值只有在盐编码为的时才匹配Rfc2898DeriveBytes的哈希值. ASCII.

这是相同的PHP实现 http://www.php.net/manual/en/function.hash-hmac.php#101540

pou*_*pou 6

  1. 避免使用加密字符串.使用字节数组,即byte[]
  2. 如果必须使用字符串采取非常谨慎编码.他们会在10次中咬你9次;

例如

byte [] data = new byte [] { 65, 0, 65 };
var s = System.Text.Encoding.ASCII.GetString (data);
Run Code Online (Sandbox Code Playgroud)

什么是s价值?

答案:"A"

如果您要求使用byte[]相同的字符串,那么byte [1] { 65 }它与原始字符串不同,并且不适用于大多数加密用法.

Base64更安全,因为它将保持每个字节完整.