I feel pretty stupid asking this, but as I don't know the answer, I'm going ahead anyway.
I"m trying out some authentication code and want to know why the byte array I get from Rfc2898DeriveBytes needs to be converted to HEX and back to a byte array again for it to correctly initialise my HMACSHA1 object. I feel like I am doing something silly, or simply missing something obvious.
My client code is a javascript function based on crypto-js;
var key256bit = Crypto.PBKDF2(passwordEntered, saltBytes, 32, { iterations: 1000 });
var hmacBytes = Crypto.HMAC(Crypto.SHA1, url, key256bit, { asBytes: true });
var base64Hash = Crypto.util.bytesToBase64(hmacBytes);
My Server side code is as follows;
Rfc2898DeriveBytes rfc2898 = new Rfc2898DeriveBytes(password,
encoding.GetBytes(salt), 1000);
byte[] key = rfc2898.GetBytes(32);
// Don't think I should need to do this.
// However, it wont work if I initialise HMACSHA1
// with the rfc2898.GetBytes(32)
string test = ByteArrayToString(key);
HMACSHA1 hmacSha1 = new HMACSHA1(encoding.GetBytes(test));
byte[] computedHash = hmacSha1.ComputeHash(encoding.GetBytes(requestUri));
string computedHashString = Convert.ToBase64String(computedHash);
My ByteArrayToString method which I nabbed from the web is;
private static string ByteArrayToString(byte[] ba)
{
StringBuilder hex = new StringBuilder(ba.Length * 2);
foreach (byte b in ba)
hex.AppendFormat("{0:x2}", b);
return hex.ToString();
}
So I can see that I get 32 bytes from my call to rfc2898.GetBytes(32)
. I converted that to HEX using the ByteArrayToString method to confirm it matches what I am seeing in my Javascript variable key256bit. Now my test variable is a string of length 64 and when I pass that to HMACSHA1's constuctor using encoding.GetBytes(test) it is a byte array of length 64.
The doco on crypto-js is a bit lacking, but I thought the call to Crypto.PBKDF2 with a param of 32 and it was creating a key of 32 bytes long (or 256 bits).
Any clarification is much appreciated.
I suspect this is the root of the issue, in PBKDF2.js:
return options && options.asBytes ? derivedKeyBytes :
options && options.asString ? Binary.bytesToString(derivedKeyBytes) :
util.bytesToHex(derivedKeyBytes);
Because you haven't provided options for either asBytes
or asString
, it's converting the key to a hex representation - just as your C# code does. So at the moment you are using a 512 bit key, precisely because you're generating 2 bytes of "used key" from each byte of "original key".
I suspect that if you specify the asBytes
option in the Javascript, it will just work without the extra hex part in the C# code.
Then again, I've never seen PBKDF2 before, so I could be way off base...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With