Skip to content

Commit 9dde95e

Browse files
committed
Attempt to find the root cause of the BCrypt memory leak.
1 parent 4607edf commit 9dde95e

File tree

4 files changed

+49
-26
lines changed

4 files changed

+49
-26
lines changed

Source/DECFormat.pas

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1950,7 +1950,7 @@ class function TFormat_BCryptBSD.CharTableBinary: TBytes;
19501950
$30, $31, $32, $33, $34, $35, $36, $37, $38, $39];
19511951
end;
19521952

1953-
class procedure TFormat_BCryptBSD.DoDecode(const Source;
1953+
class procedure TFormat_BCryptBSD.DoDecode(const Source;
19541954
var Dest: TBytes;
19551955
Size: Integer);
19561956
const
@@ -1962,55 +1962,55 @@ class procedure TFormat_BCryptBSD.DoDecode(const Source;
19621962
-1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
19631963
17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, -1, -1, -1, -1, -1,
19641964
-1, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42,
1965-
43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, -1, -1, -1, -1, -1);
1965+
43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, -1, -1, -1, -1, -1);
19661966

19671967
var
1968-
Src : PByte;
1968+
Src : PByte;
19691969
c1, c2, c3, c4: Integer;
19701970

19711971
function GetNextByte: integer;
19721972
var
19731973
b: UInt8;
19741974
begin
19751975
Result := -1;
1976-
if (Size > 0) then
1976+
if (Size > 0) then
19771977
begin
19781978
b := Src^;
19791979
Inc(Src);
19801980
Dec(Size);
1981-
if (b < 128) then
1981+
if (b < 128) then
19821982
Result := BT[b];
19831983
end;
1984-
end;
1984+
end;
19851985

19861986
procedure SetNextByte(b: Integer);
19871987
{-Put next byte into pdest if LA<ldest, inc LA and pdest}
19881988
begin
1989-
Dest := Dest + [byte(b and $ff)]
1989+
Dest := Dest + [byte(b and $ff)];
19901990
end;
1991-
1991+
19921992
begin
19931993
Src := @Source;
19941994

1995-
if (Src = nil) or (Size < 1) then
1995+
if (Src = nil) or (Size < 1) then
19961996
exit;
1997-
1998-
while Size > 0 do
1997+
1998+
while Size > 0 do
19991999
begin
2000-
c1 := GetNextByte;
2000+
c1 := GetNextByte;
20012001
if (c1 < 0) then exit;
2002-
c2 := GetNextByte;
2002+
c2 := GetNextByte;
20032003
if (c2 < 0) then exit;
20042004
SetNextByte(((c1 and $3f) shl 2) or (c2 shr 4));
20052005

2006-
c3 := GetNextByte;
2006+
c3 := GetNextByte;
20072007
if (c3 < 0) then exit;
20082008
SetNextByte(((c2 and $0f) shl 4) or (c3 shr 2));
20092009

2010-
c4 := GetNextByte;
2010+
c4 := GetNextByte;
20112011
if (c4 < 0) then exit;
20122012
SetNextByte(((c3 and $03) shl 6) or c4);
2013-
end;
2013+
end;
20142014
end;
20152015

20162016
class procedure TFormat_BCryptBSD.DoEncode(const Source;

Source/DECHash.pas

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5197,15 +5197,26 @@ class function THash_BCrypt.GetCryptHash(
51975197
Format : TDECFormatClass): string;
51985198
var
51995199
Hash : THash_BCrypt;
5200+
B: TBytes;
52005201
begin
52015202
Hash := THash_BCrypt.Create;
52025203
try
52035204
Hash.Cost := StrToInt(string(Params));
52045205
Hash.Salt := Salt;
52055206

52065207
// BCrypt leaves off the $ in front of the actual password hash value
5207-
Result := TEncoding.ASCII.GetString(
5208-
Format.Encode(Hash.CalcBytes(TEncoding.UTF8.GetBytes(Password))));
5208+
// Result := TEncoding.ASCII.GetString(//Hash.CalcBytes(TEncoding.UTF8.GetBytes(Password)));
5209+
// Format.Encode(Hash.CalcBytes(TEncoding.UTF8.GetBytes(Password))));
5210+
5211+
// b:= TEncoding.UTF8.GetBytes(Password);
5212+
5213+
// b := Format.Encode([85, 126, 148, 243, 75, 242, 134, 232, 113, 154, 38, 190, 148, 172, 30, 22, 217, 94, 249, 248, 25, 222, 224]);
5214+
b := Hash.CalcBytes(b));
5215+
5216+
5217+
Result := TEncoding.ASCII.GetString(b);
5218+
// [85, 126, 148, 243, 75, 242, 134, 232, 113, 154, 38, 190, 148, 172, 30, 22, 217, 94, 249, 248, 25, 222, 224];
5219+
// //Hash.CalcBytes(TEncoding.UTF8.GetBytes(Password))));
52095220
finally
52105221
Hash.Free;
52115222
end;
@@ -5309,7 +5320,7 @@ procedure THash_BCrypt.DoInit;
53095320
procedure THash_BCrypt.DoTransform(Buffer: PUInt32Array);
53105321
begin
53115322
// Empty on purpose, as bcrypt needs to know the input length. Thus calculation
5312-
// is done directly in CalcBuffer.
5323+
// is done directly in method Calc.
53135324
end;
53145325

