Skip to content

Commit 4607edf

Browse files
committed
Reworked GetDigestInCryptFormat and all other methods relevant for that one to work on Unicode string (Delphi's UTF16 based Unicode string type). We still have some memory leaks though.
1 parent b6de97b commit 4607edf

File tree

3 files changed

+177
-93
lines changed

3 files changed

+177
-93
lines changed

Source/DECHash.pas

Lines changed: 23 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1060,7 +1060,6 @@ THash_BCrypt = class(TDECPasswordHash)
10601060
TBFBlock = packed array[0..7] of UInt8;
10611061
PBFBlock = ^TBFBlock;
10621062

1063-
TBCSalt = packed array[0..15] of byte;
10641063
TBCDigest = packed array[0..23] of byte;
10651064

10661065
TBF2Long = packed record
@@ -1121,7 +1120,7 @@ THash_BCrypt = class(TDECPasswordHash)
11211120
/// Cost factor which might be used to adapt the algorithm to increased
11221121
/// processing power.
11231122
/// </summary>
1124-
FCost : UInt32;
1123+
FCost : UInt8;
11251124
/// <summary>
11261125
/// Sets the cost factor. Throws an EDECHashException when a value of 0
11271126
/// is to be set.
@@ -1130,7 +1129,7 @@ THash_BCrypt = class(TDECPasswordHash)
11301129
/// Exception raised if <c>Value</c> is lower than <c>MinCost</c> or
11311130
/// higher than <c>MaxCost</c>.
11321131
/// </exception>
1133-
procedure SetCost(const Value: UInt32);
1132+
procedure SetCost(const Value: UInt8);
11341133
/// <summary>
11351134
/// Special setup for the bcrypt variant of the blowfish implementation.
11361135
/// Designed to be unavoidably slow.
@@ -1188,7 +1187,7 @@ THash_BCrypt = class(TDECPasswordHash)
11881187
/// <returns>
11891188
/// A Crypt/BSD ID
11901189
/// </returns>
1191-
class function GetCryptID:RawByteString; override;
1190+
class function GetCryptID:string; override;
11921191

11931192
/// <summary>
11941193
/// Returns the parameters required for the crypt-like password storing
@@ -1202,8 +1201,8 @@ THash_BCrypt = class(TDECPasswordHash)
12021201
/// Format class for formatting the output
12031202
/// </param>
12041203
class function GetCryptParams(
1205-
const Params : RawByteString;
1206-
Format : TDECFormatClass):RawByteString; override;
1204+
const Params : string;
1205+
Format : TDECFormatClass):string; override;
12071206
/// <summary>
12081207
/// Returns the hash required for the crypt-like password storing
12091208
/// in that format. If a salt etc. is needed that needs to be specified
@@ -1216,13 +1215,8 @@ THash_BCrypt = class(TDECPasswordHash)
12161215
/// In case of BCrypt this has to be the numeric integer value of "Cost"
12171216
/// </param>
12181217
/// <param name="Salt">
1219-
/// Salt value used by the password hash calculation. Depending on the
1220-
/// value of SaltIsRaw, the salt needs to specified in raw encoding or
1221-
/// in the encoding used in the Crypt/BSD password storage string.
1222-
/// </param>
1223-
/// <param name="SaltIsRaw">
1224-
/// If true the passed salt value is a raw value. If false it is encoded
1225-
/// like in the Crypt/BSD password storage string.
1218+
/// Salt value used by the password hash calculation in binary raw format,
1219+
/// means not Radix64 encoded or so.
12261220
/// </param>
12271221
/// <param name="Format">
12281222
/// Format class for formatting the output
@@ -1231,11 +1225,10 @@ THash_BCrypt = class(TDECPasswordHash)
12311225
/// Calculated hash value
12321226
/// </returns>
12331227
class function GetCryptHash(
1234-
const Password : RawByteString;
1235-
const Params : RawByteString;
1236-
const Salt : RawByteString;
1237-
SaltIsRaw : Boolean;
1238-
Format : TDECFormatClass):RawByteString; override;
1228+
const Password : string;
1229+
const Params : string;
1230+
const Salt : TBytes;
1231+
Format : TDECFormatClass):string; override;
12391232
{$EndRegion}
12401233
public
12411234
/// <summary>
@@ -1298,7 +1291,7 @@ THash_BCrypt = class(TDECPasswordHash)
12981291
/// <exception cref="EDECHashException">
12991292
/// Exception raised if a value outside of the range 4..31 is given.
13001293
/// </exception>
1301-
property Cost: UInt32
1294+
property Cost: UInt8
13021295
read FCost
13031296
write SetCost;
13041297
end;
@@ -5198,37 +5191,34 @@ procedure THash_BCrypt.Expandkey(Salt : TBytes;
51985191
end;
51995192

52005193
class function THash_BCrypt.GetCryptHash(
5201-
const Password : RawByteString;
5202-
const Params : RawByteString;
5203-
const Salt : RawByteString;
5204-
SaltIsRaw : Boolean;
5205-
Format : TDECFormatClass): RawByteString;
5194+
const Password : string;
5195+
const Params : string;
5196+
const Salt : TBytes;
5197+
Format : TDECFormatClass): string;
52065198
var
52075199
Hash : THash_BCrypt;
52085200
begin
52095201
Hash := THash_BCrypt.Create;
52105202
try
52115203
Hash.Cost := StrToInt(string(Params));
5212-
if SaltIsRaw then
5213-
Hash.Salt := BytesOf(Salt)
5214-
else
5215-
Hash.Salt := Format.Decode(BytesOf(Salt));
5204+
Hash.Salt := Salt;
52165205

