Okay, so i wrote it.
Usage:
hash: string;
hash := TBCrypt.HashPassword('mypassword01');
returns something like:
$2a$10$Ro0CUfOqk6cXEKf3dyaM7OhSCvnwM9s4wIX9JeLapehKK5YdLxKcm
The useful thing about this (OpenBSD) style password hash is:
- that it identifies the algorithm (
2a
= bcrypt)
- the salt is automatically created for you, and shipped with the hash (
Ro0CUfOqk6cXEKf3dyaM7O
)
- the cost factor parameter is also carried with the hash (
10
).
To check a password is correct:
isValidPassword: Boolean;
isValidPassword := TBCrypt.CheckPassword('mypassword1', hash);
BCrypt uses a cost factor, which determines how many iterations the key setup will go though. The higher the cost, the more expensive it is to compute the hash. The constant BCRYPT_COST
contains the default cost:
const
BCRYPT_COST = 10; //cost determintes the number of rounds. 10 = 2^10 rounds (1024)
In this case a cost of 10
means the key will be expanded and salted 210
=1,024 rounds. This is the commonly used cost factor at this point in time (early 21st century).
It is also interesting to note that, for no known reason, OpenBSD hashed passwords are converted to a Base-64 variant that is different from the Base64 used by everyone else on the planet. So TBCrypt
contains a custom base-64 encoder and decoder.
It's also useful to note that the hash algorithm version 2a
is used to mean:
- bcrypt
- include the password's null terminator in the hashed data
- unicode strings are UTF-8 encoded
So that is why the HashPassword
and CheckPassword
functions take a WideString
(aka UnicodeString
), and internally convert them to UTF-8. If you're running this on a version of Delphi where UnicodeString
is a reserved word, then simply define out:
type
UnicodeString = WideString;
i, as David Heffernan knows, don't own Delphi XE 2. i added the UnicodeString
alias, but didn't include compilers.inc
and define away UnicodeString
(since i don't know the define name, nor could i test it). What do you want from free code?
The code comprises of two units:
- Bcrypt.pas (which i wrote, with embedded DUnit tests)
- Blowfish.pas (which Dave Barton wrote, which i adapted, extended, fixed some bugs and added DUnit tests to).
Where on the intertubes can i put some code where it can live in perpetuity?
Update 1/1/2015: It was placed onto GitHub some time ago: BCrypt for Delphi.
Bonus 4/16/2015: There is now Scrypt for Delphi