Skip to content

Commit 77e52c4

Browse files
committed
Finished implementation of RawByteString version of GetCryptHash. Some cleanup of comments.
1 parent 417baa5 commit 77e52c4

File tree

4 files changed

+209
-98
lines changed

4 files changed

+209
-98
lines changed

Source/DECHash.pas

Lines changed: 72 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1177,34 +1177,48 @@ THash_BCrypt = class(TDECPasswordHash)
11771177
/// Returns the parameters required for the crypt-like password storing
11781178
/// in that format.
11791179
/// </summary>
1180-
/// <param name="Format">
1181-
/// Format class for formatting the output
1180+
/// <param name="Params">
1181+
/// In case of BCrypt this has to be the numeric integer value of "Cost".
1182+
/// This method will ensure it is prefixed with 0 when having too few chars
11821183
/// </param>
1183-
function GetCryptParams(Format : TDECFormatClass):RawByteString; override;
1184-
/// <summary>
1185-
/// Returns the salt required for the crypt-like password storing
1186-
/// in that format.
1187-
/// </summary>
11881184
/// <param name="Format">
11891185
/// Format class for formatting the output
11901186
/// </param>
1191-
function GetCryptSalt(Format: TDECFormatClass):RawByteString; override;
1187+
class function GetCryptParams(
1188+
const Params : RawByteString;
1189+
Format : TDECFormatClass):RawByteString; override;
11921190
/// <summary>
11931191
/// Returns the hash required for the crypt-like password storing
1194-
/// in that format. If a salt etc. is needed that needs to be scepcified
1192+
/// in that format. If a salt etc. is needed that needs to be specified
11951193
/// before calling this method.
11961194
/// </summary>
11971195
/// <param name="Password">
11981196
/// Password entered which shall be hashed.
11991197
/// </param>
1198+
/// <param name="Params">
1199+
/// In case of BCrypt this has to be the numeric integer value of "Cost"
1200+
/// </param>
1201+
/// <param name="Salt">
1202+
/// Salt value used by the password hash calculation. Depending on the
1203+
/// value of SaltIsRaw, the salt needs to specified in raw encoding or
1204+
/// in the encoding used in the Crypt/BSD password storage string.
1205+
/// </param>
1206+
/// <param name="SaltIsRaw">
1207+
/// If true the passed salt value is a raw value. If false it is encoded
1208+
/// like in the Crypt/BSD password storage string.
1209+
/// </param>
12001210
/// <param name="Format">
12011211
/// Format class for formatting the output
12021212
/// </param>
12031213
/// <returns>
12041214
/// Calculated hash value
12051215
/// </returns>
1206-
function GetCryptHash(Password : RawByteString;
1207-
Format : TDECFormatClass):RawByteString; override;
1216+
class function GetCryptHash(
1217+
const Password : RawByteString;
1218+
const Params : RawByteString;
1219+
const Salt : RawByteString;
1220+
SaltIsRaw : Boolean;
1221+
Format : TDECFormatClass):RawByteString; override;
12081222
{$EndRegion}
12091223
public
12101224
/// <summary>
@@ -5076,16 +5090,16 @@ procedure THash_BCrypt.Expandkey(Salt : TBytes;
50765090
begin
50775091
KBP := @Password[0];
50785092

5079-
{Text explanations and comments are from the N.Provos & D.Mazieres paper.}
5093+
// Text explanations and comments are from the N.Provos & D.Mazieres paper.
50805094

5081-
{ExpandKey(state,salt,key) modifies the P-Array and S-boxes based on the }
5082-
{value of the 128-bit salt and the variable length key. First XOR all the}
5083-
{subkeys in the P-array with the encryption key. The first 32 bits of the}
5084-
{key are XORed with P1, the next 32 bits with P2, and so on. The key is }
5085-
{viewed as being cyclic; when the process reaches the end of the key, it }
5086-
{starts reusing bits from the beginning to XOR with subkeys. }
5095+
// ExpandKey(state,salt,key) modifies the P-Array and S-boxes based on the
5096+
// value of the 128-bit salt and the variable length key. First XOR all the
5097+
// subkeys in the P-array with the encryption key. The first 32 bits of the
5098+
// key are XORed with P1, the next 32 bits with P2, and so on. The key is
5099+
// viewed as being cyclic; when the process reaches the end of the key, it
5100+
// starts reusing bits from the beginning to XOR with subkeys.
50875101

5088-
{WE: Same as standard key part except that PArray[i] is used for _bf_p[i]}
5102+
// WE: Same as standard key part except that PArray[i] is used for _bf_p[i]
50895103
k := 0;
50905104
for i := 0 to 17 do
50915105
begin
@@ -5102,20 +5116,20 @@ procedure THash_BCrypt.Expandkey(Salt : TBytes;
51025116
FContext.PArray[i] := FContext.PArray[i] xor KL;
51035117
end;
51045118

5105-
{Subsequently, ExpandKey blowfish-encrypts the first 64 bits of}
5106-
{its salt argument using the current state of the key schedule.}
5119+
// Subsequently, ExpandKey blowfish-encrypts the first 64 bits of
5120+
// its salt argument using the current state of the key schedule.
51075121
BF_Encrypt(PBFBlock(@salt[0])^, tmp);
51085122

5109-
{The resulting ciphertext replaces subkeys P_1 and P_2.}
5123+
// The resulting ciphertext replaces subkeys P_1 and P_2.
51105124
FContext.PArray[0] := SwapUInt32(TBF2Long(tmp).L);
51115125
FContext.PArray[1] := SwapUInt32(TBF2Long(tmp).R);
51125126

5113-
{That same ciphertext is also XORed with the second 64-bits of }
5114-
{salt, and the result encrypted with the new state of the key }
5115-
{schedule. The output of the second encryption replaces subkeys}
5116-
{P_3 and P_4. It is also XORed with the first 64-bits of salt }
5117-
{and encrypted to replace P_5 and P_6. The process continues, }
5118-
{alternating between the first and second 64 bits salt. }
5127+
// That same ciphertext is also XORed with the second 64-bits of
5128+
// salt, and the result encrypted with the new state of the key
5129+
// schedule. The output of the second encryption replaces subkeys
5130+
// P_3 and P_4. It is also XORed with the first 64-bits of salt
5131+
// and encrypted to replace P_5 and P_6. The process continues,
5132+
// alternating between the first and second 64 bits salt.
51195133
h := 8;
51205134
for i := 1 to 8 do
51215135
begin
@@ -5126,53 +5140,62 @@ procedure THash_BCrypt.Expandkey(Salt : TBytes;
51265140
FContext.PArray[2*i+1] := SwapUInt32(TBF2Long(tmp).R);
51275141
end;
51285142

5129-
{When ExpandKey finishes replacing entries in the P-Array, it continues}
5130-
{on replacing S-box entries two at a time. After replacing the last two}
5131-
{entries of the last S-box, ExpandKey returns the new key schedule. }
5143+
// When ExpandKey finishes replacing entries in the P-Array, it continues
5144+
// on replacing S-box entries two at a time. After replacing the last two
5145+
// entries of the last S-box, ExpandKey returns the new key schedule.
51325146
for j := 0 to 3 do
51335147
begin
51345148
for i := 0 to 127 do
51355149
begin
51365150
BF_XorBlock(tmp, PBFBlock(@Salt[h])^, tmp);
51375151
h := h xor 8;
51385152
BF_Encrypt(tmp, tmp);
5139-
FContext.SBox[j, 2*i] := SwapUInt32(TBF2Long(tmp).L);
5140-
FContext.SBox[j, 2*i+1]:= SwapUInt32(TBF2Long(tmp).R);
5153+
FContext.SBox[j, 2*i] := SwapUInt32(TBF2Long(tmp).L);
5154+
FContext.SBox[j, 2*i+1] := SwapUInt32(TBF2Long(tmp).R);
51415155
end;
51425156
end;
51435157
end;
51445158

5145-
function THash_BCrypt.GetCryptHash(Password : RawByteString;
5146-
Format : TDECFormatClass): RawByteString;
5159+
class function THash_BCrypt.GetCryptHash(
5160+
const Password : RawByteString;
5161+
const Params : RawByteString;
5162+
const Salt : RawByteString;
5163+
SaltIsRaw : Boolean;
5164+
Format : TDECFormatClass): RawByteString;
5165+
var
5166+
Hash : THash_BCrypt;
51475167
begin
5148-
// BCrypt leaves off the $ in front of the actual password hash value
5149-
Result := CalcString(Password, Format);
5168+
Hash := THash_BCrypt.Create;
5169+
try
5170+
Hash.Cost := StrToInt(string(Params));
5171+
if SaltIsRaw then
5172+
Hash.Salt := BytesOf(Salt)
5173+
else
5174+
Hash.Salt := Format.Decode(BytesOf(Salt));
5175+
5176+
// BCrypt leaves off the $ in front of the actual password hash value
5177+
Result := Hash.CalcString(Password, Format);
5178+
finally
5179+
Hash.Free;
5180+
end;
51505181
end;
51515182

51525183
class function THash_BCrypt.GetCryptID: RawByteString;
51535184
begin
51545185
Result := '$2a';
51555186
end;
51565187

5157-
function THash_BCrypt.GetCryptParams(Format : TDECFormatClass): RawByteString;
5188+
class function THash_BCrypt.GetCryptParams(
5189+
const Params : RawByteString;
5190+
Format : TDECFormatClass): RawByteString;
51585191
begin
5159-
Result := RawByteString(FCost.ToString);
5192+
Result := Params;
51605193
if (Length(Result) < 2) then
51615194
Result := '0' + Result;
51625195

51635196
Result := '$' + Result;
51645197
end;
51655198

5166-
function THash_BCrypt.GetCryptSalt(Format: TDECFormatClass): RawByteString;
5167-
var
5168-
FormattedSalt : TBytes;
5169-
begin
5170-
FormattedSalt := Format.Encode(FSalt);
5171-
SetLength(Result, Length(FormattedSalt) + 1);
5172-
Move(FormattedSalt[0], Result[Low(Result) + 1], Length(FormattedSalt));
5173-
Result[Low(Result)] := '$';
5174-
end;
5175-
51765199
procedure THash_BCrypt.BF_Encrypt(const BI: TBFBlock; var BO: TBFBlock);
51775200
var
51785201
xl, xr : UInt32;

0 commit comments

Comments
 (0)