Skip to content

Commit 54ca5ff

Browse files
committed
Changed GetDigestInCryptFormat to a normal method instead of a class method, which required changing a few others to normal methods as well. Changed the unit test accordingly and added a yet untested IsValidPassword method.
1 parent 27204c8 commit 54ca5ff

File tree

4 files changed

+80
-95
lines changed

4 files changed

+80
-95
lines changed

Source/DECFormat.pas

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1984,8 +1984,8 @@ class procedure TFormat_BCryptBSD.DoDecode(const Source;
19841984
end;
19851985

19861986
procedure SetNextByte(b: Integer);
1987-
{-Put next byte into pdest if LA<ldest, inc LA and pdest}
19881987
begin
1988+
// Put next byte into pdest if LA<ldest, inc LA and pdest
19891989
Dest := Dest + [byte(b and $ff)];
19901990
end;
19911991

@@ -2016,8 +2016,6 @@ class procedure TFormat_BCryptBSD.DoDecode(const Source;
20162016
class procedure TFormat_BCryptBSD.DoEncode(const Source;
20172017
var Dest: TBytes;
20182018
Size: Integer);
2019-
//const
2020-
// CT64: array[0..63] of AnsiChar = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
20212019
var
20222020
CT64 : TBytes;
20232021
c1,c2 : UInt16;

Source/DECHash.pas

Lines changed: 35 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1117,7 +1117,7 @@ TBCryptBSDData = record
11171117
/// <summary>
11181118
/// Cost factor
11191119
/// </summary>
1120-
Cost : UInt8;
1120+
Cost : string;
11211121
end;
11221122

11231123
var
@@ -1197,7 +1197,7 @@ TBCryptBSDData = record
11971197
/// <summary>
11981198
/// Splits a given Crypt/BSD style password record into its parts
11991199
/// </summary>
1200-
function SplitTestVector(const Vector: string):TBCryptBSDData;
1200+
class function SplitTestVector(const Vector: string):TBCryptBSDData;
12011201
strict protected
12021202
procedure DoInit; override;
12031203
procedure DoTransform(Buffer: PUInt32Array); override;
@@ -1223,9 +1223,8 @@ TBCryptBSDData = record
12231223
/// <param name="Format">
12241224
/// Format class for formatting the output
12251225
/// </param>
1226-
class function GetCryptParams(
1227-
const Params : string;
1228-
Format : TDECFormatClass):string; override;
1226+
function GetCryptParams(const Params : string;
1227+
Format : TDECFormatClass):string; override;
12291228
/// <summary>
12301229
/// Returns the hash required for the crypt-like password storing
12311230
/// in that format. If a salt etc. is needed that needs to be specified
@@ -1295,11 +1294,18 @@ TBCryptBSDData = record
12951294
/// The data needed to "compare" the password against in Crypt/BSD like
12961295
/// format: $<id>[$<param>=<value>(,<param>=<value>)*][$<salt>[$<hash>]]
12971296
/// </param>
1297+
/// <param name="Format">
1298+
/// Must be the right type for the Crypt/BSD encoding used by the
1299+
/// algorithm used. This was implemented this way to avoid making the
1300+
/// DECHashAuthentication unit dependant on the DECFormat unit not needed
1301+
/// otherwise.
1302+
/// </param>
12981303
/// <returns>
12991304
/// True if the password given is correct.
13001305
/// </returns>
1301-
class function IsValidPassword(const Password : string;
1302-
const CryptData : string): Boolean; override;
1306+
function IsValidPassword(const Password : string;
1307+
const CryptData : string;
1308+
Format : TDECFormatClass): Boolean; override;
13031309

13041310
/// <summary>
13051311
/// Processes one chunk of data to be hashed.
@@ -5256,9 +5262,8 @@ class function THash_BCrypt.GetCryptID: string;
52565262
Result := '$2a';
52575263
end;
52585264

5259-
class function THash_BCrypt.GetCryptParams(
5260-
const Params : string;
5261-
Format : TDECFormatClass): string;
5265+
function THash_BCrypt.GetCryptParams(const Params : string;
5266+
Format : TDECFormatClass): string;
52625267
begin
52635268
Result := Params;
52645269
if (Length(Result) < 2) then
@@ -5267,11 +5272,26 @@ class function THash_BCrypt.GetCryptParams(
52675272
Result := '$' + Result;
52685273
end;
52695274

5270-
class function THash_BCrypt.IsValidPassword(const Password,
5271-
CryptData: string): Boolean;
5275+
function THash_BCrypt.IsValidPassword(const Password : string;
5276+
const CryptData : string;
5277+
Format : TDECFormatClass): Boolean;
5278+
var
5279+
SplittedCryptData : TBCryptBSDData;
5280+
Hash : string;
52725281
begin
5273-
{ TODO : To be implemented }
52745282
Result := false;
5283+
5284+
SplittedCryptData := SplitTestVector(CryptData);
5285+
// Is the CryptData for this algorithm?
5286+
if SplittedCryptData.ID <> GetCryptID then
5287+
exit;
5288+
5289+
GetCryptHash(Password,
5290+
SplittedCryptData.Cost,
5291+
Format.Decode(TEncoding.UTF8.GetBytes(SplittedCryptData.Salt)),
5292+
Format);
5293+
5294+
Result := hash = CryptData;
52755295
end;
52765296

52775297
procedure THash_BCrypt.BF_Encrypt(const BI: TBFBlock; var BO: TBFBlock);
@@ -5392,13 +5412,13 @@ procedure THash_BCrypt.SetCost(const Value: UInt8);
53925412
raise EDECHashException.CreateFmt(sCostFactorInvalid, [MinCost, MaxCost]);
53935413
end;
53945414

5395-
function THash_BCrypt.SplitTestVector(const Vector: string): TBCryptBSDData;
5415+
class function THash_BCrypt.SplitTestVector(const Vector: string): TBCryptBSDData;
53965416
var
53975417
Parts : TArray<string>;
53985418
begin
53995419
Parts := Vector.Split(['$'], TStringSplitOptions.ExcludeEmpty);
54005420
Result.ID := Parts[0];
5401-
Result.Cost := Copy(Parts[1], Low(Parts[1]), Length(Parts[1])).ToInteger;
5421+
Result.Cost := Copy(Parts[1], Low(Parts[1]), Length(Parts[1]));
54025422
Result.Salt := Copy(Parts[2], Low(Parts[2]), 22);
54035423
end;
54045424

Source/DECHashAuthentication.pas

Lines changed: 28 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -672,8 +672,8 @@ TDECPasswordHash = class(TDECHashAuthentication)
672672
/// Returns an empty string if the the algorithm on which this is being
673673
/// used is not a Crypt/BSD compatible password hash algorithm
674674
/// </returns>
675-
class function GetCryptParams(const Params : string;
676-
Format : TDECFormatClass):string; virtual;
675+
function GetCryptParams(const Params : string;
676+
Format : TDECFormatClass):string; virtual;
677677
/// <summary>
678678
/// Returns the salt required for the crypt-like password storing
679679
/// in that format.
@@ -736,7 +736,7 @@ TDECPasswordHash = class(TDECHashAuthentication)
736736
/// </summary>
737737
class function MaxPasswordLength:UInt8; virtual; abstract;
738738

739-
{$Region CryptFormatHandlingPublic}
739+
{$Region CryptBSDFormatHandlingPublic}
740740
/// <summary>
741741
/// Tries to find a class type by its Crypt identification
742742
/// (e.g. 2a is Bcrypt).
@@ -791,12 +791,11 @@ TDECPasswordHash = class(TDECHashAuthentication)
791791
/// <c>MaxPasswordLength</c> or if a salt with a different length than
792792
/// 128 bit has been specified.
793793
/// </exception>
794-
class function GetDigestInCryptFormat(
795-
const Password : string;
796-
const Params : string;
797-
const Salt : string;
798-
SaltIsRaw : Boolean;
799-
Format : TDECFormatClass):string; virtual;
794+
function GetDigestInCryptFormat(const Password : string;
795+
const Params : string;
796+
const Salt : string;
797+
SaltIsRaw : Boolean;
798+
Format : TDECFormatClass):string; virtual;
800799

801800
/// <summary>
802801
/// Checks whether a given password is the correct one for a password
@@ -809,55 +808,18 @@ TDECPasswordHash = class(TDECHashAuthentication)
809808
/// The data needed to "compare" the password against in Crypt/BSD like
810809
/// format: $<id>[$<param>=<value>(,<param>=<value>)*][$<salt>[$<hash>]]
811810
/// </param>
811+
/// <param name="Format">
812+
/// Must be the right type for the Crypt/BSD encoding used by the
813+
/// algorithm used. This was implemented this way to avoid making the
814+
/// DECHashAuthentication unit dependant on the DECFormat unit not needed
815+
/// otherwise.
816+
/// </param>
812817
/// <returns>
813818
/// True if the password given is correct.
814819
/// </returns>
815-
class function IsValidPassword(const Password : string;
816-
const CryptData : string): Boolean; virtual;
817-
818-
// /// <summary>
819-
// /// Calculates a passwort hash for the given password and returns it in
820-
// /// a BSDCrypt compatible format. This method only works for those hash
821-
// /// algorithms implementing the necessary GetBSDCryptID method.
822-
// /// </summary>
823-
// /// <param name="Password">
824-
// /// Entered password for which to calculate the hash. The caller is
825-
// /// responsible to ensure the maximum password length is adhered to.
826-
// /// Any exceptions raised due to too long passwords are not caught here!
827-
// /// </param>
828-
// /// <param name="Params">
829-
// /// Algorithm specific parameters used for initialization. For details see
830-
// /// documentation of the concrete implementation in the algorithm.
831-
// /// </param>
832-
// /// <param name="Salt">
833-
// /// Salt value used by the password hash calculation. Depending on the
834-
// /// value of SaltIsRaw, the salt needs to specified in raw encoding or
835-
// /// in the encoding used in the Crypt/BSD password storage string.
836-
// /// </param>
837-
// /// <param name="SaltIsRaw">
838-
// /// If true the passed salt value is a raw value. If false it is encoded
839-
// /// like in the Crypt/BSD password storage string.
840-
// /// </param>
841-
// /// <param name="Format">
842-
// /// Formatting class used to format the calculated password. Different
843-
// /// algorithms in BSDCrypt use different algorithms so one needs to know
844-
// /// which one to pass. See description of the hash class used.
845-
// /// </param>
846-
// /// <returns>
847-
// /// Calculated hash value in BSD crypt style format. Returns an empty
848-
// /// string if the algorithm is not a Crypt/BSD style password hash algorithm.
849-
// /// </returns>
850-
// /// <exception cref="EDECHashException">
851-
// /// Exception raised if length of <c>Password</c> is higher than
852-
// /// <c>MaxPasswordLength</c> or if a salt with a different length than
853-
// /// 128 bit has been specified.
854-
// /// </exception>
855-
// class function GetDigestInCryptFormat(
856-
// const Password : string;
857-
// const Params : RawByteString;
858-
// const Salt : RawByteString;
859-
// SaltIsRaw : Boolean;
860-
// Format : TDECFormatClass):RawByteString; virtual; overload;
820+
function IsValidPassword(const Password : string;
821+
const CryptData : string;
822+
Format : TDECFormatClass): Boolean; virtual;
861823
{$EndRegion}
862824

863825
/// <summary>
@@ -1509,9 +1471,8 @@ class function TDECPasswordHash.GetCryptID: string;
15091471
Result := '';
15101472
end;
15111473

1512-
class function TDECPasswordHash.GetCryptParams(
1513-
const Params : string;
1514-
Format : TDECFormatClass): string;
1474+
function TDECPasswordHash.GetCryptParams(const Params : string;
1475+
Format : TDECFormatClass): string;
15151476
begin
15161477
Result := '';
15171478
end;
@@ -1571,12 +1532,12 @@ class function TDECPasswordHash.GetCryptHash(
15711532
Result := '';
15721533
end;
15731534

1574-
class function TDECPasswordHash.GetDigestInCryptFormat(
1575-
const Password : string;
1576-
const Params : string;
1577-
const Salt : string;
1578-
SaltIsRaw : Boolean;
1579-
Format : TDECFormatClass): string;
1535+
function TDECPasswordHash.GetDigestInCryptFormat(
1536+
const Password : string;
1537+
const Params : string;
1538+
const Salt : string;
1539+
SaltIsRaw : Boolean;
1540+
Format : TDECFormatClass): string;
15801541
var
15811542
SaltBytes : TBytes;
15821543
begin
@@ -1598,8 +1559,9 @@ class function TDECPasswordHash.GetDigestInCryptFormat(
15981559
end;
15991560
end;
16001561

1601-
class function TDECPasswordHash.IsValidPassword(const Password : string;
1602-
const CryptData : string): Boolean;
1562+
function TDECPasswordHash.IsValidPassword(const Password : string;
1563+
const CryptData : string;
1564+
Format : TDECFormatClass): Boolean;
16031565
begin
16041566
Result := false;
16051567
end;

Unit Tests/Tests/TestDECHash.pas

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6364,18 +6364,23 @@ TPair = record
63646364
Result : string;
63656365
i : Integer;
63666366
SplitData : TBCryptBSDTestData;
6367+
HashInst : THash_BCrypt;
63676368
begin
6368-
for i := Low(TestData) to High(TestData) do
6369-
begin
6370-
SplitData := SplitTestVector(TestData[i].bs);
6371-
Result := string(THash_BCrypt.GetDigestInCryptFormat(
6372-
Passwords[TestData[i].pn],
6373-
SplitData.Cost.ToString,
6374-
SplitData.Salt,
6375-
False,
6376-
TFormat_BCryptBSD));
6377-
6378-
CheckEquals(TestData[i].bs, Result);
6369+
HashInst := THash_BCrypt.Create;
6370+
try
6371+
for i := Low(TestData) to High(TestData) do
6372+
begin
6373+
SplitData := SplitTestVector(TestData[i].bs);
6374+
Result := string(HashInst.GetDigestInCryptFormat(Passwords[TestData[i].pn],
6375+
SplitData.Cost.ToString,
6376+
SplitData.Salt,
6377+
False,
6378+
TFormat_BCryptBSD));
6379+
6380+
CheckEquals(TestData[i].bs, Result);
6381+
end;
6382+
finally
6383+
HashInst.Free;
63796384
end;
63806385
end;
63816386

0 commit comments

Comments
 (0)