cancel
Showing results for 
Search instead for 
Did you mean: 

HMAC-SHA512 comparing Problem in Nodejs

Hi Everyone

 

I am using webhook after finishing the transactions and getting a key "x-anet-signature" in the header from webhook then after trying to create a hash using text "^" + apiLogin + "^" + transId + "^" + amount + "^" as given in his doc.Please look into my below code and give me suggestions what mistake i made ?


function generateSHA512(textToHash, signatureKey) {

 
var sha512 = require('js-sha512');
if (textToHash != null && signatureKey != null) {
var sig = sha512.hmac(Buffer.from(signatureKey, 'hex'), textToHash).toUpperCase();
return sig;
} else {
return 0;
}
 
}

 

var apiLoginId = "xxxxxxxxxxxx";

var transId = "xxxxxxxxx";

var amount = 10;

var signatureKey = config.SIGNATURE_KEY;
var textToHash = "^" + apiLogin + "^" + transId + "^" + amount + "^"
var SHa512key = generateSHA512(textToHash, signatureKey);
 
SHa512key is not equal to "x-anet-signature".
 
 
also tried other core node js cryto library
// var hmac1 = crypto.createHmac("sha512", Uint8Array.from(Buffer.from(signatureKey)));
// var signed1 = hmac.update(textToHash).digest('hex');
// console.log("signed1",signed1)
// var hmac2 = crypto.createHmac("sha512", Uint8Array.from(Buffer.from(signatureKey, 'utf8')));
// var signed2 = hmac.update(textToHash).digest('hex');
// console.log("signed2",signed2)

but nothing works.Please help.
 

 

 

bitlume
Member
12 REPLIES 12
@bitlume

You are mixing and matching hash validation elements. Webhooks doesn’t use login etc. you use the json payload. I just helped another developer on the thread below this one. Read that I said there about using the test button to test your hash.
Renaissance
All Star

Hi Renaissance,

 

Response came from webhook.

 

 Authorize .net callback body:
{ notificationId: 'xxx',
eventType: 'xxx',
eventDate: 'xxx',
webhookId: 'xxx',

payload:
{ responseCode: 1,
authCode: 'T05SXH',
avsResponse: 'Y',
authAmount: 80,
entityName: 'transaction',
id: '60125874223' } }

Authorize .net callback header: EECDA210427E8FF17FFE8FF45E58DFCC542DEEF92D1156F3943C42FF7AFFFB5DA310E7476474490B6833B0271438BA20C699FFC105FBA7422D732B797A38C734
 
So according to you, this text has to be hashed:

'^1^T05SXH^Y^80^transaction^60125874223^'


I tried hashing with same function shown in original post but it did not work - it got a different hash value. 

 

I then tried converting responseCode and amount to string, since they are not strings in the payload - both got the same hashcode as before (so javascript is implicitly converting to string).

Let me know if you see anything wrong with the text to hash or the method to generate the hash..

bitlume
Member
@bitlume

Nope. According to me you hash the entire body. You do not construct a string. So Anet hits your endpoint with an http request. You capture the entire body of the request and hash it just like it is. I have led you astray by calling it the json payload. I was referring to the content type, not the payload component of the body of the request.

Thanks for clarifying. But I still don't know how to continue.

 

You said the same as the docs for Authorize.net - Just use the body as-is and hash it. But what method should we use to hash it as-is, as an object? Our method(s) only work on text strings, as in the authorize.net sample code for SHA512 (in sample-code-node/Sha512/compute_trans_hashSHA2.js ). When I tried using body as-is, it failed with error (input is invalid type).

 

Since that sample code doesn't apply to webhooks, and we have to do exactly the same hashing as authorize.net does, I need to see some sample code for hashing, in webhooks, in node.js...

 

Thanks for your patience. 

@bitlume

How are you capturing the body? Can you post your entire endpoint script? I do not have sample code for js.

Hi

 

 

Here is my webhook endpoint in nodejs

 