52175206
// BCrypt leaves off the $ in front of the actual password hash value
5218-
Result := Hash.CalcString(Password, Format);
5207+
Result := TEncoding.ASCII.GetString(
5208+
Format.Encode(Hash.CalcBytes(TEncoding.UTF8.GetBytes(Password))));
52195209
finally
52205210
Hash.Free;
52215211
end;
52225212
end;
52235213

5224-
class function THash_BCrypt.GetCryptID: RawByteString;
5214+
class function THash_BCrypt.GetCryptID: string;
52255215
begin
52265216
Result := '$2a';
52275217
end;
52285218

52295219
class function THash_BCrypt.GetCryptParams(
5230-
const Params : RawByteString;
5231-
Format : TDECFormatClass): RawByteString;
5220+
const Params : string;
5221+
Format : TDECFormatClass): string;
52325222
begin
52335223
Result := Params;
52345224
if (Length(Result) < 2) then
@@ -5347,7 +5337,7 @@ class function THash_BCrypt.MinSaltLength: UInt8;
53475337
Result := 16;
53485338
end;
53495339

5350-
procedure THash_BCrypt.SetCost(const Value: UInt32);
5340+
procedure THash_BCrypt.SetCost(const Value: UInt8);
53515341
begin
53525342
if (Value in [MinCost..MaxCost]) then
53535343
FCost := Value

Source/DECHashAuthentication.pas

Lines changed: 51 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -640,6 +640,11 @@ TDECPasswordHash = class(TDECHashAuthentication)
640640
/// </summary>
641641
FSalt : TBytes;
642642

643+
/// <summary>
644+
/// Overwrite the salt value
645+
/// </summary>
646+
procedure DoDone; override;
647+
643648
{$Region CryptFormatHandling}
644649
/// <summary>
645650
/// Returns the ID code for Crypt/BSD like storing of passwords. The ID
@@ -650,7 +655,7 @@ TDECPasswordHash = class(TDECHashAuthentication)
650655
/// If the algorithm on which this is being used is a Crypt/BSD compatible
651656
/// password hash algorithm the ID is returned otherwise an empty string.
652657
/// </returns>
653-
class function GetCryptID:RawByteString; virtual;
658+
class function GetCryptID:string; virtual;
654659

