Python 3.5中的Hmac哈希错误 [英] Hmac Hashing Error in Python 3.5

查看:94
本文介绍了Python 3.5中的Hmac哈希错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用hmac哈希API机密.但是我无法在Python 3.5上使用它.

I'm trying to hash an API secret using hmac. But I can't get it to work using Python 3.5.

这是问题代码:

sign = hmac.new(self.Secret, post_data, hashlib.sha512).hexdigest()

这是错误:

TypeError: key: expected bytes or bytearray, but got 'str'

我已经尝试过像这样先编码...

I've tried encoding first like so...

secret = b'api_secret_here'

也尝试过...

sign = hmac.new(self.Secret.encode('utf-8'), post_data, hashlib.sha512).hexdigest()

和...

sign = hmac.new(self.Secret.encode(), post_data, hashlib.sha512).hexdigest()


所有人都给出错误:

TypeError: Unicode-objects must be encoded before hashing

以下是完整上下文中的代码:

Here's the code in full context:

import hashlib
import hmac
import json
import sys
import time
from datetime import datetime

# Tested on Python 2.7.6 & 3.4.3
if sys.version_info[0] == 3:
    from urllib.request import Request, urlopen
    from urllib.parse import urlencode
else:
    from urllib2 import Request, urlopen
    from urllib import urlencode

minute = 60
hour = minute * 60
day = hour * 24
week = day * 7
month = day * 30
year = day * 365

# Possible Commands
PUBLIC_COMMANDS = ['returnTicker', 'return24hVolume', 'returnOrderBook', 'returnTradeHistory', 'returnChartData',
                   'returnCurrencies', 'returnLoanOrders']
PRIVATE_COMMANDS = ['returnBalances', 'returnCompleteBalances', 'returnDepositAddresses', 'generateNewAddress',
                    'returnDepositsWithdrawals', 'returnOpenOrders', 'returnTradeHistory',
                    'returnAvailableAccountBalances', 'returnTradableBalances', 'returnOpenLoanOffers',
                    'returnActiveLoans', 'createLoanOffer', 'cancelLoanOffer', 'toggleAutoRenew', 'buy', 'sell',
                    'cancelOrder', 'moveOrder', 'withdraw', 'transferBalance', 'returnMarginAccountSummary',
                    'marginBuy', 'marginSell', 'getMarginPosition', 'closeMarginPosition']