53155326
class function THash_BCrypt.MaxCost: UInt8;

Source/DECHashAuthentication.pas

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -792,7 +792,7 @@ TDECPasswordHash = class(TDECHashAuthentication)
792792
/// 128 bit has been specified.
793793
/// </exception>
794794
class function GetDigestInCryptFormat(
795-
const Password : RawByteString;
795+
const Password : string;
796796
const Params : string;
797797
const Salt : string;
798798
SaltIsRaw : Boolean;
@@ -1480,6 +1480,10 @@ procedure TDECPasswordHash.SetSalt(const Value: TBytes);
14801480
if (Length(Value) < MinSaltLength) then
14811481
raise EDECHashException.CreateFmt(sSaltValueTooShort, [MinSaltLength]);
14821482

1483+
//// Angeblich verursacht das hier das Speicherleck?!
1484+
// SetLength(FSalt, Length(Value));
1485+
// if (Length(Value) > 0) then
1486+
// Move(Value[0], FSalt[0], Length(Value));
14831487
FSalt := Value;
14841488
end;
14851489

@@ -1551,7 +1555,7 @@ class function TDECPasswordHash.GetCryptHash(
15511555
end;
15521556

15531557
class function TDECPasswordHash.GetDigestInCryptFormat(
1554-
const Password : RawByteString;
1558+
const Password : string;
15551559
const Params : string;
15561560
const Salt : string;
15571561
SaltIsRaw : Boolean;
@@ -1569,12 +1573,19 @@ class function TDECPasswordHash.GetDigestInCryptFormat(
15691573
if SaltIsRaw then
15701574
SaltBytes := TEncoding.UTF8.GetBytes(Salt)
15711575
else
1572-
SaltBytes := Format.Decode(TEncoding.UTF8.GetBytes(Salt));
1576+
SaltBytes := [20, 75, 61, 105, 26, 123, 78, 207, 57, 207, 115, 92, 127, 167, 167, 156]; //Format.Decode(TEncoding.UTF8.GetBytes(Salt));
1577+
1578+
// Mal noch mehr mocken um einzugrenzen welche Nutzung von Salt das Leck verursacht
1579+
// Result := Result + GetCryptParams(Params, Format) +
1580+
// GetCryptSalt(SaltBytes, Format) +
1581+
// GetCryptHash(Password, Params, SaltBytes, Format);
15731582

15741583
Result := Result + GetCryptParams(Params, Format) +
15751584
GetCryptSalt(SaltBytes, Format) +
15761585
GetCryptHash(Password, Params, SaltBytes, Format);
15771586
end;
1587+
1588+
SetLength(SaltBytes, 0);
15781589
end;
15791590

15801591
end.

Unit Tests/Tests/TestDECHash.pas

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -672,7 +672,7 @@ TestTHash_BCrypt = class(THash_TestPasswordBase)
672672
type
673673
// Extract only the interesting parts
674674
TBCryptBSDTestData = record
675-
Salt : RawByteString;
675+
Salt : string;
676676
Cost : UInt8;
677677
end;
678678

@@ -6302,7 +6302,7 @@ function TestTHash_BCrypt.SplitTestVector(Vector: string): TBCryptBSDTestData;
63026302
begin
63036303
Parts := Vector.Split(['$'], TStringSplitOptions.ExcludeEmpty);
63046304
Result.Cost := Copy(Parts[1], Low(Parts[1]), Length(Parts[1])).ToInteger;
6305-
Result.Salt := RawByteString(Copy(Parts[2], Low(Parts[2]), 22));
6305+
Result.Salt := Copy(Parts[2], Low(Parts[2]), 22);
63066306
end;
63076307

63086308
procedure TestTHash_BCrypt.TestBlockSize;
@@ -6365,11 +6365,12 @@ TPair = record
63656365
i : Integer;
63666366
SplitData : TBCryptBSDTestData;
63676367
begin
6368-
for i := Low(TestData) to High(TestData) do
6368+
for i := Low(TestData) to 1 do //High(TestData) do
63696369
begin
63706370
SplitData := SplitTestVector(TestData[i].bs);
6371+
// Fix memory leaks we get
63716372
Result := string(THash_BCrypt.GetDigestInCryptFormat(
6372-
RawByteString(Passwords[TestData[i].pn]),
6373+
Passwords[TestData[i].pn],
63736374
SplitData.Cost.ToString,
63746375
SplitData.Salt,
63756376
False,

0 commit comments

Comments
 (0)