655660
/// <summary>
656661
/// Returns the parameters required for the crypt-like password storing
@@ -667,8 +672,8 @@ TDECPasswordHash = class(TDECHashAuthentication)
667672
/// Returns an empty string if the the algorithm on which this is being
668673
/// used is not a Crypt/BSD compatible password hash algorithm
669674
/// </returns>
670-
class function GetCryptParams(const Params : RawByteString;
671-
Format : TDECFormatClass):RawByteString; virtual;
675+
class function GetCryptParams(const Params : string;
676+
Format : TDECFormatClass):string; virtual;
672677
/// <summary>
673678
/// Returns the salt required for the crypt-like password storing
674679
/// in that format.
@@ -679,8 +684,8 @@ TDECPasswordHash = class(TDECHashAuthentication)
679684
/// <param name="Format">
680685
/// Format class for formatting the output
681686
/// </param>
682-
class function GetCryptSalt(const Salt : RawByteString;
683-
Format : TDECFormatClass):RawByteString; virtual;
687+
class function GetCryptSalt(const Salt : TBytes;
688+
Format : TDECFormatClass):string; virtual;
684689
/// <summary>
685690
/// Returns the hash required for the crypt-like password storing
686691
/// in that format. If a salt etc. is needed that needs to be scepcified
@@ -698,9 +703,9 @@ TDECPasswordHash = class(TDECHashAuthentication)
698703
/// value of SaltIsRaw, the salt needs to specified in raw encoding or
699704
/// in the encoding used in the Crypt/BSD password storage string.
700705
/// </param>
701-
/// <param name="SaltIsRaw">
702-
/// If true the passed salt value is a raw value. If false it is encoded
703-
/// like in the Crypt/BSD password storage string.
706+
/// <param name="Salt">
707+
/// Salt value used by the password hash calculation in binary raw format,
708+
/// means not Radix64 encoded or so.
704709
/// </param>
705710
/// <param name="Format">
706711
/// Format class for formatting the output
@@ -709,11 +714,10 @@ TDECPasswordHash = class(TDECHashAuthentication)
709714
/// Returns an empty string if the the algorithm on which this is being
710715
/// used is not a Crypt/BSD compatible password hash algorithm.
711716
/// </returns>
712-
class function GetCryptHash(const Password : RawByteString;
713-
const Params : RawByteString;
714-
const Salt : RawByteString;
715-
SaltIsRaw : Boolean;
716-
Format : TDECFormatClass):RawByteString; virtual;
717+
class function GetCryptHash(const Password : string;
718+
const Params : string;
719+
const Salt : TBytes;
720+
Format : TDECFormatClass):string; virtual;
717721
{$EndRegion}
718722
public
719723
/// <summary>
@@ -789,10 +793,10 @@ TDECPasswordHash = class(TDECHashAuthentication)
789793
/// </exception>
790794
class function GetDigestInCryptFormat(
791795
const Password : RawByteString;
792-
const Params : RawByteString;
793-
const Salt : RawByteString;
796+
const Params : string;
797+
const Salt : string;
794798
SaltIsRaw : Boolean;
795-
Format : TDECFormatClass):RawByteString; virtual;
799+
Format : TDECFormatClass):string; virtual;
796800

797801
// /// <summary>
798802
// /// Calculates a passwort hash for the given password and returns it in
@@ -1479,27 +1483,29 @@ procedure TDECPasswordHash.SetSalt(const Value: TBytes);
14791483
FSalt := Value;
14801484
end;
14811485

1482-
class function TDECPasswordHash.GetCryptID: RawByteString;
1486+
class function TDECPasswordHash.GetCryptID: string;
14831487
begin
14841488
Result := '';
14851489
end;
14861490

