Can someone explain how BCrypt verifies a hash?

后端 未结 2 717
萌比男神i
萌比男神i 2020-11-28 07:39

I\'m using C# and BCrypt.Net to hash my passwords.

For example:

string salt = BCrypt.Net.BCrypt.GenerateSalt(6);
var hashedPassword = BCrypt.Net.BCry         


        
2条回答
  •  被撕碎了的回忆
    2020-11-28 08:01

    A BCrypt hash string looks like:

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

    Where

    • 2a: Algorithm Identifier (BCrypt, UTF8 encoded password, null terminated)
    • 10: Cost Factor (210 = 1,024 rounds)
    • Ro0CUfOqk6cXEKf3dyaM7O: OpenBSD-Base64 encoded salt (22 characters, 16 bytes)
    • hSCvnwM9s4wIX9JeLapehKK5YdLxKcm: OpenBSD-Base64 encoded hash (31 characters, 24 bytes)

    Edit: i just noticed these words fit exactly. i had to share:

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

    BCrypt does create a 24-byte binary hash, using 16-byte salt. You're free to store the binary hash and the salt however you like; nothing says you have to base-64 encode it into a string.

    But BCrypt was created by guys who were working on OpenBSD. OpenBSD already defines a format for their password file:

    $[HashAlgorithmIdentifier]$[AlgorithmSpecificData]

    This means that the "bcrypt specification" is inexorably linked to the OpenBSD password file format. And whenever anyone creates a "bcrypt hash" they always convert it to an ISO-8859-1 string of the format:

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

    A few important points:

    • 2a is the algorithm identifier

      • 1: MD5
      • 2: early bcrypt, which had confusion over which encoding passwords are in (obsolete)
      • 2a: current bcrypt, which specifies passwords as UTF-8 encoded
    • Cost is a cost factor used when computing the hash. The "current" value is 10, meaning the internal key setup goes through 1,024 rounds

      • 10: 210 = 1,024 iterations
      • 11: 211 = 2,048 iterations
      • 12: 212 = 4,096 iterations
    • the base64 algorithm used by the OpenBSD password file is not the same Base64 encoding that everybody else uses; they have their own:

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

      So any implementations of bcrypt cannot use any built-in, or standard, base64 library


    Armed with this knowledge, you can now verify a password correctbatteryhorsestapler against the saved hash:

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

    BCrypt variants

    There is a lot of confusion around the bcrypt versions.

    $2$

    BCrypt was designed by the OpenBSD people. It was designed to hash passwords for storage in the OpenBSD password file. Hashed passwords are stored with a prefix to identify the algorithm used. BCrypt got the prefix $2$.

    This was in contrast to the other algorithm prefixes:

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

    $2a$

    The original BCrypt specification did not define how to handle non-ASCII characters, or how to handle a null terminator. The specification was revised to specify that when hashing strings:

    • the string must be UTF-8 encoded
    • the null terminator must be included

    $2x$, $2y$ (June 2011)

    A bug was discovered in crypt_blowfish

提交回复
热议问题