Compare commits

..

No commits in common. "master" and "v0.1.0" have entirely different histories.

3 changed files with 172 additions and 220 deletions

View File

@ -11,16 +11,13 @@
*}
unit BCrypt;
{$mode objfpc}{$H+}
{$CODEPAGE UTF-8}
{$codepage utf8}
interface
uses
sysutils,
classes
;
SysUtils,
Classes;
const
// bcrypt uses 128-bit (16-byte) salt
@ -222,7 +219,6 @@ type
BCryptSalt,
BCryptHash : AnsiString;
end;
UTF8String = type AnsiString(CP_UTF8);
EHash = class(EArgumentException);
@ -232,7 +228,7 @@ private
FPBox: array[0..17] of DWord;
function BsdBase64Encode(const RawByteData: TBytes; CharacterLength: Sizeint): AnsiString;
function BsdBase64Decode(const EncodedString : AnsiString): TBytes;
function Crypt(const Password : UTF8String; const Salt : AnsiString; Cost : Byte; HashType : THashTypes) : AnsiString;
function Crypt(const Password, Salt : AnsiString; Cost : Byte; HashType : THashTypes) : AnsiString;
function CryptRaw(const HashKey, Salt: TBytes; Cost : Byte): TBytes;
procedure EKSKey(const Salt, HashKey: TBytes);
procedure Encipher(var lr: array of DWord; const offset: SizeInt);
@ -251,10 +247,10 @@ private
public
constructor Create; overload;
destructor Destroy; override;
function CreateHash(const Password : UTF8String) : AnsiString; overload;
function CreateHash(const Password : UTF8String; HashType : THashTypes) : AnsiString; overload;
function CreateHash(const Password : UTF8String; HashType : THashTypes; Cost : Byte) : AnsiString; overload;
function VerifyHash(const Password : UTF8STring; const Hash : AnsiString) : Boolean;
function CreateHash(const Password : AnsiString) : AnsiString; overload;
function CreateHash(const Password : AnsiString; HashType : THashTypes) : AnsiString; overload;
function CreateHash(const Password : AnsiString; HashType : THashTypes; Cost : Byte) : AnsiString; overload;
function VerifyHash(const Password, Hash : AnsiString) : Boolean;
function NeedsRehash(const BCryptHash : AnsiString) : Boolean; overload;
function NeedsRehash(const BCryptHash : AnsiString; Cost : Byte) : Boolean; overload;
function HashGetInfo(const Hash : AnsiString) : RTPasswordInformation;
@ -267,7 +263,6 @@ Uses
constructor TBCryptHash.Create;
begin
inherited Create;
end;
@ -486,6 +481,7 @@ begin
end;
end; { TBCryptHash.EKSKey }
{$OVERFLOWCHECKS OFF}
procedure TBCryptHash.Encipher(var lr: array of DWord; const offset: SizeInt);
var
i, n, block, r: DWord;
@ -497,22 +493,23 @@ begin
while i <= BLOWFISH_NUM_ROUNDS - 1 do
begin
n := FSBox[(block shr 24) and $FF];
n := DWord(n + FSBox[$100 or ((block shr 16) and $FF)]);
n := n + FSBox[$100 or ((block shr 16) and $FF)];
n := n xor FSBox[$200 or ((block shr 8) and $FF)];
n := DWord(n + FSBox[$300 or (block and $FF)]);
n := n + FSBox[$300 or (block and $FF)];
r := r xor (n xor FPBox[i]);
Inc(i);
n := FSBox[(r shr 24) and $FF];
n := DWord(n + FSBox[$100 or ((r shr 16) and $FF)]);
n := n + FSBox[$100 or ((r shr 16) and $FF)];
n := n xor FSBox[$200 or ((r shr 8) and $FF)];
n := DWord(n + FSBox[$300 or (r and $FF)]);
n := n + FSBox[$300 or (r and $FF)];
block := block xor (n xor FPBox[i]);
Inc(i);
end;
lr[offset] := r xor FPBox[BLOWFISH_NUM_ROUNDS + 1];
lr[offset + 1] := block;
end;
{$OVERFLOWCHECKS ON}
function TBCryptHash.FormatPasswordHash(const Salt, Hash: TBytes; Cost : Byte; HashType : THashTypes): AnsiString;
var
@ -690,16 +687,16 @@ begin
Result := RandomFileBuffer;
end; { TBCryptHash.unixRandomBytes }
function TBCryptHash.CreateHash(const Password : UTF8String) : AnsiString; overload;
function TBCryptHash.CreateHash(const Password : AnsiString) : AnsiString; overload;
begin
Result := CreateHash(Password, bcPHP, BCRYPT_DEFAULT_COST);
end;
function TBCryptHash.CreateHash(const Password : UTF8String; HashType : THashTypes) : AnsiString; overload;
function TBCryptHash.CreateHash(const Password : AnsiString; HashType : THashTypes) : AnsiString; overload;
begin
Result := CreateHash(Password, HashType, BCRYPT_DEFAULT_COST);
end; { TBCryptHash.CreateHash }
function TBCryptHash.CreateHash(const Password : UTF8String; HashType : THashTypes; Cost : Byte) : AnsiString; overload;
function TBCryptHash.CreateHash(const Password : AnsiString; HashType : THashTypes; Cost : Byte) : AnsiString; overload;
var
PasswordKey,
SaltBytes,
@ -717,7 +714,7 @@ begin
Result := FormatPasswordHash(SaltBytes, Hash, Cost, HashType);
end; { TBCryptHash.CreateHash }
function TBCryptHash.Crypt(const Password : UTF8String; const Salt : AnsiString; Cost : Byte; HashType : THashTypes) : AnsiString;
function TBCryptHash.Crypt(const Password, Salt : AnsiString; Cost : Byte; HashType : THashTypes) : AnsiString;
var
PasswordKey,
SaltBytes,
@ -743,12 +740,12 @@ begin
end;
else
begin
Result := (bcUnknown);
Result := (bcPHP);
end;
end;
end;
function TBCryptHash.VerifyHash(const Password : UTF8String; const Hash : AnsiString) : Boolean;
function TBCryptHash.VerifyHash(const Password, Hash : AnsiString) : Boolean;
var
WorkingBcryptHash, Salt : AnsiString;
HashCounter, ResultStatus, BCryptCost : Byte;