app.post('/auth/payment/authorizenet/callback', function (req, res) {
console.log("AUthorize .net callback body", req.body );
var payload = req.body.payload;
var hashKey = req.headers['x-anet-signature'];
hashKey = hashKey.substring(7, hashKey.length)
console.log("AUthorize .net callback headers", hashKey);
if(payload && hashKey){
var apiLogin = config.API_LOGIN_KEY;
var transId = payload.id;
var amount = payload.authAmount;
var signatureKey = config.SIGNATURE_KEY
console.log("amount",typeof amount , amount.toString() ,typeof amount.toString())
var textToHash = "^" + apiLogin + "^" + transId + "^" + amount + "^";
/*textToHash = `^${payload.responseCode}^${payload.authCode}^${payload.avsResponse}^${payload.authAmount}^${payload.entityName}^${payload.id}^`;*/
console.log("signatureKey",signatureKey)
console.log("textToHash",textToHash)
var SHa512key = encryption.generateSHA512(textToHash, signatureKey);
if(SHa512key === hashKey){
console.log("Computed SHA512 Hash: " + SHa512key + "\n");
payment.getTransactionDetails(payload.id, async function (response) {
try {
let transactionDetails = response.getTransaction();
console.log(transactionDetails)
let orderDetails = transactionDetails.order;
let customerDetails = transactionDetails.customer;
let { invoiceNumber, description } = orderDetails;
let { id, email } = customerDetails;
//let query = { name: invoiceNumber };
let query = { _id: mongoose.Types.ObjectId(description) };
let pSubscriptionPackages = await pSubscriptionPackageModel.findOne(query);
let userInfo = await User.findOne({ username: email });
transactionDetails.order = orderDetails;
transactionDetails.customer = customerDetails;
let pTransactionsResut = await pTransactions.create(transactionDetails);
var subscriptionObj = {
subscriptionPackageId: pSubscriptionPackages._id,
userId: userInfo._id,
partnerTransactionId: pTransactionsResut._id
};
console.log("subscriptionObj", subscriptionObj)
await pSubscriptionModel.create(subscriptionObj)
res.status(200).send();
} catch (err) {
console.log("Error in autherize webhook", err);
res.status(400).send();
}
});
}else{
console.log("Either Signature key or the text to hash is empty \n");
res.status(400).send();
}
}else{
console.log("Hash key not available in headers.");
res.status(400).send();
}
});
 
generate hash function in other file
 
exports.generateSHA512 = function (textToHash, signatureKey) {
if (textToHash != null && signatureKey != null) {
var sig = sha512.hmac(Buffer.from(signatureKey, 'hex'), textToHash).toUpperCase();
return sig;
} else {
return 0;
}
}

 

@bitlume

I’m not very good with server side js, but this is useful. So what you would hash here would be req.body. I do all of my server side stuff in php, and in my application if I remember right setting the content type to json was needed to make my app work. This is accomplished in PHP through either capturing all headers (or just the content type header) sent by auth.net or by setting your own content type header.

What I would suggest you do is generate a brand new signature key, just to eliminate that as a possible source of your problem. Then I would run a request and capture the body and the signature header and log them. Then I would cease running test transactions for a bit and instead just use the body and run your hash function several times and try to match. Use what you log from that one request.

I can tell you for certain that using any sort of concatenated string will never work. You hash the body for sure. It may be that you stringify it. Another difference is that you do not convert the signature key to a binary or byte array.

I am extremely busy right now, but if you want post a request body, your sandbox signature key, and the hash returned in the header. You can IM me the sk if you don’t want everyone to see it. When I have time to kill I’ll mess around with it and see what I can do.

AUthorize .net callback body

 

{

notificationId: '4919527c-fdcc-4b22-9ca9-022e4800f4c8',
eventType: 'net.authorize.payment.authcapture.created',
eventDate: '2019-09-04T16:46:28.7407067Z',
webhookId: 'a92b9535-f456-4cc6-8b13-30d2a15296ba',
payload:
 {

    responseCode: 1,
    authCode: 'W4DC4O',
    avsResponse: 'Y',
    authAmount: 30,
    entityName: 'transaction',
    id: '60126807698'

 }

}

 

AUthorize .net callback headers

 

{

'content-type': 'application/json',
'x-anet-signature': 'sha512=8547F08392F112D5FAA9025FC51C3C5C1294AF1C6264CAABCC924B23E62F6F8D57BEF05F755745058A8649DAAA402164DE5C3816E397AC5426015C5E4681C0F2',
host: 'bitlume.com:4443',
connection: 'close',
'transfer-encoding': 'chunked'

}

 

Singnature kEY:

 

EF20F659DE690B6F9B5ED9D4F1C25D1A0BFC3E7B1755D35344B3563E641B0A55ECA70205CDFB2CD26E4C5424C8646DD58E67CDE9FC099510F0147DA2F7D825E8

@bitlume 

 

That body looks like it has been formatted.  Run another request and capture the complete body in a log file and post what is on the log file here. The headers can be formatted any way you wish, but the body having those extra spaces and line breaks will throw off your hash.