Issue creating password digest for Amadeus SOAP API - node.js

I followed the instructions in the docs and tried to do the same formula in Node, however, I'm not able to correctly authenticate with the server as I receive an 11|Session| response. I assume that error is in response to incorrectly set nonce and/or password digest.
The formula: Base64(SHA1($NONCE + $TIMESTAMP + SHA1($CLEARPASSWORD)))
The variables: $CLEARPASSWORD=AMADEUS, $TIMESTAMP=2015-09-30T14:12:15Z, $NONCE=c2VjcmV0bm9uY2UxMDExMQ==.
The expected hash: +LzcaRc+ndGAcZIXmq/N7xGes+k=
The code I tried was:
const crypto = require('crypto')
const hashedPassword = crypto.createHash('sha1').update(CLEARPASSWORD).digest() // Returns a buffer
crypto.createHash('sha1').update(NONCE + TIMESTAMP + hashedPassword).digest('base64') // Returns a Base64 String
However, this returns DDcZEaS5AtoVaZhsARy9MqV+Y34=. And if I change the nonce to its plain string secretnonce10111, then I get gHOoqyDb9YJBrk30iabSO8nKxio= which still isn't correct.
I'm not sure what could be the issue.

I finally figured out what was wrong. The problem was I was trying to concatenate a string with a Buffer, when I should have just made everything a buffer from the start.
So, instead of
const hashedPassword = crypto.createHash('sha1').update(CLEARPASSWORD).digest()
crypto.createHash('sha1').update(NONCE + TIMESTAMP + hashedPassword).digest('base64')
It should have been
const buffer = Buffer.concat([Buffer.from(NONCE), Buffer.from(TIMESTAMP), nodeCrypto.createHash('sha1').update(CLEARPASSWORD).digest()])
const hashedPassword = nodeCrypto.createHash("sha1").update(buffer).digest("base64")

you can use this php code to generate Digest Password
<?php
date_default_timezone_set('UTC');
$t = microtime(true);
$micro = sprintf("%03d",($t - floor($t)) * 1000);
$date = new DateTime( date('Y-m-d H:i:s.'.$micro) );
echo $timestamp = $date->format("Y-m-d\TH:i:s").$micro . 'Z';
$nonce = mt_rand(10000000, 99999999);
echo $nounce = base64_encode($nonce);//we have to decode the nonce and then apply the formula on it and in xml we have to send the encoded nonce
$password = "AMADEUS"; //clear password
echo $passSHA = base64_encode(sha1($nonce . $timestamp . sha1($password, true), true));
?>

Related

How do I form an SAS token for Microsoft Azure API Management's REST API in Node.js?

