BCRYPT(3) ========= NAME ---- bcrypt - Password hashing library SYNOPSIS -------- Header and prototypes ~~~~~~~~~~~~~~~~~~~~~ --------------------------------------- #include int bcrypt_gensalt(int workfactor, char salt[BCRYPT_HASHSIZE]); int bcrypt_hashpw(const char *passwd, const char salt[BCRYPT_HASHSIZE], char hash[BCRYPT_HASHSIZE]); int bcrypt_checkpw(const char *passwd, const char hash[BCRYPT_HASHSIZE]); int bcrypt_sha512(const char *passwd, char digest[BCRYPT_512BITS_BASE64_SIZE]); int bcrypt_sha3_512(const char *passwd, char digest[BCRYPT_512BITS_BASE64_SIZE]); --------------------------------------- Compilation and linkage ~~~~~~~~~~~~~~~~~~~~~~~ In systems with *pkg-config* or an equivalent tool, compile with the flags indicated by *pkg-config --cflags libbcrypt* and link with the flags indicated by *pkg-config --libs libbcrypt*. Otherwise, check the installation path for *bcrypt.h* and link with *-lbcrypt* and an additional *-L* flag to indicate the library location. DESCRIPTION ----------- The function _bcrypt_gensalt_ can be used to generate a salt value for hashing a password with a following call to _bcrypt_hashpw_. Its _workfactor_ argument determines how many rounds will be used and the time it will take to hash or verify the hashed password. Allowed values range from 4 to 31. If the provided work factor is not in the previous range, it will default to BCRYPT_DEFAULT_WORK_FACTOR. The _salt_ argument is an output array of chars that will store the generated salt. It must have space for at least BCRYPT_HASHSIZE bytes. The function _bcrypt_hashpw_ expects a password to be hashed (_passwd_), a _salt_ to hash the password with, generated with _bcrypt_gensalt_ and a char array to leave the result (_hash_). Both the salt and the output hash arguments must point to buffers with, at least, BCRYPT_HASHSIZE bytes in capacity. It can also be used to verify passwords, but it is easier to use _bcrypt_checkpw_ for that specific purpose. The function _bcrypt_checkpw_ expects a password (_passwd_) and a _hash_ to verify the password against, allowing you to see if the password matches a stored hash. Do note the generated hashes are null-terminated strings that can be printed or stored and they include the salt information. There is no need to store the salt separately. Hence, verifying a password only needs the hash string. The function _bcrypt_sha512_ can be used to get the base64 representation of the SHA-512 digest of the password _passwd_. This digest can be used as a replacement for the password itself to overcome the character limit of the bcrypt implementation. Please see the *CAVEATS* and *EXAMPLES* sections for more details. The function _bcrypt_sha3_512_ is identical to the previous one but uses SHA3-512 instead of SHA-512. RETURN VALUE ------------ Both _bcrypt_gensalt_, _bcrypt_hashpw_, _bcrypt_sha512_ and _bcrypt_sha3_512_ return zero on success and nonzero on errors. _bcrypt_checkpw_ will return -1 on errors, zero if the provided password matches the given hash and a value greater than zero if the password and hashes do not match. CAVEATS ------- The included bcrypt implementation only uses the first 72 bytes of the password to generate the hash. That means two passwords with the same initial 72-byte prefix but a different suffix will give the same hash if using the same salt. They are, effectively, the same password. 72 bytes may be 72 characters or may be as low as 18 characters if the password is completely made of 4-byte UTF-8 sequences, for example. This can be a problem in many contexts. You may want users to be able to use passphrases for which the 72-bytes limit is simply too low. You probably want, if possible, to capture the entropy of the full passphrase to calculate the bcrypt hash instead of ignoring everyting after the 72nd byte. One solution to this problem is pre-hashing the password with a secure and fast cryptographic hash function, and use the resulting digest, or a textual representation of it, as the effective password. This scheme was in use in September 2016 by Dropbox and received positive criticism, gaining popularity and becoming a common approach if it was not before. Dropbox was hashing the passwords first with SHA-512. The resulting binary digest may contain null characters and cannot be used as a text string. As per their blog post (see *REFERENCES*), we can deduce they were converting the 64-bytes digest to 88 text bytes in base64 and feeding that to bcrypt. bcrypt would use the first 72 bytes of the base64 representation, for a total underlying entropy of 72*3/4 = 54 bytes or 432 bits, which should be extremely secure as a password. Using this scheme, you can allow users to type very long passwords or passphrases with varied entropy and compress that entropy very fast to something having at most 432 bits of entropy. This scheme lets different passwords, even with a common 72-byte prefix, be considered different. The _bcrypt_sha512_ and _bcrypt_sha3_512_ functions are provided with the goal of letting you replicate that scheme. The first one hashes the given password with SHA-512 and is the "conservative" choice. The second one uses the newer SHA3-512 algorithm and should also be fine. Both output the digest as a null-terminated base64 string that can be feeded directly to bcrypt. SHA-512, SHA3-512 and the base64 routine are implemented in software, with reasonable performance. SHA3-512 is much slower than SHA-512, but their run time is many orders of magnitudes smaller than running bcrypt itself to hash or verify the password. EXAMPLES -------- Hashing a password ~~~~~~~~~~~~~~~~~~ --------------------------------------- char salt[BCRYPT_HASHSIZE]; char hash[BCRYPT_HASHSIZE]; int ret; ret = bcrypt_gensalt(BCRYPT_DEFAULT_WORK_FACTOR, salt); if (ret != 0) // Handle the error here. ret = bcrypt_hashpw("thepassword", salt, hash); if (ret != 0) // Handle another error here. printf("Generated hash: %s\n", hash); --------------------------------------- Verifying a password ~~~~~~~~~~~~~~~~~~~~ --------------------------------------- char hash[BCRYPT_HASHSIZE]; int ret; // Read the hash somewhere here and store it in the `hash' buffer. ret = bcrypt_checkpw("thepassword", hash); if (ret == -1) // Handle the error here. if (ret == 0) printf("The password matches\n"); else printf("The password does NOT match\n"); --------------------------------------- Hashing a password using SHA-512 as a pre-hash ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --------------------------------------- char salt[BCRYPT_HASHSIZE]; char hash[BCRYPT_HASHSIZE]; char digest[BCRYPT_512BITS_BASE64_SIZE]; int ret; ret = bcrypt_sha512("thepassword", digest); if (ret != 0) // Handle the error here. ret = bcrypt_gensalt(BCRYPT_DEFAULT_WORK_FACTOR, salt); if (ret != 0) // Handle another error here. ret = bcrypt_hashpw(digest, salt, hash); if (ret != 0) // Handle another error here. printf("Generated hash: %s\n", hash); --------------------------------------- Verifying a password using SHA-512 as a pre-hash ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --------------------------------------- char hash[BCRYPT_HASHSIZE]; char digest[BCRYPT_512BITS_BASE64_SIZE]; int ret; // Read the hash somewhere here and store it in the `hash' buffer. ret = bcrypt_sha512("thepassword", digest); if (ret != 0) // Handle the error here. ret = bcrypt_checkpw(digest, hash); if (ret == -1) // Handle another error here. if (ret == 0) printf("The password matches\n"); else printf("The password does NOT match\n"); --------------------------------------- AUTHORS ------- Ricardo Garcia based on the work of: - Solar Designer. - The Keccak Team. - musl-libc. - Dropbox. REFERENCES ---------- . http://www.openwall.com/crypt/ . https://github.com/gvanas/KeccakCodePackage . https://git.musl-libc.org/cgit/musl . https://blogs.dropbox.com/tech/2016/09/how-dropbox-securely-stores-your-passwords/