Free Pascal Implementation of BCrypt password hashing.
Go to file
Eric 469aae80dc
Merge pull request #8 from GabrielF7/master
Adding explicit typecast to DWord to avoid overflow assertion error
2019-03-01 09:34:03 -08:00
Renegade.Random@4e23838567 Update Renegade.Random 2016-05-07 10:04:45 -07:00
docs First commit 2016-04-26 10:29:24 -07:00
tests Implement UTF8 support 2017-02-22 17:20:45 -08:00
.gitignore See Changlog 2016-11-03 11:29:38 -07:00
.gitmodules Added Renegade.Random unit 2016-05-04 10:44:29 -07:00
BCrypt.pas Adding explicit typecast to DWord to avoid overflow assertion error (I was having problems with debugger) 2018-09-27 23:32:02 -03:00
CHANGELOG.md Rename changelog 2016-11-03 11:35:07 -07:00
LICENSE First commit 2016-04-26 10:29:24 -07:00
README.md Update README.md 2016-11-03 13:27:25 -07:00

README.md

Free Pascal BCrypt

Free Pascal BCrypt implementation.

This started because I wanted something that would be compatible with PHP's 2y BCrypt hashing. Ultimately there is no difference between the 2a algorithm and the 2y algorithm. Just the a, and y. But I didn't want to have a wrapper function that replaced the a with the y.

If you try to verify a 2a password with PHP it will verify, but if you run the needs rehash function it will always say it needs a rehash. So I moved this to Free Pascal compatible class format.

Tested with :

  • Free Pascal

    • 2.6.4
      • Linux
        • Gentoo, 2.2-Current-x64
        • Raspbian
    • 3.0.0
      • Linux
        • Gentoo, 2.2-Current-x64
      • FreeBSD
        • 12.0-CURRENT-x64
      • Windows
        • Windows 10-x64
    • 3.1.1
      • Linux
        • Gentoo, 2.2-Current-x64
  • PHP

    • 5.5.x
      • 5.5.38-pl0-gentoo
    • 5.6.x
      • 5.6.20-pl0-gentoo
      • 5.6.28-pl0-gentoo
    • 7.0.x
      • 7.0.6_rc1-pl0-gentoo
      • 7.0.13-pl0-gentoo
    • 7.x.x (dev)
      • 7.2.0-dev-x64 (ZTS) 10/31/2016, Gentoo 2.2 Current
      • 7.2.0-dev-x64 (ZTS) 11/02/2016, FreeBSD 12.0-CURRENT
  • HHVM

    • Soon

Usage

BCrypt.CreateHash(Password);
BCrypt.CreateHash(Password, HashType);
BCrypt.CreateHash(Password, HashType, Cost);

Where

  • Password is the password to be hashed
  • HashType is one of bcPHP, bcBSD, or bcDefault, bcPHP is the default 2y
  • and Cost is a number between 10 and 30, default is 12.
var
  BCrypt : TBCryptHash;
  Hash   : AnsiString;
begin
  BCrypt := TBCryptHash.Create;
  Hash := BCrypt.CreateHash('password'); // PHP $2y$ hash with a cost of 12
  // or
  Hash := BCrypt.CreateHash('password', bcBSD); // BSD $2a$ hash with a cost of 12
  // or
  Hash := BCrypt.CreateHash('password', bcPHP, 14); // PHP hash, with a cost of 14
  Writeln(Hash);
  BCrypt.Free;
end;

To verify

var
  BCrypt : TBCryptHash;
  Hash : AnsiString;
  Verify : Boolean;
begin
  Hash := '$2y$12$GuC.Gk2YDsp8Yvga.IuSNOWM0fxEIsAEaWC1hqEI14Wa.7Ps3iYFq';
  BCrypt := TBCryptHash.Create;
  Verify := BCrypt.VerifyHash('password', Hash);
  BCrypt.Free;
end;

HashGetInfo - raises EHash exception if the hash is bad, (too short, too long);

var
  BCrypt : TBCryptHash;
  Hash : AnsiString;
  PasswordInfo : RTPasswordInformation;
begin
  BCrypt := TBCryptHash.Create;
  Hash := '$2y$12$GuC.Gk2YDsp8Yvga.IuSNOWM0fxEIsAEaWC1hqEI14Wa.7Ps3iYFq';
  PasswordInfo := BCrypt.HashGetInfo(Hash);
  with PasswordInfo do
    begin
      WriteLn('Algo : ', Algo); // bcPHP  
      WriteLn('AlgoName : ', AlgoName); // bcrypt
      WriteLn('Cost : ', Cost); // 12
      WriteLn('Salt : ', BCryptSalt); // GuC.Gk2YDsp8Yvga.IuSNO
      WriteLn('Hash : ', BCryptHash); // WM0fxEIsAEaWC1hqEI14Wa.7Ps3iYFq
    end;

  Hash := '$2a$12$GuC.Gk2YDsp8Yvga.IuSNOWM0fxEIsAEaWC1hqEI14Wa.7Ps3iYFq';
  PasswordInfo := BCrypt.HashGetInfo(Hash);
  with PasswordInfo do
    begin
      WriteLn('Algo : ', Algo); // bcBSD  
      WriteLn('AlgoName : ', AlgoName); // bcrypt
      WriteLn('Cost : ', Cost); // 12
      WriteLn('Salt : ', BCryptSalt); // GuC.Gk2YDsp8Yvga.IuSNO
      WriteLn('Hash : ', BCryptHash); // WM0fxEIsAEaWC1hqEI14Wa.7Ps3iYFq
    end;
    BCrypt.Free;
end;  

NeedsRehash

var
  BCrypt : TBCryptHash;
  Hash : AnsiString;
  Rehash : Boolean;
begin
  BCrypt := TBCryptHash.Create;
  Hash := '$2a$12$GuC.Gk2YDsp8Yvga.IuSNOWM0fxEIsAEaWC1hqEI14Wa.7Ps3iYFq';
  Rehash := BCrypt.NeedsRehash(Hash); // false
  Rehash := BCrypt.NeedsRehash(Hash, 14); // true
  Hash := '$2y$14$GuC.Gk2YDsp8Yvga.IuSNOWM0fxEIsAEaWC1hqEI14Wa.7Ps3iYFq';
  Rehash := BCrypt.NeedsRehash(Hash); // true
  Rehash := BCrypt.NeedsRehash(Hash, 14); // false
  BCrypt.Free;
end;

Evolution

This has had quite the evolution.

FreeBSD crypt.c

BCrypt for Delphi

BCrypt for Delphi, Lazarus, FPC

PHP password.c For the verify logic.

To here.