I am using Microsoft Azure API Management service and want to use the REST API service. In creating my SAS token, which is needed otherwise the API call doesn't authorize, I'm having difficulty forming a proper token. Microsoft's webpage about this SAS token for API Management only shows an example in C#. I want to know how to form an SAS token in Node.js, which is not shown. Below is my code that was working last week, but is not now for some unknown reason. The error I get is: 401 Authorization error, token invalid
If someone can help me formulate this token, I would appreciate it.
This is Microsoft's webpage regarding this authentication token: https://learn.microsoft.com/en-us/rest/api/apimanagement/apimanagementrest/azure-api-management-rest-api-authentication
Here's my code:
const crypto = require('crypto');
const util = require('util');
const sign = () => {
const id = ${process.env.id}
const key = `${process.env.SASKey}`;
const date = new Date();
const newDate = new Date(date.setTime(date.getTime() + 8 * 86400000));
const expiry = `${newDate.getFullYear()}${
newDate.getMonth() < 10
? '' + newDate.getMonth() + 1
: newDate.getMonth() + 1
}${newDate.getDate()}${newDate.getHours()}${
newDate.getMinutes() < 10
? '0' + newDate.getMinutes()
: newDate.getMinutes()
}`;
const dataToSignString = '%s\n%s';
const dataToSign = util.format(dataToSignString, ${id}, expiry);
const hash = crypto
.createHmac('sha512', key)
.update(dataToSign)
.digest('base64');
const encodedToken = `SharedAccessSignature ${id}&${expiry}&${hash}`;
console.log(encodedToken);
return encodedToken;
};
Try the code:
protected getAPIManagementSAS(){
let utf8 = require("utf8")
let crypto= require("crypto")
let identifier = process.env.API_IDENTIFIER;
let key = process.env.API_KEY;
var now = new Date;
var utcDate = new Date(now.getUTCFullYear(),now.getUTCMonth(), now.getUTCDate() , now.getUTCHours(), now.getUTCMinutes(), now.getUTCSeconds(), now.getUTCMilliseconds());
let expiry = addMinutes(utcDate,1,"yyyy-MM-ddThh:mm:ss") + '.0000000Z'
var dataToSign = identifier + "\n" + expiry;
var signatureUTF8 = utf8.encode(key);
var signature = crypto.createHmac('sha512', signatureUTF8).update(dataToSign).digest('base64');
var encodedToken = `SharedAccessSignature uid=${identifier}&ex=${expiry}&sn=${signature}`;
return encodedToken
}
For more information, see here.
After a million tries, it seems like the only format acceptable right now is:
SharedAccessSignature uid=${identifier}&ex=${expiry}&sn=${signature}
If you are using the other format that has the "integration" parameter, that's a hit or a miss, mostly miss though. Set the uid as "integration" if that's your identifier and follow the above format as it works.

Build hmac sha256 hashing algorithm in node.js

I am using Bold Commerce Webhooks to subscribe to subscription events in my store. They give documentation about how their request signatures are generated in PHP:
$now = time(); // current unix timestamp
$json = json_encode($payload, JSON_FORCE_OBJECT);
$signature = hash_hmac('sha256', $now.'.'.$json, $signingKey);
I'm trying to recreate the hash on my side in node.js. From my research I've figured out the following so far, which I believe is pretty close, but doesn't match yet:
const hash = request.header("X-Bold-Signature")!;
const SECRET = "my-secret-api-key";
const body = request.body;
const time = request.header("timestamp")!;
const mySignature = crypto.createHmac('sha256', SECRET).update(time + '.' + body).digest("hex");
if (mySignature !== request.header("X-Bold-Signature")!) {
//...
}
I've also tried using JSON.stringify(body) which changes the hash but still doesn't match.
It matched with this code.
const hash = crypto
.createHmac('sha256', secretKey)
.update(timestamp + '.' + JSON.stringify(body))
.digest('hex');
Note that unlike shopify, do not use rawbody.

In MongoUri how can I handle # in my password?

My Mongo Uri is like this. There must be an # at the end of my password. And Mongo throws an error called= Unescaped at-sign in authority section. Is there a way to make it work?
const url = 'mongodb://roots:something##localhost:27017?authMechanism=DEFAULT&authSource=db';
you can also encode your string using template literals like this:
const DB_USER = 'roots';
const PASSWORD = encodeURIComponent('something#');
const DB_URL = mongodb://${DB_USER}:${PASSWORD}#localhost:27017?authMechanism=DEFAULT&authSource=db';
in my opinion it is also more easy to read
hope it helps =)
Try encoding your user and password with this:
function percentEncode(string) {
let encoded = '';
string.split('').forEach(function(char) {
encoded += '%' + char.charCodeAt(0).toString(16).toUpperCase();
});
return encoded;
}
https://www.rfc-editor.org/rfc/rfc3986#section-2.1
Here's where I got the idea from: https://github.com/strongloop/loopback-connector-mongodb/issues/499
Good Luck =)
You can use URL encoding ,the default ASCII code for # is %40. See link here
const url = 'mongodb://roots:something%40#localhost:27017?authMechanism=DEFAULT&authSource=db';

define hash cod SHA256 NodeJS

