有人可以解释BCrypt如何validation散列?

我正在使用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没有在任何地方保存盐,那么如何用哈希validation密码。 我唯一的想法是它以某种方式在散列末尾添加salt。

这是一个正确的假设吗?

如果不在任何地方储存盐,BCrypt如何用哈希validation密码?

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

我们来看维基百科上的密码encryptionscheme。 来自http://en.wikipedia.org/wiki/Crypt_(Unix); :

函数的输出不仅仅是散列:它是一个文本string,它也编码盐并标识所使用的散列algorithm。

另外,对这个主题的上一个问题的答案包括一个链接到源代码 。 而不是要求互联网阅读你的源代码,你可以select自己阅读。 这可能会让你的答案更快。 源代码的相关部分是:

  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(); 

很显然,返回的string是版本信息,接着是使用的循环次数,接着是编码为base64的盐,接着是编码为base64的哈希。

BCrypt哈希string如下所示:

 $2a$10$Ro0CUfOqk6cXEKf3dyaM7OhSCvnwM9s4wIX9JeLapehKK5YdLxKcm $==$==$======================------------------------------- 

哪里

  • 2a :algorithm标识符(BCrypt,UTF8编码密码,空终止)
  • 10 :成本因素(2 10 = 1,024轮)
  • Ro0CUfOqk6cXEKf3dyaM7O :OpenBSD-Base64编码盐(22个字符,16字节)
  • hSCvnwM9s4wIX9JeLapehKK5YdLxKcm :OpenBSD-Base64编码散列(31个字符,24个字节)

编辑 :我只是注意到这些词完全适合。 我不得不分享:

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

BCrypt创build一个24字节的二进制散列,使用16字节的盐。 你可以自由地存储二进制散列和盐,不pipe你喜欢什么; 没有什么说你必须将base-64编码成一个string。

但是BCrypt是由在OpenBSD上工作的人创build的。 OpenBSD已经为其密码文件定义了一个格式:

$ [HashAlgorithmIdentifier] $ [AlgorithmSpecificData]

这意味着“bcrypt规范”与OpenBSD的密码文件格式是不可分割的。 每当有人创build一个“bcrypt hash”,他们总是把它转换成ISO-8859-1格式的string:

$ 2a $ [Cost] $ [Base64Salt][Base64Hash]

几点重要的一点:

  • 2a是对数标识符
    • 1:MD5
    • 2:早期的bcrypt,对哪些编码密码在(过时)
    • 2a:当前的bcrypt,它将密码指定为UTF-8编码
  • 成本是计算散列时使用的成本因素。 “当前”值是10,这意味着内部密钥设置要经过1,024个回合
    • 10:2 10 = 1024次迭代
    • 11:2 11 = 2048次迭代
    • 12:2 12 = 4,096次迭代
  • OpenBSD密码文件使用的base64algorithm与其他人使用的Base64编码不同; 他们有自己的:

     Regular Base64 Alphabet: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/ BSD Base64 Alphabet: ./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 

    所以任何bcrypt的实现都不能使用任何内build或标准的base64库


有了这些知识,你现在可以validation密码correctbatteryhorsestapler对保存的散列:

 $2a$12$mACnM5lzNigHMaf7O1py1O3vlf6.BA8k8x3IoJ.Tq3IB/2e7g61Km