【问题标题】:Need help creating IsValidPassword for PBKDF2 in C#需要帮助在 C# 中为 PBKDF2 创建 IsValidPassword
【发布时间】:2020-05-16 16:35:42
【问题描述】:

尝试创建 PBKDF2 有效密码检查器最困难。 PBKDF2 代码来自一个 SharpHash 项目; https://github.com/ron4fun/SharpHash。类是:SharpHash/SharpHash.Tests/KDF/PBKDF2_HMACTests.cs

该示例显示了如何实现它,但没有任何关于如何验证哈希的示例。我设法尝试了几种不同的“IsValidPassword”是其中一种方法,但它们似乎都不起作用。无论我向 PBKDF2 或 IsValidPassword 方法添加什么值,它们中的每一个结果都是错误的。我还尝试更改为十六进制和 base64,但得到了相同的结果;失败了。

我什至替换了 Rfc2898DeriveBytes。

有没有人有过 PBKDF2 密码验证的经验。这将基于应用程序,而不是基于网站。 IDE 环境 Visual Studios 2019 - C#。

谢谢。

    public void TestOne()
    {
        IPBKDF2_HMAC PBKDF2 = HashFactory.KDF.PBKDF2_HMAC.CreatePBKDF2_HMAC(hash, Password, Salt, 100000);
        byte[] Key = PBKDF2.GetBytes(64);
        PBKDF2.Clear();

        string ActualString = Converters.ConvertBytesToHexString(Key, false);

        Assert.AreEqual(ExpectedString, ActualString);
    }



public bool IsValidPassword(string password, string hashPass)
    {
        bool result = false;

        // Extract the bytes
        byte[] hashBytes = Encoding.ASCII.GetBytes(hashPass);
        // Get the salt
        byte[] salt = new byte[20]; // Doesn't matter what values and here; same issue… False
        Array.Copy(hashBytes, 0, salt, 0, 20);// Doesn't matter what values and here; same issue… False
        // Compute the hash on the password the user entered
        var pbkdf2 = new Rfc2898DeriveBytes(password, salt, 100000);
        byte[] hash = pbkdf2.GetBytes(64);
        // compare the results
        for (int i = 0; i < 20; i++) // If I go to 64 I get an error
        {
            if (hashBytes[i + 20] != hash[i])
            {
                return false;
            }
        }

        return true;
    }


// Replaced Rfc2898DeriveBytes
        public bool IsValidPassword(string password, string hashPass)
    {
        bool result = false;
        IHash hash1 = HashFactory.Crypto.CreateSHA1();
        // Extract the bytes
        byte[] hashBytes = Encoding.ASCII.GetBytes(hashPass);
        byte[] Password = Encoding.ASCII.GetBytes(password);
        // Get the salt
        byte[] salt = new byte[20]; // Doesn't matter what values and here; same issue… False
        Array.Copy(hashBytes, 0, salt, 0, 20); // Doesn't matter what values and here; same issue… False
        // Compute the hash on the password the user entered
        var pbkdf2 = HashFactory.KDF.PBKDF2_HMAC.CreatePBKDF2_HMAC(hash1, Password, salt, 100000); // Replaced Rfc2898DeriveBytes
        byte[] Key = pbkdf2.GetBytes(64);
        pbkdf2.Clear();
        string test = Converters.ConvertBytesToHexString(Key, false); // Taking a peek
        string test2 = Encoding.ASCII.GetString(hashBytes); // Taking a peek
        // compare the results
        for (int i = 0; i < 20; i++)
        {
            if (hashBytes[i + 20] != Key[i])
            {
                return false;
            }
        }

        return true;
    }

