Skip to content

Commit dbd8687

Browse files
committed
V3.x legacy migration functionality
Add ability to validate and hash using V4 interoperable method while maintaining default V3 behaviour
1 parent a0a72b5 commit dbd8687

6 files changed

Lines changed: 67 additions & 9 deletions

File tree

src/BCrypt.Net.MainPackage/BCrypt.Net.Package.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
<PublicSign Condition=" '$(OS)' != 'Windows_NT' ">true</PublicSign>
2525
<AssemblyOriginatorKeyFile>../bcrypt.pfx</AssemblyOriginatorKeyFile>
2626

27-
<Version>4.0.0</Version>
27+
<Version>3.5.0</Version>
2828
<PackageTags>bcrypt;BCrypt.Net;cryptography;hashing;password;security,hash;crypto;blowfish;gdpr</PackageTags>
2929
<Configurations>Debug;Release</Configurations>
3030
</PropertyGroup>

src/BCrypt.Net.StrongName/BCrypt.Net.StrongName.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
<PublicSign Condition=" '$(OS)' != 'Windows_NT' ">true</PublicSign>
2525
<AssemblyOriginatorKeyFile>../bcrypt.pfx</AssemblyOriginatorKeyFile>
2626

27-
<Version>4.0.0</Version>
27+
<Version>3.5.0</Version>
2828
<PackageTags>bcrypt;BCrypt.Net;cryptography;hashing;password;security,hash;crypto;blowfish;gdpr</PackageTags>
2929
<Configurations>Debug;Release</Configurations>
3030
</PropertyGroup>

src/BCrypt.Net.UnitTests/BCryptTests.cs

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,10 +208,40 @@ public void TestHashPasswordEnhanced_PASSLIB()
208208
//Check hash that goes in one end comes out the next the same
209209
salt = _pythonPassLibTestVectors[i, 1];
210210

211-
string hashed = BCrypt.HashPassword(plain, salt, enhancedEntropy: true, HashType.SHA256);
211+
string hashed = BCrypt.HashPassword(plain, salt, enhancedEntropy: true, HashType.SHA256, v4CompatibleEnhancedEntropy:true);
212212

213213
Assert.Equal(hashed, _pythonPassLibTestVectors[i, 2]);
214214

