C# 有人能解释一下BCrypt是如何验证散列的吗?

C# 有人能解释一下BCrypt是如何验证散列的吗?,c#,bcrypt,bcrypt.net,C#,Bcrypt,Bcrypt.net,我正在使用C#和BCrypt.Net散列我的密码 例如: string salt = BCrypt.Net.BCrypt.GenerateSalt(6); var hashedPassword = BCrypt.Net.BCrypt.HashPassword("password", salt); //This evaluates to True. How? I'm not telling it the salt anywhere, nor //is it a member of a BCryp

我正在使用C#和BCrypt.Net散列我的密码

例如:

string salt = BCrypt.Net.BCrypt.GenerateSalt(6);
var hashedPassword = BCrypt.Net.BCrypt.HashPassword("password", salt);

//This evaluates to True. How? I'm not telling it the salt anywhere, nor
//is it a member of a BCrypt instance because there IS NO BCRYPT INSTANCE.
Console.WriteLine(BCrypt.Net.BCrypt.Verify("password", hashedPassword));
Console.WriteLine(hashedPassword);
如果BCrypt没有在任何地方保存salt,那么它如何使用哈希验证密码。我唯一的想法是,它不知怎么地在散列的末尾加了盐

这是正确的假设吗

如果BCrypt没有在任何地方保存salt,它如何使用哈希验证密码

显然,它没有做任何这样的事情。盐必须保存在某个地方

让我们在维基百科上查找密码加密方案。发件人:

函数的输出不仅仅是散列:它是一个文本字符串,它还对salt进行编码并标识所使用的散列算法

或者,在回答您关于这个主题的问题时,会包含一个链接到。源代码的相关部分是:

    StringBuilder rs = new StringBuilder();
    rs.Append("$2");
    if (minor >= 'a') {
        rs.Append(minor);
    }
    rs.Append('$');
    if (rounds < 10) {
        rs.Append('0');
    }
    rs.Append(rounds);
    rs.Append('$');
    rs.Append(EncodeBase64(saltBytes, saltBytes.Length));
    rs.Append(EncodeBase64(hashed,(bf_crypt_ciphertext.Length * 4) - 1));
    return rs.ToString();
StringBuilder rs=new StringBuilder();
卢比(“$2”);
如果(次要>='a'){
卢比(小调);
}
rs.Append(“$”);
如果(轮数<10){
rs.Append('0');
}
卢比(轮);
rs.Append(“$”);
rs.Append(EncodeBase64(saltBytes,saltBytes.Length));
rs.Append(EncodeBase64(散列,(bf_crypt_ciphertext.Length*4)-1);
返回rs.ToString();
显然,返回的字符串是版本信息,后面是使用的轮数,后面是编码为base64的salt,后面是编码为base64的哈希。

BCrypt hash字符串类似于:

$2a$10$Ro0CUfOqk6cXEKf3dyaM7OhSCvnwM9s4wIX9JeLapehKK5YdLxKcm
\__/\/ \____________________/\_____________________________/
 |   |        Salt                     Hash
 |  Cost
Version
在哪里

  • 2a
    :算法标识符(BCrypt,UTF8编码密码,以null结尾)
  • 10
    :成本系数(2
    10
    =1024轮)
  • Ro0CUfOqk6cXEKf3dyaM7O
    :OpenBSD-Base64编码的salt(22个字符,16个字节)
  • hSCvnwM9s4wIX9JeLapehKK5YdLxKcm
    :OpenBSD-Base64编码哈希(31个字符,24个字节)
编辑:我刚刚注意到这些词正好合适。我必须分享:

$2a$10$TwentytwocharactersaltThirtyonecharacterspasswordhash
$==$==$======================-------------------------------

BCrypt使用16字节的salt创建24字节的二进制哈希。你可以随意存储二进制散列和盐;没有人说你必须用base-64编码成一个字符串

但是BCrypt是由从事OpenBSD工作的人创建的OpenBSD已经为其密码文件定义了一种格式:

$
[HashAlgorithmIdentifier]
$
[AlgorithmSpecificData]

这意味着“bcrypt规范”与OpenBSD密码文件格式有着不可分割的联系。每当有人创建“bcrypt哈希”时,他们总是将其转换为ISO-8859-1格式的字符串:

$
2a
<成本]$
[Base64Salt][Base64Hash]

有几点很重要:

  • 2a
    是算法标识符

    • 1:MD5
    • 2:早期的bcrypt,对哪些编码密码存在混淆(过时)
    • 2a:当前bcrypt,它将密码指定为UTF-8编码
  • 成本是计算哈希时使用的成本因子。“当前”值为10,这意味着内部按键设置要经过1024轮

    • 10:210=1024次迭代
    • 11:211=2048次迭代
    • 12:212=4096次迭代
  • OpenBSD密码文件使用的base64算法与其他人使用的base64编码不同;他们有自己的:

      Regular Base64 Alphabet: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/
          BSD Base64 Alphabet: ./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
    
    因此,bcrypt的任何实现都不能使用任何内置的或标准的base64库


有了这些知识,您现在可以根据保存的哈希验证密码
correctbatteryhorsestapler

$2a$12$mACnM5lzNigHMaf7O1py1O3vlf6.BA8k8x3IoJ.Tq3IB/2e7g61Km
BCrypt变异体 关于bcrypt版本有很多混淆

$2$

BCrypt是由OpenBSD人员设计的。它被设计成散列密码以存储在OpenBSD密码文件中。哈希密码以前缀存储,以识别所使用的算法。BCrypt获得前缀
$2$

这与其他算法前缀不同:

  • $1$
    :MD5
  • $5$
    :SHA-256
  • $6$
    :SHA-512
$2a$

最初的BCrypt规范没有定义如何处理非ASCII字符,或者如何处理空终止符。对规范进行了修订,以规定在散列字符串时:

  • 字符串必须是UTF-8编码的
  • 必须包括空终止符
$2x$,$2y$(2011年6月)


在骗子中发现了一个错误:22个字符对31个字符(复数)。幸运的是,Salt以s开头,所以你可以说它在两个词之间是共享的。尽管如此,它仍然很棒…很好的回答@Ian Boyd,一个问题,成本意味着你想要迭代生成随机值的次数?我的意思是,如果成本是10,它将进行1024次迭代,直到生成hast为止?@Skizo ozᴉʞS从技术上讲,它花费2^n次迭代来生成加密“密钥”。然后使用该密钥对文本“OrpheanBeholderCryQuestion”进行64次加密。但是是的,您可以想象它在生成哈希之前必须运行多少次迭代。