mirror of
https://github.com/rg3/libbcrypt.git
synced 2026-10-25 00:19:18 +03:00
238 lines
7.9 KiB
Plaintext
238 lines
7.9 KiB
Plaintext
BCRYPT(3)
|
|
=========
|
|
|
|
NAME
|
|
----
|
|
bcrypt - Password hashing library
|
|
|
|
SYNOPSIS
|
|
--------
|
|
|
|
Header and prototypes
|
|
~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
---------------------------------------
|
|
#include <bcrypt.h>
|
|
|
|
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 <r@rg3.name> 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/
|