14871491
class function TDECPasswordHash.GetCryptParams(
1488-
const Params : RawByteString;
1489-
Format : TDECFormatClass): RawByteString;
1492+
const Params : string;
1493+
Format : TDECFormatClass): string;
14901494
begin
14911495
Result := '';
14921496
end;
14931497

1494-
class function TDECPasswordHash.GetCryptSalt(const Salt : RawByteString;
1495-
Format : TDECFormatCLass): RawByteString;
1498+
class function TDECPasswordHash.GetCryptSalt(const Salt : TBytes;
1499+
Format : TDECFormatCLass): string;
14961500
var
14971501
FormattedSalt : TBytes;
14981502
begin
1499-
FormattedSalt := Format.Encode(BytesOf(Salt));
1500-
SetLength(Result, Length(FormattedSalt) + 1);
1501-
Move(FormattedSalt[0], Result[Low(Result) + 1], Length(FormattedSalt));
1502-
Result[Low(Result)] := '$';
1503+
FormattedSalt := Format.Encode(Salt);
1504+
// SetLength(Result, Length(FormattedSalt) + 1);
1505+
// Move(FormattedSalt[0], Result[Low(Result) + 1], Length(FormattedSalt));
1506+
// Result[Low(Result)] := '$';
1507+
1508+
Result := '$' + TEncoding.ASCII.GetString(FormattedSalt);
15031509
end;
15041510

15051511
class function TDECPasswordHash.ClassByCryptIdentity(
@@ -1527,24 +1533,31 @@ class function TDECPasswordHash.ClassByCryptIdentity(
15271533
[Identity]);
15281534
end;
15291535

1536+
procedure TDECPasswordHash.DoDone;
1537+
begin
1538+
inherited;
1539+
1540+
ProtectBuffer(FSalt, SizeOf(FSalt));
1541+
SetLength(FSalt, 0);
1542+
end;
1543+
15301544
class function TDECPasswordHash.GetCryptHash(
1531-
const Password : RawByteString;
1532-
const Params : RawByteString;
1533-
const Salt : RawByteString;
1534-
SaltIsRaw : Boolean;
1535-
Format : TDECFormatClass): RawByteString;
1545+
const Password : string;
1546+
const Params : string;
1547+
const Salt : TBytes;
1548+
Format : TDECFormatClass): string;
15361549
begin
15371550
Result := '';
15381551
end;
15391552

15401553
class function TDECPasswordHash.GetDigestInCryptFormat(
15411554
const Password : RawByteString;
1542-
const Params : RawByteString;
1543-
const Salt : RawByteString;
1555+
const Params : string;
1556+
const Salt : string;
15441557
SaltIsRaw : Boolean;
1545-
Format : TDECFormatClass): RawByteString;
1558+
Format : TDECFormatClass): string;
15461559
var
1547-
SaltStr : RawByteString;
1560+
SaltBytes : TBytes;
15481561
begin
15491562
// generic format used by Crypt, but not every algorithm sticks 100% to it
15501563
// $<id>[$<param>=<value>(,<param>=<value>)*][$<salt>[$<hash>]]
@@ -1554,13 +1567,13 @@ class function TDECPasswordHash.GetDigestInCryptFormat(
15541567
if (Result <> '') then
15551568
begin
15561569
if SaltIsRaw then
1557-
SaltStr := Salt
1570+
SaltBytes := TEncoding.UTF8.GetBytes(Salt)
15581571
else
1559-
SaltStr := Format.Decode(salt);
1572+
SaltBytes := Format.Decode(TEncoding.UTF8.GetBytes(Salt));
15601573

15611574
Result := Result + GetCryptParams(Params, Format) +
1562-
GetCryptSalt(SaltStr, Format) +
1563-
GetCryptHash(Password, Params, Salt, SaltIsRaw, Format);
1575+
GetCryptSalt(SaltBytes, Format) +
1576+
GetCryptHash(Password, Params, SaltBytes, Format);
15641577
end;
15651578
end;
15661579

0 commit comments

Comments
 (0)