View File

@ -2,7 +2,6 @@ Program BCryptHashTest;
{$mode objfpc}{$H+}
{$ASSERTIONS ON}
{$UNITPATH ../}
{$CODEPAGE UTF-8}
uses BCrypt, Classes, SysUtils, Crt;
const
@ -22,10 +21,6 @@ var
PassedAssertions : Word;
Passed : Boolean;
UTF8TestString : UTF8String = 'Τη γλώσσα μου έδωσαν ελληνική';
UTF8TestHash : AnsiString = '$2y$12$RSxqgCt5T4qPXLM3AzKMCueMBZo6cc9o/bN4wqcX6KA6lZnOkqzTG';
UTF8PHPHash : AnsiString = '$2y$12$KrBUSn54WO5C/aw2H3imKurgsnrGq7PsrIZYXusaTNIO.27IGsmkG';
PasswordHashes : array [1..14] of AnsiString = (
'$2y$10$LCb3aOt8lAXSzNrEpQKDQO1zc2wCCQltrDwSEbb9JaUo4OKbphC3i',
'$2y$11$H7TRTJZqQTzN5RCiwMOne.yjVxyKCd4GyLrBQzV91gK0T4XQeKTNa',
@ -109,40 +104,8 @@ for i := 1 to 7 do
WriteLn(' - Pass');
Inc(PassedAssertions);
end;
WriteLn(#10#13'Testing UTF8 with ', UTF8TestString, ' ... '#10#13);
Write('Testing : ', UTF8TestHash);
try
Assert(TBCrypt.VerifyHash(UTF8TestString, UTF8TestHash) = True, 'Should Be True');
Inc(Assertions);
Inc(PassedAssertions);
Writeln(' - Pass');
except
on e: EAssertionFailed do
begin
WriteLn(' - Fail');
Inc(FailedAssertions);
Dec(PassedAssertions);
end;
end;
WriteLn(#10#13'Testing UTF8 PHP Hash with ', UTF8TestString, ' ... '#10#13);
Write('Testing : ', UTF8PHPHash);
try
Assert(TBCrypt.VerifyHash(UTF8TestString, UTF8PHPHash) = True, 'Should Be True');
Inc(Assertions);
Inc(PassedAssertions);
Writeln(' - Pass');
except
on e: EAssertionFailed do
begin
WriteLn(' - Fail');
Inc(FailedAssertions);
Dec(PassedAssertions);
end;
end;
WriteLn(#10#13'Testing Failures ...'#10#13);
for i := 1 to 7 do
WriteLn(#10#13'Testing Failures ...'#10#13);
for i := 1 to 7 do
begin
Write('Testing : ', PasswordHashFailures[i]);
try
@ -161,8 +124,8 @@ WriteLn(#10#13'Testing UTF8 with ', UTF8TestString, ' ... '#10#13);
end;
WriteLn(#10#13'Testing Rehash True ...'#10#13);
for i := 1 to 7 do
WriteLn(#10#13'Testing Rehash True ...'#10#13);
for i := 1 to 7 do
begin
Write('Testing : ', PasswordHashes[i]);
try
@ -362,6 +325,7 @@ WriteLn(#10#13'Testing UTF8 with ', UTF8TestString, ' ... '#10#13);
Inc(FailedAssertions);
end;
Writeln(#10#13'Testing hashing ...'#10#13);
Writeln(TBCrypt.CreateHash(StaticPassword));
Writeln(TBCrypt.CreateHash(StaticPassword, bcBSD));
@ -372,9 +336,9 @@ WriteLn(#10#13'Testing UTF8 with ', UTF8TestString, ' ... '#10#13);
Writeln(TBCrypt.CreateHash(StaticPassword, bcPHP, 14));
Writeln(#10#13);
TBCrypt.Free;
TBCrypt.Free;
Writeln('Assertions : ', Assertions);
Writeln('Passed Assertions : ', PassedAssertions);
Writeln('Failed Assertions : ', FailedAssertions);
Writeln;
end.
end.

View File

@ -14,8 +14,6 @@ assert_options(ASSERT_CALLBACK, 'bcrypt_assert_handler');
$bsdPascalHash = '$2a$12$9NWTTEbRtjLNd4KdW.VtUekFA6pJ3DF23FqdvwwvMtoMD9zqdaZg2';
$bsdPascalHashFail = '$2a$12$9NWTTEbRtjLNd4KdW.VtUekFA6pJ3DF23FqdvwwvMtoMD9zqdaZg1';
$utf8String = 'Τη γλώσσα μου έδωσαν ελληνική';
$utf8PascalHash = '$2y$12$RSxqgCt5T4qPXLM3AzKMCueMBZo6cc9o/bN4wqcX6KA6lZnOkqzTG';
$pascalHashesMT = [
'$2y$10$kJgRFQ993paFLArmPE3gn.8yuUB/SRpaEw7lkJJ1oVqhWVIecI5nO',
@ -37,13 +35,6 @@ $pascalHashesURandom = [
'$2y$16$Y0QNc8vaJJY5mQO0IkN6oeAxEVjtnHYqk0WeWLPm7bRjxA7fWHRBG',
];
print PHP_EOL . 'Testing UTF8Hashe ... ' . str_repeat(PHP_EOL, 2);
print 'Testing : ' . $utf8PascalHash;
print PHP_EOL . ' with : ' . $utf8String;
if(true === assert(password_verify($utf8String, $utf8PascalHash), ' - Fail')) {
print ' - Pass' . PHP_EOL;
}
print PHP_EOL . 'Testing bsdPascalHash ... ' . str_repeat(PHP_EOL, 2);
print 'Testing : ' . $bsdPascalHash;
if (true === assert(password_verify('password', $bsdPascalHash), ' - Fail')) {