【问题讨论】:

    标签: c# pbkdf2


    【解决方案1】:

    快速浏览一下,您遇到的问题只是对所涉及的数据内容的误传。 password 是基于 base256 的数据,而 hashPass 是基于 base16 的数据。 在将hashPass 转换为byte[] 时,您必须使用适当的转换例程。 为此,只需使用 Converters 类中的this 方法即可。

    byte[] hashBytes = Converters.ConvertHexStringToBytes(hashPass);
    

    请注意,我假设您的密码在 base256 中(因为您没有在问题中指定此密码),因此您可以保持原样。 你需要做的唯一改变就是我上面描述的那个。

    【讨论】:

      【解决方案2】:

      好吧,我想这将帮助其他人。我不得不做一些认真的搜索并将我的头撞到墙上,因为这是我在 PBKDF2 上第一次尝试提出 SharpHash 项目中不包含的功能验证方法。只是为了让任何阅读本文的人都能理解我的问题是什么。该代码生成的密码没有任何问题。但是,代码项目中并没有真正使用盐验证密码、生成密码和迭代的函数。

      提供的代码是简单版本,因为我还为不需要发布的方法添加了重载。此方法具有默认设置,而其中一个重载允许完全自定义散列算法、盐和迭代。我已经测试了其中的每一个,它们都按预期工作。

      希望这对某人有所帮助。 :-)

      private static Int32 Salt256bit { get; } = 256 / 8; // 256 bits = 32 Bytes
              public static string GetHashPBKDF2Password(string password)
          {
              // Notes:
              // Create a 32-byte secure salt and the same size of the key. This 32-byte produces 256 bits key output.
              // Add the same 32-byte size to the pbkdf2.GetBytes.
              // KDF.PBKDF2_HMAC.CreatePBKDF2_HMAC hashes these values using the crypto SHA presented.
              // Double the hashBytes bytes then add the salt and pbkdf2.GetBytes value.
              // Copy each of the 32-bytes to the hashBytes bytes from the hashed salt and hashed value.
              //
              byte[] Password = Encoding.Unicode.GetBytes(password);
              string hashPass = string.Empty;
      
              // Create the salt value with a cryptographic PRNG
              byte[] salt;
              new RNGCryptoServiceProvider().GetBytes(salt = new byte[ByteSize]); // 32 Bytes = 256 bits.
      
              // Create the KDF.PBKDF2_HMAC.CreatePBKDF2_HMAC and get the hash value using the SHA presented.
              // I know SHA1 is not that secured at all anymore. Just using it to test with. :-)
              IHash sha = HashFactory.Crypto.CreateSHA1();
              IPBKDF2_HMAC pbkdf2 = HashFactory.KDF.PBKDF2_HMAC.CreatePBKDF2_HMAC(sha, Password, salt, Pbkdf2Iterations);
              byte[] hash = pbkdf2.GetBytes(ByteSize); // 32 Bytes = 256 bits.
      
              // Double the size of the byte array to include the "pbkdf2.GetBytes" and salt.
              Int32 g = hash.Length + salt.Length;
              byte[] hashBytes = new byte[g];
      
              // Combine the salt and password bytes.
              Array.Copy(salt, 0, hashBytes, 0, ByteSize);
              Array.Copy(hash, 0, hashBytes, ByteSize, ByteSize);
      
              // Turn the combined salt+hash into a string for storage
              hashPass = Convert.ToBase64String(hashBytes);
      
              return hashPass;
          }
      
          public static bool ValidatePBKDF2Password(string password, string hashPass)
          {
              try
              {
                  byte[] Password = Encoding.Unicode.GetBytes(password);
                  bool result = true;
      
                  // Extract the bytes
                  byte[] hashBytes = Convert.FromBase64String(hashPass);
                  // Get the salt
                  byte[] salt = new byte[32];
                  Array.Copy(hashBytes, 0, salt, 0, 32);
                  // Compute the hash on the password that user entered.
                  // I know SHA1 is not that secured at all anymore. Just using it to test with. :-)
                  IHash hash1 = HashFactory.Crypto.CreateSHA1();
                  IPBKDF2_HMAC pbkdf2 = HashFactory.KDF.PBKDF2_HMAC.CreatePBKDF2_HMAC(hash1, Password, salt, Pbkdf2Iterations);
                  byte[] hash = pbkdf2.GetBytes(32);
                  // compare the results
                  for (int i = 0; i < 32; i++)
                  {
                      if (hashBytes[i + 32] != hash[i])
                      {
                          result = false;
                      }
                  }
                  return result;
              }
              catch (Exception)
              {
                  return false;
              }
          }
      
      
          How to use:     string GeneratedHash = PBKDF2Helper.GetHashPBKDF2Password("password");
          Results: hv6t8N4rrVSKYFm80cCoVUEiUk2o11xLBc6lJb5kBXKTcwcKwl9dZwSdce01X0bi8BBhJY/QGGnNVAcR7ZhSvQ==
      
          Verify Paword:  Boolean tester = PBKDF2Helper.ValidatePBKDF2Password("password", GeneratedHash);
                          txtVerificationResults.Text = tester.ToString();
      

      【讨论】:

        猜你喜欢
        • 2013-05-19
        • 1970-01-01
        • 2020-03-06
        • 1970-01-01
        • 1970-01-01
        • 2014-02-22
        • 2011-08-02
        • 2013-12-08
        • 1970-01-01
        相关资源
        最近更新 更多