The CreatorCon Call for Content is officially open! Get started here.

SHA256 encode data with key

Travis_C
Giga Contributor

I have an API I'm attempting to call from ServiceNow, but I am running into issues with the SHA256 encoded data. In the request to the API, the Authentication header contains SHA256 encoded that is then converted to base64. The API documentation has an example for Node.js of how to get this to work, but it uses Crypto-JS. Crypto-JS is not included in ServiceNow and I could add it in if needed, but I would prefer to use to use something else that is already built into ServiceNow. 

 

Node.js

var crypto = require("crypto");
var hex = crypto.createHmac("sha256", apiKey).update(data).digest("hex");
var signature = new Buffer(hex).toString('base64');

python

signature = base64.b64encode(hmac.new(apiKey.encode(),msg=data.encode(),digestmod=hashlib.sha256).hexdigest().encode())

Is there a way to SHA256 encode a message with a specific key and then base64 encode the output in ServiceNow? Or do I need to add Crypto-JS to ServiceNow?

1 ACCEPTED SOLUTION

Travis_C
Giga Contributor

Just a follow up on this. I was able to get this working by:

  • Created a new app for CryptoJS to be created in. This was required to get it working due to scoping.
  • Created script include for CryptoJS using the instructions provided in the video Crypto-JS into ServiceNow
  • Created a system property to store the apiKey in as a password.

At this point, you can call the function HmacSHA256 from the script include CryptoJS in the application NodeJS with an application scope of x_fise_nodejs. Example below:

  • var sig = (x_fise_nodejs.CryptoJS.HmacSHA256(requestVars, apiKey));

My specific use case also required base64 encoding, which can be completed with by using GlideStringUil.base64Encode. Example below:

  • var signature = GlideStringUtil.base64Encode(sig);

With this complete, signature and some other information was stored in a variable authSig input into an HTTP Auth header and using a RestMessage to send the API. RestMessagev2 documentation is here.

View solution in original post

16 REPLIES 16

tantony
Mega Guru

Looking for an easier route, tried GlideCertificateEncryption and found a matching result with your python code: 

Python script:

>>> import hmac
>>> import hashlib
>>> import base64
>>> data = "data_to_process"
>>> secret = "my_secret"
>>> signature = base64.b64encode( hmac.new(secret.encode(), data.encode(), hashlib.sha256).digest())
>>> signature.decode()
'IxrAav9TMkECoI3chUWyy4EfTzouEHTKQBiAsTvoMzo='

 

Servicenow background script:

var secret = "my_secret";
secret = encodeURIComponent(secret);
secret = GlideStringUtil.base64Encode(secret);
var data = "data_to_process";
data = encodeURIComponent(data);
var mac = new GlideCertificateEncryption;
signature = mac.generateMac(secret, "HmacSHA256",data );
gs.print(signature);

Output:
*** Script: IxrAav9TMkECoI3chUWyy4EfTzouEHTKQBiAsTvoMzo=

 

 

Hi @tantony 

Found your GlideCertificate Encryption way useful, thanks.  I have a similar conversion from Python that I'm trying to do but not having much luck, was wondering if you wouldn't mind taking a look please?

Python code which gives the expected output:

key = "key"
msg = "message"
hmac = hmac.new(key.encode(),msg.encode(),digestmod=hashlib.sha256).hexdigest()
signature = base64.b64encode(hmac.encode())

The signature this outputs is:

HEX

6e9ef29b75fffc5b7abae527d58fdadb2fe42e7219011976917343065f58ed4a

B64

NmU5ZWYyOWI3NWZmZmM1YjdhYmFlNTI3ZDU4ZmRhZGIyZmU0MmU3MjE5MDExOTc2OTE3MzQzMDY1ZjU4ZWQ0YQ==

 

ServiceNow code which does not give the expected output:

var key = "key";
var message = "message";

key = encodeURIComponent(key);
message = encodeURIComponent(message);

var encryption = new GlideCertificateEncryption;
var digest = new GlideDigest();

var mac = encryption.generateMac(key, "HmacSHA256", message);
var hex = digest.getSHA256Hex(mac);
var b64 = GlideStringUtil.base64Encode(hex);

HEX

AA197A43BDB253F1A3E91A3E26383A9EB4D826715CF999DA93A4EA3E7DF459F2

B64

QUExOTdBNDNCREIyNTNGMUEzRTkxQTNFMjYzODNBOUVCNEQ4MjY3MTVDRjk5OURBOTNBNEVBM0U3REY0NTlGMg==

 

Any help would be much appreciated.  (I hate HMAC stuff, LOL.)

Regards.

 

I am not an expert in this but I believe the python code should use digest() instead of hexdigest() if you are using base64Encode() after. I think the RFC requirement is base64 or hexadecimal data.

 

Figured out how to get the same results as Python using the native GlideCertificateEncryption and a bit of hex conversion:

var HexUtil = 
{
  convertByteArrayToHex : function(byteArray)
  {
    var hex = "";

    byteArray.forEach(function(byteValue) { hex += HexUtil.convertByteToHex(byteValue); });

    return hex;  
  },

  convertByteToHex : function(b) 
  {
    var hexChar = ["0", "1", "2", "3", "4", "5", "6", "7","8", "9", "a", "b", "c", "d", "e", "f"];
  
    return hexChar[(b >> 4) & 0x0f] + hexChar[b & 0x0f];
  }
};

var key = "key";
key = encodeURIComponent(key);
key = GlideStringUtil.base64Encode(key);

var msg = "message";
msg = encodeURIComponent(msg);

var mac = new GlideCertificateEncryption();
signature = mac.generateMac(key, "HmacSHA256", msg);
gs.print(signature);

// Yes! bp7ym3X//Ft6uuUn1Y/a2y/kLnIZARl2kXNDBl9Y7Uo=

var bytes = GlideStringUtil.base64DecodeAsBytes(signature);
gs.print(JSON.stringify(bytes));
gs.print(bytes.length);

// Yes! [110,-98,-14,-101,117,-1,-4,91,122,-70,-27,39,-43,-113,-38,-37,47,-28,46,114,25,1,25,118,-111,115,67,6,95,88,-19,74]

var hex = HexUtil.convertByteArrayToHex(bytes);
gs.print(hex);

// Yes! 6e9ef29b75fffc5b7abae527d58fdadb2fe42e7219011976917343065f58ed4a

var hexB64 = GlideStringUtil.base64Encode(hex);
gs.print(hexB64);

// Yes! NmU5ZWYyOWI3NWZmZmM1YjdhYmFlNTI3ZDU4ZmRhZGIyZmU0MmU3MjE5MDExOTc2OTE3MzQzMDY1ZjU4ZWQ0YQ==

tantony
Mega Guru

Thanks for sharing.This will be helpful to community. Here in the community I could find only answers  using CryptoJS