How to validate hash format?
AlirezaAsadi96 opened this issue · 4 comments
Hi.
How to found current hash is valid?
Below method validate hash and replace new password hash:
BCrypt.ValidateAndReplacePassword
But I don't want replace hash, Just validate current hash without password like this BCrypt.ValidateHash(currentHash)
How can I do that?
BCrypt.Net.BCrypt.Verify(givenPassword, hashedPassword)
@AlirezaAsadi96 you just want to validate the format or you want to determine that its a bcrypt hash?
@AlirezaAsadi96 you just want to validate the format or you want to determine that its a bcrypt hash?
Just validate the format of bcrypt hash
It's not really something I'd expose as its more of a utility function than part of the bcrypt public api but you can easily add code like this.
using System;
public class Program
{
private static readonly HashFormatDescriptor OldFormatDescriptor = new HashFormatDescriptor(versionLength: 1);
private static readonly HashFormatDescriptor NewFormatDescriptor = new HashFormatDescriptor(versionLength: 2);
public class HashFormatDescriptor
{
public HashFormatDescriptor(int versionLength)
{
VersionLength = versionLength;
WorkfactorOffset = 1 + VersionLength + 1;
SettingLength = WorkfactorOffset + 2;
HashOffset = SettingLength + 1;
}
public int VersionLength
{
get;
}
public int WorkfactorOffset
{
get;
}
public int SettingLength
{
get;
}
public int HashOffset
{
get;
}
}
public static bool IsValidHash(string hash, out HashFormatDescriptor format)
{
if (hash is null)
{
throw new ArgumentNullException(nameof(hash));
}
if (hash.Length != 59 && hash.Length != 60)
{
// Incorrect full hash length
format = null;
return false;
}
if (!hash.StartsWith("$2"))
{
// Not a bcrypt hash
format = null;
return false;
}
// Validate version
int offset = 2;
if (IsValidBCryptVersionChar(hash[offset]))
{
offset++;
format = NewFormatDescriptor;
}
else
{
format = OldFormatDescriptor;
}
if (hash[offset++] != '$')
{
format = null;
return false;
}
// Validate workfactor
if (!IsAsciiNumeric(hash[offset++]) || !IsAsciiNumeric(hash[offset++]))
{
format = null;
return false;
}
if (hash[offset++] != '$')
{
format = null;
return false;
}
// Validate hash
for (int i = offset; i < hash.Length; ++i)
{
if (!IsValidBCryptBase64Char(hash[i]))
{
format = null;
return false;
}
}
return true;
}
private static bool IsValidBCryptVersionChar(char value)
{
return value == 'a' || value == 'b' || value == 'x' || value == 'y';
}
private static bool IsValidBCryptBase64Char(char value)
{
// Ordered by ascending ASCII value
return value == '.' || value == '/' || (value >= '0' && value <= '9') || (value >= 'A' && value <= 'Z') || (value >= 'a' && value <= 'z');
}
private static bool IsAsciiNumeric(char value)
{
return value >= '0' && value <= '9';
}
public static void Main()
{
Console.WriteLine(IsValidHash("$2y$12$WDviXbO4Y8VM.aS.vmv7FOt3/KztzzVjLb7U/NOMjdzdXDiBbaHRC", out _));
Console.WriteLine(IsValidHash("X2y$12$WDviXbO4Y8VM.aS.vmv7FOt3/KztzzVjLb7U/NOMjdzdXDiBbaHRC", out _));
}
}
You can sling it in https://dotnetfiddle.net/ to test