Skip to content Skip to sidebar Skip to footer

Hmac Sha256 In Python Vs. Javascript

I want to re-implement a certain API client, which is written in Python, in JavaScript. I fail to replicate the HMAC SHA256 signing function. For some keys the output is identical,

Solution 1:

The base64 encoded secret you are trying to give to CryptoJs does not represent a valid UTF-8 string, which CryptoJS requires. You can use this tool to check for validity. atob() is encoding agnostic and just converts byte by byte, and does not check if it's valid UTF-8.

Here I did the decoding of the base64 secret with CryptoJS's own decoder and it throws an error saying it's invalid UTF-8:

<scriptsrc="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.9-1/crypto-js.min.js"></script><scriptsrc="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.9-1/hmac-sha256.min.js"></script><scriptsrc="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.9-1/enc-base64.min.js"></script><script>functionsign_string(key_b64, to_sign) {
        var key = CryptoJS.enc.Base64.parse(key_b64).toString(CryptoJS.enc.Utf8);
        var hash = CryptoJS.HmacSHA256(to_sign, key);
        var hashInBase64 = CryptoJS.enc.Base64.stringify(hash);
        document.write(hashInBase64 + '<br>');
    }
    sign_string('VGhpcyBpcyBhIHByaW50YWJsZSBzdHJpbmcuCg==', "my message")
    sign_string('dGhlIHdpbmQgb2YgTXQuIEZ1amkK', "my message")
    sign_string('pkmNNJw3alrpIBi5t5Pxuym00M211oN86IhLZVT8', "my message")
</script>

I also found a way you can use raw bytes for the key. This works for the last key but not for the first two.

var key = CryptoJS.enc.Hex.parse(toHex(atob(key_b64)));

Now if you combine these two methods you can have a real solution. This final code gives identical output as python:

<scriptsrc="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.9-1/crypto-js.min.js"></script><scriptsrc="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.9-1/hmac-sha256.min.js"></script><scriptsrc="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.9-1/enc-base64.min.js"></script><script>functionsign_string(key_b64, to_sign) {
        try {
            var key = CryptoJS.enc.Base64.parse(key_b64).toString(CryptoJS.enc.Utf8);
        }
        catch {
            var key = CryptoJS.enc.Hex.parse(toHex(atob(key_b64)));
        }
        var hash = CryptoJS.HmacSHA256(to_sign, key);
        var hashInBase64 = CryptoJS.enc.Base64.stringify(hash);
        document.write(hashInBase64 + '<br>');
    }
    
    functiontoHex(str) {
        var result = '';
        for (var i=0; i<str.length; i++) {
          if (str.charCodeAt(i).toString(16).length === 1) {
            result += '0' + str.charCodeAt(i).toString(16);
          } else {
            result += str.charCodeAt(i).toString(16);
          }
        }
        return result;
    }

    sign_string('VGhpcyBpcyBhIHByaW50YWJsZSBzdHJpbmcuCg==', "my message")
    sign_string('dGhlIHdpbmQgb2YgTXQuIEZ1amkK', "my message")
    sign_string('pkmNNJw3alrpIBi5t5Pxuym00M211oN86IhLZVT8', "my message")
    sign_string('xTsHZGfWUmnIpSu+TaVraECU88O3j9qVjlwTWGb/C8k=', "my message")
</script>

Solution 2:

In the third example you are using different parameters in the python and JavaScript versions. In python: sign_string('xTsHZGfWUmnIpSu+TaVraECU88O3j9qVjlwTWGb/C8k=', "my message") In JavaScript: sign_string('pkmNNJw3alrpIBi5t5Pxuym00M211oN86IhLZVT8', "my message")

Post a Comment for "Hmac Sha256 In Python Vs. Javascript"