Confused on how to implement HMACSHA1 in C# .NET coming from javascript - javascript

I am using the crypto-js library to implement the HMACSHA1 for my javascript code
the code looks like this
const hash1 = require("crypto-js");
let signature = "application_id=3610&auth_key=aDRceQyTXSYEdJU&nonce=6304033672&timestamp=1623098533&user[login]=john#mail.com&user[password]=123456789"
let key = "dBV2PdhYMnruSMb"
let hash = hash1.HmacSHA1(signature, key).toString()
console.log(hash)
//which prints
467280c4cb82fc97bd04c51d8a846446ad6e82e1
this obviously is pretty easy in javascript. But then I tried using the same exact string and key in c# and it prints out a completely different string. I am lost and don't know how to solve this issue.
Here is my attempt to implement this in C#
string signSession = "application_id=3610&auth_key=aDRceQyTXSYEdJU&nonce=6304033672&timestamp=1623098533&user[login]=john#mail.com&user[password]=123456789"
string key = "dBV2PdhYMnruSMb="
//convert the session signature string to a byte array
byte[] signature = Encoding.UTF8.GetBytes(signSession.ToString());
var apiKey = Convert.FromBase64String(key);
//Generate a HMACSHA1 signature
using(HMACSHA1 hmac = new HMACSHA1(apiKey))
{
byte[] signatureBytes = hmac.ComputeHash(signature);
string base64Signature = Convert.ToBase64String(signatureBytes);
Console.WriteLine(base64Signature);
session.Signature = base64Signature;
}
//And this prints
sztTnSTv2xvuA7pPXxk2cKMP0Eo=
//which is wrong. It should be the same as the javascript result
Im not sure what im doing wrong here and is my C# implementation right?

Your key is different. While crypto-js expects a string, C# expects a byte array. You shouldn't use FromBase64String() but Encoding.UTF8.GetBytes(). As #jps mentioned in the comment
Of course it's different, your JS implementation has a hex encoded
output but in your C# implementation you're base64 encoding the
result.
you should convert the byte-array to a hex-string like so
string signSession = "application_id=3610&auth_key=aDRceQyTXSYEdJU&nonce=6304033672&timestamp=1623098533&user[login]=john#mail.com&user[password]=123456789";
string key = "dBV2PdhYMnruSMb";
//convert the session signature string to a byte array
byte[] signature = Encoding.UTF8.GetBytes(signSession);
var apiKey = Encoding.UTF8.GetBytes(key);
//Generate a HMACSHA1 signature
using (HMACSHA1 hmac = new HMACSHA1(apiKey))
{
byte[] signatureBytes = hmac.ComputeHash(signature);
string hexSignature = BitConverter.ToString(signatureBytes).ToLowerInvariant().Replace("-", "");
Console.WriteLine(hexSignature);
session.Signature = hexSignature;
}

Related

Conversion from buffer to string gives different results in c# and Nodejs

I'm trying to convert this function from C# to node but I'm getting different results when I try to convert a buffer to a string.
string str = "34924979";
System.Security.Cryptography.SHA512 sha = new System.Security.Cryptography.SHA512Managed();
byte[] ba = System.Text.Encoding.ASCII.GetBytes(str);
byte[] data= sha.ComputeHash(ba);
Console.WriteLine(System.Text.Encoding.ASCII.GetString(data));
>> `?????gV)????∟?Z?s??v$We-??N?"?w????0??\i♠G???
that's what i'm trying to do.
const crypto = require('crypto')
const str = '34924979';
const sha = crypto.createHash('sha512').update(str).digest('utf8');
const hash = sha.toString('utf-8').replace(/\uFFFD/g, '?');
console.log(hash);
>> `????gV)????∟?Z?v$We-??N?"?w????0?\i♠Gߕ?
You're using different encodings in C# and JS.
Try changing the JS code to the following:
const sha = crypto.createHash('sha512').update(str).digest('ascii');
const hash = sha.toString('ascii');