How to select the hash code on NodeJS?
I have a system made in another language with passwords on SHA256
The function there is:
#define HASH_CODE = 'WEASDSAEWEWAEAWEAWEWA';
SHA256_PassHash(HASH_CODE, password, 64);
First, param is the hash code, second is the var will be encrypted, third is the base64
I made the encrypt on NodeJS, but I have no control on hash code, so the systems don't make the same hash, how to select the code on the register on NodeJS so the system communicates with others?
const code = 'WEASDSAEWEWAEAWEAWEWA';
const normal = 'anne';
const crypto = require('crypto');
const encrypted = crypto
.createHash('sha256')
.update(normal)
.digest('base64');
console.log(encrypted);
A exemple of compatibly code, this login on PHP
login.php
<?php require_once('../mysql_conn.php'); ?>
<?php
session_start();
$HASH_SENHA = 'WEASDSAEWEWAEAWEAWEWA';
if(isset($_SESSION['Username']))
{
header("location: ../myaccount.php");
exit();
}
if(isset($_POST['usr']) && isset($_POST['psw']) && isset($_POST['botao']))
{
$usuario = mysqli_real_escape_string($MYSQL_CONNECT, $_POST['usr']);
$senha = strtoupper(hash("sha256", $_POST['psw'] . $HASH_SENHA));
$query = mysqli_query($MYSQL_CONNECT, "SELECT * FROM accounts WHERE Username='$usuario' AND Senha='$senha' LIMIT 1");
if(mysqli_num_rows($query) < 1)
{
echo "<script type=\"text/javascript\">
alert('Incorrect Username or Password.');
window.location = '../login.php';
</script>";
exit();
}
else
{
//login efetuado
$dados = mysqli_fetch_assoc($query);
if (isset($_SESSION['loc'])) {
header("location:".$_SESSION['loc']);
}
else header("location:../index.php");
}
}
?>
By looking at the PHP code you've provided.
hash("sha256", $_POST['psw'] . $HASH_SENHA)
It's hashing the string concatenation of $_POST['psw'] and $HASH_SENHA
So, the equivalent code in Node.js should look like below
Node.js
const crypto = require('crypto');
const code = 'WEASDSAEWEWAEAWEAWEWA';
const input = 'password 123';
const encrypted = crypto
.createHash('sha256')
.update(input + code) // concatenation
.digest('hex'); // get hash in hex format
console.log(encrypted);
Output
3b3107f01da624da6bb014abe532aa7416869811ebe321784b26770cd2dd74ff

Cannot reproduce sha512 hmac from PHP in node.js

I have some PHP code that produces a hmac as follows:
<?php
$secret = "7pgj8Dm6";
$message = "Test\0Message";
echo base64_encode(hash_hmac('sha512', $message, base64_decode($secret), true))."\n";
echo "69H45OZkKcmR9LOszbajUUPGkGT8IqasGPAWqW/1stGC2Mex2qhIB6aDbuoy7eGfMsaZiU8Y0lO mQxlsWNPrw==\n";
?>
When I try to produce similar code in node.js, I get a different base64 encoded result than I'd like to have, and I can't figure out why.
var hmac = function(msg, secret){
var s = (new Buffer(secret, 'base64')).toString('utf8');
var hmac = require('crypto').createHmac('sha512',s);
hmac.update(msg);
return hmac.digest('base64');
};
var secret = "7pgj8Dm6";
var message = "Test\0Message";
var wanted = "69H45OZkKcmR9LOszbajUUPGkGT8IqasGPAWqW/1stGC2Mex2qhIB6aDbuoy7eGfMsaZiU8Y0lO3mQxlsWNPrw==";
var got = hmac(message, secret);
if(wanted === got){
console.log('All is fine.');
}else{
console.log('Hash is wrong :(');
}
console.log('wanted:\t'+wanted);
console.log('got:\t'+got);
My motivation for this is the anxpro api, with which I'd like to play a bit.
Ok, I figured it out. The problem was that I was calling toString on the Buffer created in the hmac function. When I remove that, everything works fine.
var hmac = function(msg, secret){
var s = new Buffer(secret, 'base64');
var hmac = require('crypto').createHmac('sha512',s);
hmac.update(msg);
return hmac.digest('base64');
};

Resources