【问题标题】:Python HMAC to CryptoJSPython HMAC 到 CryptoJS
【发布时间】:2018-01-24 19:28:10
【问题描述】:

我的问题与Translation from Python to JavaScript: HMAC-SHA256 非常相似,但该问题从未得到解答。

以下 Python 代码生成正确的哈希:

def sign_api_request(api_secret, api_key, method, url):
    encoded_url = urllib.parse.quote(url.lower(), '').lower()
    timestamp = int(time.time())print("timestamp: " + str(timestamp))
    nonce = str(uuid.uuid4())

    signature = api_key + method + encoded_url + str(timestamp) + nonce

    secret_bytes = base64.b64decode(api_secret)

    signature_bytes = signature.encode('UTF8')

    signature_hash = hmac.new(secret_bytes, signature_bytes, hashlib.sha256).digest()
    base64_signature_hash = base64.b64encode(signature_hash).decode()

    print(base64_signature_hash)

我正在尝试使用 Javascript(作为 Postman 预请求脚本)生成相同的哈希字符串。这是我得到的:

function epochTime() {
    var d = new Date();
    var t = d.getTime();
    var o = t + "";
    return o.substring(0, 10);
}

function newGuid() {
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { var r = Math.random() * 16 | 0, v = c == 'x' ? r : r & 0x3 | 0x8; return v.toString(16); });
}

var uri_path = encodeURIComponent(request.url.toLowerCase()).toLowerCase();
var payload = uri_path; //.toLowerCase();

timestamp = epochTime();
nonce = newGuid();
signature = environment.api_key + "GET" + payload + timestamp + nonce;

secret_bytes = atob(environment.api_secret);

var hash = CryptoJS.HmacSHA256(signature, secret_bytes);
var hashInBase64 = CryptoJS.enc.Base64.stringify(hash);
var sig = "amx " + environment.api_key + ":" + hashInBase64 + ":" + nonce + ":" + timestamp;
postman.setGlobalVariable("signature", sig);

如果我使用相同的 timestampnonce(通过显式设置而不是在运行时生成它们)和相同的 api_keyapi_secret(在调用中保持不变),我希望得到相同的结果sig (Javascript) 中的值,就像我在 base64_signature_hash (Python) 中所做的一样,但事实并非如此。

我知道这可能是编码问题,但我的 js-fu 很弱。有什么想法吗?

编辑添加:每个使用的methodurl 也是相同的。

【问题讨论】:

    标签: javascript python hmac cryptojs


    【解决方案1】:

    基本上,有两个问题。首先,在 Python 和 JS 代码中 secret_bytes 应该是 base64 编码的字符串。其次,在 JavaScript 代码中,secret_bytes 没有从 base64 字符串正确解码。请在下面找到更正后的 Python 和 JavaScript 示例。

    Python:

    import hmac
    import time
    import uuid
    import base64
    import hashlib
    import urllib.parse
    
    
    def sign_api_request(api_secret, api_key, method, url):
        encoded_url = urllib.parse.quote(url.lower(), '').lower()
        # timestamp = int(time.time())
        # nonce = str(uuid.uuid4())
        timestamp = str(1569158586);
        nonce = '708b7df1-7494-49fa-812c-e5f6c24aeab6'
    
        signature = api_key + method + encoded_url + timestamp + nonce
        # print(signature)
    
        secret_bytes = base64.standard_b64decode(api_secret)
        # print(secret_bytes)
    
        signature_bytes = signature.encode('UTF8')
    
        signature_hash = hmac.new(secret_bytes, signature_bytes, hashlib.sha256).digest()
        base64_signature_hash = base64.b64encode(signature_hash).decode()
        return base64_signature_hash 
    
    
    base64_signature_hash = sign_api_request('MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2Nzg=', '0987654321', 'POST', '/signin')
    print(base64_signature_hash)
    

    JavaScript:

    const CryptoJS = require('crypto-js');
    
    function epochTime() {
        var d = new Date();
        var t = d.getTime();
        var o = t + "";
        return o.substring(0, 10);
    }
    
    function newGuid() {
        return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { var r = Math.random() * 16 | 0, v = c == 'x' ? r : r & 0x3 | 0x8; return v.toString(16); });
    }
    
    let api_secret = 'MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2Nzg=';
    let api_key = '0987654321';
    let method = 'POST';
    let url_path = '/signin';
    
    let encoded_url = encodeURIComponent(url_path.toLowerCase()).toLowerCase();
    let timestamp = '1569158586';
    let nonce = '708b7df1-7494-49fa-812c-e5f6c24aeab6';
    
    let signature = api_key + method + encoded_url + timestamp + nonce;
    // console.log(signature);
    
    let secret_bytes = new Buffer.from(api_secret, 'base64');
    secret_bytes = secret_bytes.toString('ascii');
    // console.log(secret_bytes);
    
    let hash = CryptoJS.HmacSHA256(signature, secret_bytes);
    let hashInBase64 = CryptoJS.enc.Base64.stringify(hash);
    console.log(hashInBase64);
    

    两者的输出应该相同:

    1Hw92JPDJPFB3Je4MvwapODmn5S6KdIbvot3MAvg0jM=
    

    【讨论】:

      【解决方案2】:

      这是一个很好的python到javascript翻译

      python sign-api-request

      import hmac
      import base64
      import hashlib
      
      SECRET_KEY = 'b7566b7c87365a970e64109f92bb7415719cca1a0fea04c196f7ca7a45cc64b4'
      API_KEY = '/v1/users/me'
      
      def sign_api_request(api_secret=SECRET_KEY, api_key=API_KEY):
      
          signature_hash = hmac.new(api_secret.encode(), api_key.encode(),  hashlib.sha512).digest()
          base64_signature_hash = base64.b64encode(signature_hash).decode()
      
          return base64_signature_hash
      
      

      等于nodejs sign-api-request:

      const CryptoJS = require('crypto-js');
      
      
      SECRET_KEY = 'b7566b7c87365a970e64109f92bb7415719cca1a0fea04c196f7ca7a45cc64b4'
      API_KEY = '/v1/users/me'
      
      function sign_api_request(api_secret=SECRET_KEY, api_key=API_KEY) {
         return CryptoJS.enc.Base64.stringify(CryptoJS.HmacSHA512(api_key, api_secret));
      }
      
      console.log(sign_api_request())
      
      
      

      npm install crypto-js

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-07-29
        • 2017-12-29
        • 1970-01-01
        • 2012-08-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多