Reputation: 1307
Oki So I want to hash my password by appending random salt in .Net . The inbuilt classes I m using for this purpose are RNGCryptoServiceProvider - to generate the random salt and Rfc2898DeriveBytes - to hash the actual password.
But when I call the GetBytes() function of Rfc2898DeriveBytes for the same combination of passwordString, SaltBytes & Iteration count the result is different. I m pasting my code for reference
public class PBKDF2Implementation
{
int minSaltSize = 32;
int maxSaltSize = 64;
public string CreateHash(string plainText , out string salt)
{
Random random = new Random();
int saltSize = random.Next(minSaltSize, maxSaltSize);
// Allocate a byte array, which will hold the salt.
byte[] saltBytes = new byte[saltSize];
// Initialize a random number generator.
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
// Fill the salt with cryptographically strong byte values.
rng.GetNonZeroBytes(saltBytes);
string strSalt = System.Text.Encoding.ASCII.GetString(saltBytes);
//string strSalt = System.Convert.ToBase64String(saltBytes);
salt = strSalt;
Console.WriteLine(saltBytes.Count());
Console.WriteLine(strSalt);
Rfc2898DeriveBytes pwdGen = new Rfc2898DeriveBytes(plainText, saltBytes, 1000);
// generate an RC2 key
byte[] key = pwdGen.GetBytes(32);
Console.WriteLine(System.Convert.ToBase64String(key));
return System.Convert.ToBase64String(key);
}
public bool CompareHash(string plainText, string salt, string hashValue)
{
byte[] saltBytes = System.Text.Encoding.ASCII.GetBytes(salt);
//byte[] saltBytes = System.Convert.FromBase64String(salt);
Console.WriteLine(saltBytes.Count());
Console.WriteLine(System.Text.Encoding.ASCII.GetString(saltBytes));
Rfc2898DeriveBytes pwdGen = new Rfc2898DeriveBytes(plainText, saltBytes, 1000);
// generate an RC2 key
byte[] key = pwdGen.GetBytes(32);
Console.WriteLine(System.Convert.ToBase64String(key));
return System.Convert.ToBase64String(key) == hashValue;
}
}
And in my test class I hav this function
[Test]
public void shouldGenerateConsistentHash()
{
PBKDF2Implementation cPbkdf2Implementation = new PBKDF2Implementation();
string salt;
string hashValue = cPbkdf2Implementation.CreateHash("password", out salt);
bool result = cPbkdf2Implementation.CompareHash("password", salt, hashValue);
Assert.IsTrue(result) ;
}
The test fails.
But if in the above class PBKDF2Implementation if I replace the lines
System.Text.Encoding.ASCII.GetString with System.Text.Encoding.Unicode.GetString
and
System.Text.Encoding.ASCII.GetBytes with System.Text.Encoding.Unicode.GetBytes
The test passes. any idea why is this happening? The reason I want to make it work with ASCII encoding is because the same DB in which this hashvalue is stored will also be used by a PHP application & the hashvalue produced by PBKDF2 implementaion of PHP matches the hashvalue of Rfc2898DeriveBytes only if the salt encoding is ASCII.
Here is the PHP implementation of the same http://www.php.net/manual/en/function.hash-hmac.php#101540
Upvotes: 4
Views: 2751
Reputation: 43543
byte[]
E.g.
byte [] data = new byte [] { 65, 0, 65 };
var s = System.Text.Encoding.ASCII.GetString (data);
what is s
value ?
Answer: "A"
If you ask the byte[]
out of the same string you'll get: byte [1] { 65 }
, which is not the same as the original and won't work for most cryptographic usage.
Base64 is safer since it will keep every byte intact.
Upvotes: 7