2

I'm wanting to use the built in browser crypto object instead of importing the crypto library in my browser project.

I want to not need this.

npm i crypto

The following code illustrates trying to sign a simple message using both libraries, however I get a different result when using the built in crypto object. The outputs are logged to console.

// START CRYPTO LIBRARY METHOD
import crypto from 'crypto';

const HMAC_SHA256_KEY = {
    API_KEY: '***',
    SECRET_KEY: '***'
};

const queryString = `timestamp=${(new Date().getTime())}`;

const signature = crypto
    .createHmac('sha256', HMAC_SHA256_KEY.SECRET_KEY)
    .update(queryString)
    .digest('hex')

console.log("standard encrypt", signature);

// START NATIVE LIBRARY METHOD    
const getUtf8Bytes = (str: string) => {
    return new Uint8Array(
        [...(unescape(encodeURIComponent(str)))].map(c => c.charCodeAt(0))
    );
};

// @ts-ignore
const builtInCrypto = window.crypto || window.msCrypto;
builtInCrypto.subtle.importKey(
    'raw',
    getUtf8Bytes(HMAC_SHA256_KEY.SECRET_KEY),
    {
        name: 'HMAC', hash: 'SHA-256'
    },
    true, ['sign']
).then(key => {
    builtInCrypto.subtle.sign(
        'HMAC',
        key,
        getUtf8Bytes(queryString))
        .then(signature => {
            console.log('builtIn Signature', btoa(String.fromCharCode(...(new Uint8Array(signature)))));
        })
})

Clearly I'm doing something wrong, but what? Why am I getting a different output for the native encryption?

Programming Guy
  • 7,259
  • 11
  • 50
  • 59

1 Answers1

2

For the same values of HMAC_SHA256_KEY.SECRET_KEY and queryString (the last parameter depends on time and therefore has a different value for each run) both scripts return the same HMac but in different encodings, resulting in different output. In the NodeJS / crypto code the HMac is hex encoded, in the JavaScript / Web Crypto API code Base64 encoded.

To make sure that the output is identical, the same encoding must be used in both scripts. Either the HMac in the JavaScript / Web Crypto API code must also be hex encoded, see e.g. here for a suitable method, or the HMac in the NodeJS / crypto code must be Base64 encoded (by passing 'base64' instead of 'hex' as argument of digest).

Topaco
  • 40,594
  • 4
  • 35
  • 62