Skip to content

Commit 81095fb

Browse files
committed
Removed FastMM4 from uses, fixed IsValid password and implemented tests for it, also declared that TDECPasswordHash uses the IDECHashPassword interface and added the GetDigestInCryptFormat and IsValidPassword methods to it.
1 parent 54ca5ff commit 81095fb

File tree

4 files changed

+110
-16
lines changed

4 files changed

+110
-16
lines changed

Source/DECHash.pas

Lines changed: 40 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1197,7 +1197,18 @@ TBCryptBSDData = record
11971197
/// <summary>
11981198
/// Splits a given Crypt/BSD style password record into its parts
11991199
/// </summary>
1200-
class function SplitTestVector(const Vector: string):TBCryptBSDData;
1200+
/// <param name="Vector">
1201+
/// Data to split
1202+
/// </param>
1203+
/// <param name="SplittedData">
1204+
/// Data splitted in ID, Cost and Salt
1205+
/// </param>
1206+
/// <returns>
1207+
/// true if splitting resulted in the right number of parts,
1208+
/// otherwise false
1209+
/// </returns>
1210+
function SplitTestVector(const Vector : string;
1211+
var SplittedData : TBCryptBSDData):Boolean;
12011212
strict protected
12021213
procedure DoInit; override;
12031214
procedure DoTransform(Buffer: PUInt32Array); override;
@@ -5281,17 +5292,23 @@ function THash_BCrypt.IsValidPassword(const Password : string;
52815292
begin
52825293
Result := false;
52835294

5284-
SplittedCryptData := SplitTestVector(CryptData);
5285-
// Is the CryptData for this algorithm?
5286-
if SplittedCryptData.ID <> GetCryptID then
5287-
exit;
5295+
if (Length(CryptData) = 60) then
5296+
begin
5297+
if SplitTestVector(CryptData, SplittedCryptData) then
5298+
begin
5299+
// Is the CryptData for this algorithm?
5300+
if '$' + SplittedCryptData.ID <> GetCryptID then
5301+
exit;
52885302

5289-
GetCryptHash(Password,
5290-
SplittedCryptData.Cost,
5291-
Format.Decode(TEncoding.UTF8.GetBytes(SplittedCryptData.Salt)),
5292-
Format);
5303+
Hash := GetDigestInCryptFormat(Password,
5304+
SplittedCryptData.Cost,
5305+
SplittedCryptData.Salt,
5306+
False,
5307+
Format);
52935308

5294-
Result := hash = CryptData;
5309+
Result := Hash = CryptData;
5310+
end;
5311+
end;
52955312
end;
52965313

52975314
procedure THash_BCrypt.BF_Encrypt(const BI: TBFBlock; var BO: TBFBlock);
@@ -5412,14 +5429,22 @@ procedure THash_BCrypt.SetCost(const Value: UInt8);
54125429
raise EDECHashException.CreateFmt(sCostFactorInvalid, [MinCost, MaxCost]);
54135430
end;
54145431

5415-
class function THash_BCrypt.SplitTestVector(const Vector: string): TBCryptBSDData;
5432+
function THash_BCrypt.SplitTestVector(const Vector : string;
5433+
var SplittedData : TBCryptBSDData): Boolean;
54165434
var
54175435
Parts : TArray<string>;
54185436
begin
5419-
Parts := Vector.Split(['$'], TStringSplitOptions.ExcludeEmpty);
5420-
Result.ID := Parts[0];
5421-
Result.Cost := Copy(Parts[1], Low(Parts[1]), Length(Parts[1]));
5422-
Result.Salt := Copy(Parts[2], Low(Parts[2]), 22);
5437+
Result := false;
5438+
5439+
Parts := Vector.Split(['$'], TStringSplitOptions.ExcludeEmpty);
5440+
5441+
if (Length(Parts) = 3) then
5442+
begin
5443+
SplittedData.ID := Parts[0];
5444+
SplittedData.Cost := Copy(Parts[1], Low(Parts[1]), Length(Parts[1]));
5445+
SplittedData.Salt := Copy(Parts[2], Low(Parts[2]), 22);
5446+
Result := true;
5447+
end;
54235448
end;
54245449

54255450
{$IFDEF RESTORE_RANGECHECKS}{$R+}{$ENDIF}

Source/DECHashAuthentication.pas

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -618,7 +618,7 @@ TDECHashExtended = class(TDECHashAuthentication, IDECHashExtended)
618618
/// those from normal hash algorithms not really meant to be used for password
619619
/// hashing.
620620
/// </summary>
621-
TDECPasswordHash = class(TDECHashAuthentication)
621+
TDECPasswordHash = class(TDECHashAuthentication, IDECHashPassword)
622622
strict private
623623
/// <summary>
624624
/// Sets the salt value given. Throws an EDECHashException if a salt is
@@ -807,6 +807,7 @@ TDECPasswordHash = class(TDECHashAuthentication)
807807
/// <param name="CryptData">
808808
/// The data needed to "compare" the password against in Crypt/BSD like
809809
/// format: $<id>[$<param>=<value>(,<param>=<value>)*][$<salt>[$<hash>]]
810+
/// The exact format depends on the algorithm used.
810811
/// </param>
811812
/// <param name="Format">
812813
/// Must be the right type for the Crypt/BSD encoding used by the

Source/DECHashInterface.pas

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,73 @@ interface
387387

388388
IDECHashPassword = Interface(IDECHash)
389389
['{B4D8A80C-1F42-46F8-9288-D71ECCFE6F02}']
390+
/// <summary>
391+
/// Calculates a passwort hash for the given password and returns it in
392+
/// a BSDCrypt compatible format. This method only works for those hash
393+
/// algorithms implementing the necessary GetBSDCryptID method.
394+
/// </summary>
395+
/// <param name="Password">
396+
/// Entered password for which to calculate the hash. The caller is
397+
/// responsible to ensure the maximum password length is adhered to.
398+
/// Any exceptions raised due to too long passwords are not caught here!
399+
/// </param>
400+
/// <param name="Params">
401+
/// Algorithm specific parameters used for initialization. For details see
402+
/// documentation of the concrete implementation in the algorithm.
403+
/// </param>
404+
/// <param name="Salt">
405+
/// Salt value used by the password hash calculation. Depending on the
406+
/// value of SaltIsRaw, the salt needs to specified in raw encoding or
407+
/// in the encoding used in the Crypt/BSD password storage string.
408+
/// </param>
409+
/// <param name="SaltIsRaw">
410+
/// If true the passed salt value is a raw value. If false it is encoded
411+
/// like in the Crypt/BSD password storage string.
412+
/// </param>
413+
/// <param name="Format">
414+
/// Formatting class used to format the calculated password. Different
415+
/// algorithms in BSDCrypt use different algorithms so one needs to know
416+
/// which one to pass. See description of the hash class used.
417+
/// </param>
418+
/// <returns>
419+
/// Calculated hash value in BSD crypt style format. Returns an empty
420+
/// string if the algorithm is not a Crypt/BSD style password hash algorithm.
421+
/// </returns>
422+
/// <exception cref="EDECHashException">
423+
/// Exception raised if length of <c>Password</c> is higher than
424+
/// <c>MaxPasswordLength</c> or if a salt with a different length than
425+
/// 128 bit has been specified.
426+
/// </exception>
427+
function GetDigestInCryptFormat(const Password : string;
428+
const Params : string;
429+
const Salt : string;
430+
SaltIsRaw : Boolean;
431+
Format : TDECFormatClass):string;
432+
433+
/// <summary>
434+
/// Checks whether a given password is the correct one for a password
435+
/// storage "record"/entry in Crypt/BSD format.
436+
/// </summary>
437+
/// <param name="Password">
438+
/// Password to check for validity
439+
/// </param>
440+
/// <param name="CryptData">
441+
/// The data needed to "compare" the password against in Crypt/BSD like
442+
/// format: $<id>[$<param>=<value>(,<param>=<value>)*][$<salt>[$<hash>]].
443+
/// The exact format depends on the algorithm used.
444+
/// </param>
445+
/// <param name="Format">
446+
/// Must be the right type for the Crypt/BSD encoding used by the
447+
/// algorithm used. This was implemented this way to avoid making the
448+
/// DECHashAuthentication unit dependant on the DECFormat unit not needed
449+
/// otherwise.
450+
/// </param>
451+
/// <returns>
452+
/// True if the password given is correct.
453+
/// </returns>
454+
function IsValidPassword(const Password : string;
455+
const CryptData : string;
456+
Format : TDECFormatClass): Boolean;
390457
/// <summary>
391458
/// Sets the salt value given. Throws an EDECHashException if a salt is
392459
/// passed which is longer than MaxSaltLength.

Unit Tests/DECDUnitTestSuite.dpr

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ program DECDUnitTestSuite;
1616
{$ENDIF}
1717

1818
uses
19+
// FastMM4,
1920
Vcl.Forms,
2021
{$IFDEF TESTINSIGHT}
2122
TestInsight.Client,

0 commit comments

Comments
 (0)