try to generating signature using HMACSHA512 in c#

signature in c# using HMACSHA512 not equivalent to java and JavaScript.
after tracing my c# code i found the key is not used during generating signature.
using System.Security.Cryptography;
using System.Text;
string privateKey = "OPAYPRV16388855997950.6319778282304234";
string message = "{\r\n \"country\": \"EG\",\r\n \"reference\": \"9cf357a79ffc4cb5a57cd0489a1a4bfa\"\r\n}";
byte[] messagebyte = Encoding.Default.GetBytes(message);
byte[] pkey = Encoding.Default.GetBytes(privateKey);
HMACSHA512 hMACSHA512 = new HMACSHA512(pkey);
//hMACSHA512.Key = pkey; //other way and not give right signature
//hmacsha512.Initialize();
var hmac = hMACSHA512.ComputeHash(messagebyte);
var hmacres = BitConverter.ToString(hmac).Replace("-", "");
Console.WriteLine(hmacres);
// signature c# =FC96AABB47DE439A78CB98943BA3E9F9C25B24264E1431CC4180348F5B48C869F9003E3B67B8E387D25A7189093ACDD90205A103A489856379971EBE07E295E5
// signature in java and JavaScript (the same and the right signature)=
20c8b06951a7907b48db0ccb0b1fb514e8addb2b7c72786cc21316576d57e57560188cac837ffe232a9b24e65e73c6c05e6a5dddff3cc03e26521c92e74e064d
HMACSHA512 deal with \r\n and spaces as characters, when remove /r/n and space I got the right signature
message= message.Replace(System.Environment.NewLine, string.Empty).Replace(" ", "");
byte[] messagebyte = Encoding.Default.GetBytes(message);
byte[] pkey = Encoding.Default.GetBytes(privateKey);
HMACSHA512 hMACSHA512 = new HMACSHA512(pkey);
var hmac = hMACSHA512.ComputeHash(messagebyte);
var hmacres = BitConverter.ToString(hmac).Replace("-", "");

unable to get the value of decoded base64 data in node

this value was encoded to base64
{
a: "008078888658936",
b: "REA"
}
and was decoded using this code
var mytokenvalue = "ewphOiAiMDA4MDc4ODg4NjU4OTM2IiwKYjogIlJFQSIKfQ=="
let decoded = Buffer.from(token, 'base64')
meanwhile, when I try to get the decoded value
console.log(decoded.a)
I am getting undefined in my console.
Please help
You may need to return the decoded value as a string with .toString().
let token = "ewphOiAiMDA4MDc4ODg4NjU4OTM2IiwKYjogIlJFQSIKfQ==";
let decoded = Buffer.from(token, 'base64').toString();
console.log(decoded);
You could do:
var token = "ewphOiAiMDA4MDc4ODg4NjU4OTM2IiwKYjogIlJFQSIKfQ==";
eval('var decoded = ' + Buffer.from(token, 'base64').toString());
console.log(decoded.a);
But eval is extremely dangerous if the base64-encoded string can come from somewhere that is outside your control. An arbitrary string could expand to some unexpected JavaScript that would cause eval to do something that would make your program misbehave or breach security.
It would be better to express the original object as a JSON string (use JSON.stringify to do that) and base64-encode that string. Then you can use JSON.parse to reconstruct the original object without taking on the risk of using eval. Like this:
var obj = { x: "foo", y: 123 };
var obj_json = JSON.stringify(obj);
// obj_json is '{"x":"foo","y":123}'
var obj_b64 = Buffer(obj_json).toString('base64');
// obj_b64 is 'eyJ4IjoiZm9vIiwieSI6MTIzfQ=='
var decoded = JSON.parse(Buffer.from(obj_b64, 'base64').toString());
console.log(decoded.x);

Reassemble crypto hmac code in C#