215+
var validateHashCheck = BCrypt.Verify(plain, hashed, true, HashType.SHA256, v4CompatibleEnhancedEntropy: true);
216+
Assert.True(validateHashCheck);
217+
218+
Trace.WriteLine(hashed);
219+
220+
Trace.Write(".");
221+
}
222+
223+
Trace.WriteLine(sw.ElapsedMilliseconds);
224+
Trace.WriteLine("");
225+
}
226+
227+
[Fact()]
228+
public void TestHashPasswordEnhanced_PASSLIB_V3EnhancedIsNotInteroperable()
229+
{
230+
Trace.Write("BCrypt.HashPassword(): ");
231+
var sw = Stopwatch.StartNew();
232+
233+
for (int i = 0; i < _pythonPassLibTestVectors.Length / 3; i++)
234+
{
235+
string plain = _pythonPassLibTestVectors[i, 0];
236+
string salt;
237+
238+
//Check hash that goes in one end comes out the next the same
239+
salt = _pythonPassLibTestVectors[i, 1];
240+
241+
string hashed = BCrypt.HashPassword(plain, salt, enhancedEntropy: true, HashType.SHA256);
242+
243+
Assert.NotEqual(hashed, _pythonPassLibTestVectors[i, 2]);
244+
215245
var validateHashCheck = BCrypt.EnhancedVerify(plain, hashed, HashType.SHA256);
216246
Assert.True(validateHashCheck);
217247

src/BCrypt.Net/BCrypt.Net.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
<License>https://github.com/BcryptNet/bcrypt.net/blob/master/licence.txt</License>
2020
<PackageLicenseUrl>https://github.com/BcryptNet/bcrypt.net/blob/master/licence.txt</PackageLicenseUrl>
2121

22-
<Version>4.0.0</Version>
22+
<Version>3.5.0</Version>
2323

2424
<Configurations>Debug;Release</Configurations>
2525
</PropertyGroup>

src/BCrypt.Net/BCrypt.cs

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -596,7 +596,7 @@ public static string ValidateAndReplacePassword(string currentKey, string curren
596596
/// <returns>The hashed password</returns>
597597
/// <exception cref="ArgumentNullException">Thrown when the <paramref name="inputKey"/> is null.</exception>
598598
/// <exception cref="SaltParseException">Thrown when the <paramref name="salt"/> could not be parsed.</exception>
599-
public static string HashPassword(string inputKey, string salt, bool enhancedEntropy, HashType hashType = DefaultEnhancedHashType)
599+
public static string HashPassword(string inputKey, string salt, bool enhancedEntropy, HashType hashType = DefaultEnhancedHashType, bool v4CompatibleEnhancedEntropy = false)
600600
{
601601
if (inputKey == null)
602602
{
@@ -653,10 +653,14 @@ public static string HashPassword(string inputKey, string salt, bool enhancedEnt
653653

654654
byte[] inputBytes;
655655

656-
if (enhancedEntropy)
656+
if (enhancedEntropy && v4CompatibleEnhancedEntropy)
657657
{
658658
inputBytes = EnhancedHash(SafeUTF8.GetBytes(inputKey), bcryptMinorRevision, hashType);
659659
}
660+
else if (enhancedEntropy)
661+
{
662+
inputBytes = V3EnhancedHash(SafeUTF8.GetBytes(inputKey + (bcryptMinorRevision >= 'a' ? Nul : EmptyString)), hashType);
663+
}
660664
else
661665
{
662666
inputBytes = SafeUTF8.GetBytes(inputKey + (bcryptMinorRevision >= 'a' ? Nul : EmptyString));
@@ -704,6 +708,29 @@ private static byte[] EnhancedHash(byte[] inputBytes, char bcryptMinorRevision,
704708
return inputBytes;
705709
}
706710

711+
private static byte[] V3EnhancedHash(byte[] inputBytes, HashType hashType)
712+
{
713+
switch (hashType)
714+
{
715+
case HashType.SHA256:
716+
inputBytes = SafeUTF8.GetBytes(Convert.ToBase64String(SHA256.Create().ComputeHash(inputBytes)));
717+
break;
718+
case HashType.SHA384:
719+
inputBytes = SafeUTF8.GetBytes(Convert.ToBase64String(SHA384.Create().ComputeHash(inputBytes)));
720+
break;
721+
case HashType.SHA512:
722+
inputBytes = SafeUTF8.GetBytes(Convert.ToBase64String(SHA512.Create().ComputeHash(inputBytes)));
723+
break;
724+
case HashType.Legacy384:
725+
inputBytes = SHA384.Create().ComputeHash(inputBytes);
726+
break;
727+
default:
728+
throw new ArgumentOutOfRangeException(nameof(hashType), hashType, null);
729+
}
730+
731+
return inputBytes;
732+
}
733+
707734

708735
/// <summary>
709736
/// Generate a salt for use with the <see cref="BCrypt.HashPassword(string, string)"/> method.
@@ -803,9 +830,9 @@ public static string GenerateSalt()
803830
/// <returns>true if the passwords match, false otherwise.</returns>
804831
/// <exception cref="ArgumentException">Thrown when one or more arguments have unsupported or illegal values.</exception>
805832
/// <exception cref="SaltParseException">Thrown when the salt could not be parsed.</exception>
806-
public static bool Verify(string text, string hash, bool enhancedEntropy = false, HashType hashType = DefaultEnhancedHashType)
833+
public static bool Verify(string text, string hash, bool enhancedEntropy = false, HashType hashType = DefaultEnhancedHashType, bool v4CompatibleEnhancedEntropy=false)
807834
{
808-
return SecureEquals(SafeUTF8.GetBytes(hash), SafeUTF8.GetBytes(HashPassword(text, hash, enhancedEntropy, hashType)));
835+
return SecureEquals(SafeUTF8.GetBytes(hash), SafeUTF8.GetBytes(HashPassword(text, hash, enhancedEntropy, hashType, v4CompatibleEnhancedEntropy)));
809836
}
810837

811838
// Compares two byte arrays for equality. The method is specifically written so that the loop is not optimised.

src/BCrypt.Net/HashType.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ public enum HashType
1010
None = -1,
1111
SHA256 = 0,
1212
SHA384 = 1,
13-
SHA512 = 2
13+
SHA512 = 2,
14+
Legacy384 = 3
1415
}
1516
}

0 commit comments

Comments
 (0)