class Poloniex:
    def __init__(self, APIKey='', Secret=''):
        self.APIKey = APIKey
        self.Secret = Secret
        # Conversions
        self.timestamp_str = lambda timestamp=time.time(), format="%Y-%m-%d %H:%M:%S": datetime.fromtimestamp(
            timestamp).strftime(format)
        self.str_timestamp = lambda datestr=self.timestamp_str(), format="%Y-%m-%d %H:%M:%S": int(
            time.mktime(time.strptime(datestr, format)))
        self.float_roundPercent = lambda floatN, decimalP=2: str(round(float(floatN) * 100, decimalP)) + "%"

        # PUBLIC COMMANDS
        self.marketTicker = lambda x=0: self.api('returnTicker')
        self.marketVolume = lambda x=0: self.api('return24hVolume')
        self.marketStatus = lambda x=0: self.api('returnCurrencies')
        self.marketLoans = lambda coin: self.api('returnLoanOrders', {'currency': coin})
        self.marketOrders = lambda pair='all': self.api('returnOrderBook', {'currencyPair': pair})
        self.marketChart = lambda pair, period=day, start=time.time() - (month * 2), end=time.time(): self.api(
            'returnChartData', {'currencyPair': pair, 'period': period, 'start': start, 'end': end})
        self.marketTradeHist = lambda pair: self.api('returnTradeHistory',
                                                     {'currencyPair': pair})  # NEEDS TO BE FIXED ON Poloniex

        # PRIVATE COMMANDS
        # self.myTradeHist = lambda pair: self.api('returnTradeHistory',{'currencyPair':pair})
        self.myAvailBalances = lambda x=0: self.api('returnAvailableAccountBalances')
        self.myMarginAccountSummary = lambda x=0: self.api('returnMarginAccountSummary')
        self.myMarginPosition = lambda pair='all': self.api('getMarginPosition', {'currencyPair': pair})
        self.myCompleteBalances = lambda x=0: self.api('returnCompleteBalances')
        self.myAddresses = lambda x=0: self.api('returnDepositAddresses')
        self.myOrders = lambda pair='all': self.api('returnOpenOrders', {'currencyPair': pair})
        self.myDepositsWithdraws = lambda x=0: self.api('returnDepositsWithdrawals')
        self.myTradeableBalances = lambda x=0: self.api('returnTradableBalances')
        self.myActiveLoans = lambda x=0: self.api('returnActiveLoans')
        self.myOpenLoanOrders = lambda x=0: self.api('returnOpenLoanOffers')
        ## Trading functions ##
        self.createLoanOrder = lambda coin, amount, rate: self.api('createLoanOffer',
                                                                   {'currency': coin, 'amount': amount, 'duration': 2,
                                                                    'autoRenew': 0, 'lendingRate': rate})
        self.cancelLoanOrder = lambda orderId: self.api('cancelLoanOffer', {'orderNumber': orderId})
        self.toggleAutoRenew = lambda orderId: self.api('toggleAutoRenew', {'orderNumber': orderId})
        self.closeMarginPosition = lambda pair: self.api('closeMarginPosition', {'currencyPair': pair})
        self.marginBuy = lambda pair, rate, amount, lendingRate=2: self.api('marginBuy',
                                                                            {'currencyPair': pair, 'rate': rate,
                                                                             'amount': amount,
                                                                             'lendingRate': lendingRate})
        self.marginSell = lambda pair, rate, amount, lendingRate=2: self.api('marginSell',
                                                                             {'currencyPair': pair, 'rate': rate,
                                                                              'amount': amount,
                                                                              'lendingRate': lendingRate})
        self.buy = lambda pair, rate, amount: self.api('buy', {'currencyPair': pair, 'rate': rate, 'amount': amount})
        self.sell = lambda pair, rate, amount: self.api('sell', {'currencyPair': pair, 'rate': rate, 'amount': amount})
        self.cancelOrder = lambda orderId: self.api('cancelOrder', {'orderNumber': orderId})
        self.moveOrder = lambda orderId, rate, amount: self.api('moveOrder', {'orderNumber': orderId, 'rate': rate,
                                                                              'amount': amount})
        self.withdraw = lambda coin, amount, address: self.api('withdraw',
                                                               {'currency': coin, 'amount': amount, 'address': address})
        self.transferBalance = lambda coin, amount, fromac, toac: self.api('transferBalance',
                                                                           {'currency': coin, 'amount': amount,
                                                                            'fromAccount': fromac, 'toAccount': toac})

    #####################
    # Main Api Function #
    #####################
    def api(self, command, args={}):
        """
        returns 'False' if invalid command or if no APIKey or Secret is specified (if command is "private")
        returns {"error":"<error message>"} if API error
        """
        args['command'] = command
        if command in PRIVATE_COMMANDS:
            if len(self.APIKey) < 2 or len(self.Secret) < 2:
                print("An APIKey and Secret is needed!")
                return False
            url, args['nonce'] = ['https://poloniex.com/tradingApi', int(time.time() * 42)]
            post_data = urlencode(args)
            sign = hmac.new(self.Secret, post_data, hashlib.sha512).hexdigest()
            headers = {'Sign': sign, 'Key': self.APIKey}
            ret = urlopen(Request(url, post_data, headers))
            return json.loads(ret.read().decode(encoding='UTF-8'))
        elif command in PUBLIC_COMMANDS:
            url = 'https://poloniex.com/public?'
            if not args:
                ret = urlopen(Request(url + command))
                return json.loads(ret.read().decode(encoding='UTF-8'))
            else:
                ret = urlopen(Request(url + urlencode(args)))
                return json.loads(ret.read().decode(encoding='UTF-8'))
        else:
            return False

推荐答案

hmac.new()keymsg参数都必须是bytes对象.您正在为其提供一个str对象,因为

Both the key and msg arguments to hmac.new() must be bytes objects. You are feeding it a str object, as that is what the urllib.parse.urlencode() function produces:

[...] 转换为百分比编码的ASCII文本字符串.如果将结果字符串用作通过urlopen()函数进行POST操作的数据,则应将其编码为字节,否则将导致TypeError.

Convert [...] to a percent-encoded ASCII text string. If the resultant string is to be used as a data for POST operation with the urlopen() function, then it should be encoded to bytes, otherwise it would result in a TypeError.

因此,不仅您的self.Secret是字节,还需要对post_data元素进行编码,甚至还要进行编码,因为您将其传递给urlopen()进行POST操作:

So not only should your self.Secret be bytes, you need to encode the post_data element too, even more so since you'll be passing it to urlopen() for a POST operation:

post_data = urlencode(args).encode('ASCII')
sign = hmac.new(self.Secret, post_data, hashlib.sha512).hexdigest()
headers = {'Sign': sign, 'Key': self.APIKey}
ret = urlopen(Request(url, post_data, headers))

这篇关于Python 3.5中的Hmac哈希错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