I am trying to reassemble code in C# from JavaScript, Node js code.
I wrote fully working example in Node just to find out if the code is working correctly but now i am having problems with finding equivalent functions in C#.
JavaScript code using Node.js.
var crypto = require('crypto');
var timestamp = Date.now() / 1000;
var what = timestamp + "hello";
var secret = "SGVsbG8gV29ybGQ=";
var key = Buffer(secret, 'base64');
var hmac = crypto.createHmac('sha256', key);
hmac.update(what);
var t = hmac.digest('base64');
console.log(t);
I am only in need of knowing how to reassemble those functions:
var key = Buffer(secret, 'base64');
var hmac = crypto.createHmac('sha256', key);
hmac.update(what);
Here's a c# example. It includes a function. You would pass your timestamp info as the string I assume, but it can be done with any string.
https://dotnetfiddle.net/eAZGfE
public static string HashString(string StringToHash, string HachKey)
{
System.Text.UTF8Encoding myEncoder = new System.Text.UTF8Encoding();
byte[] Key = myEncoder.GetBytes(HachKey);
byte[] Text = myEncoder.GetBytes(StringToHash);
System.Security.Cryptography.HMACSHA1 myHMACSHA1 = new System.Security.Cryptography.HMACSHA1(Key);
byte[] HashCode = myHMACSHA1.ComputeHash(Text);
string hash = BitConverter.ToString(HashCode).Replace("-", "");
return hash.ToLower();
}

Generate Base64 MD5 hash of byte array

I have following security encoding implemented in my c# web api:
string testStr = "test";
ASCIIEncoding encoding = new ASCIIEncoding(); //using System.Text;
byte[] byteData = encoding.GetBytes(testStr);
MD5 md5 = MD5.Create(); //using System.Security.Cryptography;
string hash = md5.ComputeHash(byteData);
string md5Base64 = Convert.ToBase64String(hash);
I bind this md5Base64 string in header and compare it in API request. This works fine when I hit the API from C# code. Now I need to use it in javascript, so will need js equivalent of above code.
I have tried following but it is giving different output:
var testStr = 'test';
var byteData = testStr.split ('').map(function (c) { return c.charCodeAt (0); });
var hash = MD5(value.join(','));
var md5Base64 = btoa(hash);
the MD5 function used here is from https://stackoverflow.com/a/33486055/7519287
Please let me know what is wrong here.
The problem with your JavaScript code is that you're doing unnecessary conversions: MD5 already takes a string. Furthermore, more conversions after hashing are required.
If we have the following C# code:
string tmp = "test";
byte[] bTmp = System.Text.Encoding.UTF8.GetBytes(tmp);
byte[] hashed = null;
using (System.Security.Cryptography.MD5CryptoServiceProvider md5 = new System.Security.Cryptography.MD5CryptoServiceProvider())
{
hashed = md5.ComputeHash(bTmp);
}
Console.WriteLine(Convert.ToBase64String(hashed));
Fiddle
then the equivalent JavaScript code is:
var tmp = 'test';
var hashed = hex2a(MD5(tmp)); // md5 src: https://stackoverflow.com/a/33486055/7519287
// src: https://stackoverflow.com/a/3745677/3181933
function hex2a(hexx) {
var hex = hexx.toString();//force conversion
var str = '';
for (var i = 0; i < hex.length; i += 2)
str += String.fromCharCode(parseInt(hex.substr(i, 2), 16));
return str;
}
alert(btoa(hashed));
Fiddle
Because MD5 returns a hex string, you have to convert that to ASCII before you can base64 encode it. I wonder if you need base64 encoding? MD5 is usually represented as a hex string. Perhaps on the C# side, instead of Convert.ToBase64String(hashed), you could use BitConverter.ToString(hashed).Replace("-", "") to get a hex string for the MD5 hash? Then you could simply just use MD5(tmp) in JavaScript.

Categories

Resources