'How do I match HMACSHA1 from C# to Javascript
A hashing algorithm in C# needs an exact match in javascript. Because of the logging, I can see that the bytes for the key, and the bytes for the password are the same, but the outputs are different.
What is different between the C# HMACSHA1 code and the javascript crypto.createHmac code that makes it give a different answer? How do I fix the javascript code so that it matches C#?
The C# code (I can't change this) looks like this:
private static string HashPassword(string password)
{
HMACSHA1 hash = new HMACSHA1();
byte[] keyBytes = HexToByte(SECRET_KEY);
hash.Key = keyBytes;
Byte[] passwordBytes = Encoding.Unicode.GetBytes(password);
Console.WriteLine(BitConverter.ToString(keyBytes));
Console.WriteLine(BitConverter.ToString(passwordBytes));
return Convert.ToBase64String(hash.ComputeHash(passwordBytes));
}
To match this, I created a function using the crypto module in node.
var hash_password = function(password) {
var keyBytes = Buffer.alloc(SECRET_KEY.length/2, SECRET_KEY, 'hex');
console.log(toHexString(Uint8Array.from(keyBytes)));
var hasher = crypto.createHmac("sha1", keyBytes);
var passwordBytes = stringToBytes16(password);
console.log(passwordBytes);
return hasher.update(passwordBytes).digest("Base64");
}
I even tried removing the javascript logging in case that was changing anything, but the output was the same either way.
Edit: keyBytes is not a string. In C#, it's a byte array, and in javascript its a Buffer. As far as I know, the important thing is that they contain the same bytes.
javascript: <Buffer 68 00 75 00 6e 00 74 00 65 00 72 00 32 00 0a 00>
C#: 68-00-75-00-6E-00-74-00-65-00-72-00-32-00
Pastebin for stringToBytes16 and toHexString.
Solution 1:[1]
I realize the answer is in the above notes, but it took me a while to find it and no one actually posted it. So, here is the working function that produces the same results HMACSHA1 call from .net all the way back to its start.
const crypto = require('crypto');
function hashPasswordSha1(password: string, membershipKey: string) {
const hashPassword = function(password:any) {
function stringToBytes16(str:any) {
let bytesv2:any = []; // char codes
for (let i = 0; i < str.length; ++i) {
const code = str.charCodeAt(i);
bytesv2 = bytesv2.concat([code & 0xff, code / 256 >>> 0]);
}
return Buffer.from(bytesv2);
}
const keyBytes = Buffer.alloc(membershipKey.length/2, membershipKey, 'hex');
const hasher = crypto.createHmac("sha1", keyBytes);
const passwordBytes = stringToBytes16(password);
return hasher.update(passwordBytes).digest("base64");
}
return hashPassword(password);
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
