【问题标题】:Hashing and GetString/GetBytes issue散列和 GetString/GetBytes 问题
【发布时间】:2013-04-26 21:07:24
【问题描述】:

我有以下代码来散列/存储/检索密码数据,但我的第一个单元测试失败了。

我相信它是导致问题的编码,因为当调用 GetBytes 时,它返回 byte[38]byte[36] 我认为应该是 20。

当我将它存储在数据库中时,我必须将其转换为字符串。

有什么想法吗?谢谢

[Fact]
public void EncryptDecryptPasswordShouldMatch()
{
    string password = "password";
    string passwordKey = string.Empty;
    string passwordSalt = string.Empty;

    Helpers.CreatePasswordHash(password, out passwordSalt, out passwordKey);

    Assert.True(Helpers.PasswordsMatch(passwordSalt, passwordKey, password));

}


public static bool PasswordsMatch(string passwordSalt, string passwordKey, string password)
{
    byte[] salt = Encoding.UTF8.GetBytes(passwordSalt);
    byte[] key = Encoding.UTF8.GetBytes(passwordKey);

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

        if (!newKey.SequenceEqual(key))
            return false;
    }

    return true;
}

public static void CreatePasswordHash(string password, out string passwordSalt, out string passwordKey)
{
    // 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

        passwordSalt = Encoding.UTF8.GetString(salt);
        passwordKey = Encoding.UTF8.GetString(key);
    }
}

【问题讨论】:

  • 使用Base64将二进制值编码为字符串,可以处理任意字节序列。 UTF-8 用于在 unicode 文本和字节之间进行转换,并不是每个有效的字节序列都对 UTF-8 有效。

标签: c# .net encryption hash salt


【解决方案1】:

使用Base64将二进制值编码为字符串,可以处理任意字节序列。 UTF-8 用于在 unicode 文本和字节之间进行转换,并不是每个有效的字节序列都对 UTF-8 有效。使用 Utf-8 将密码(文本)转换为字节,但使用 Base64 作为盐和哈希。

Convert.ToBase64StringConvert.FromBase64String 应该可以解决问题。


一些补充说明:

  • 你的术语真的很奇怪,不要叫哈希key,叫它hash
  • 我会在您的 CreatePasswordHash 函数中连接哈希和盐,因此调用者不必为拥有两个单独的值而烦恼。

    return Base64Encode(salt)+"$"+Base64Encode(hash) 之类的,然后在验证函数中使用string.Split

  • 建议使用恒定时间比较来验证,但您的时序边信道似乎不太可能被实际利用。

  • 您的迭代次数非常少。我建议将其增加到 10000。

【讨论】:

  • 你能可靠地分割 $ - 如果那个字符在那里怎么办
  • @Jon hash 和 salt 都是 Base64 编码器的输出。 Base64 永远不会产生$,所以只会有一个$ 作为分隔符。
  • @Jon:然后聘请加密专家。弄错这些东西并构建一个不安全的系统是很容易。我对密码系统足够了解,知道自己没有能力做好工作,所以我不尝试。
  • @EricLippert 由于密码散列是一个非常常见的问题,如果 Microsoft 聘请密码学家为 BCL 添加易于使用且安全的类,那就太好了。甚至 php 都做对了。
【解决方案2】:

修改您的代码以使用Convert.FromBase64String 方法:

byte[] salt = Convert.FromBase64String(passwordSalt);
byte[] key = Convert.FromBase64String(passwordKey);

修改您的代码以使用Convert.ToBase64String 方法:

passwordSalt = Convert.ToBase64String(salt);
passwordKey = Convert.ToBase64String(key);

【讨论】:

    【解决方案3】:

    UTF8 不是将任何随机字节转换为字符串的方法。它用于编码文本;不仅仅是任何字节都是有效的 UTF8 编码值。您可以使用 Base64 tofrom 转换。请注意,base64 编码的字符串将占用原始字节字符的约 4/3 倍。这是一个例子:

    byte[] salt = deriveBytes.Salt;
    byte[] key = deriveBytes.GetBytes(20);  // derive a 20-byte key
    
    passwordSalt = Convert.ToBase64String(salt);
    passwordKey = Convert.ToBase64String(key);
    

    后来:

    byte[] salt = Convert.FromBase64String(passwordSalt);
    byte[] key = Convert.FromBase64String(passwordKey);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-04-02
      • 2018-01-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多