问题描述
我正在尝试使用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()
的key
和msg
参数都必须是bytes
对象.您正在为其提供一个str
对象,因为 urllib.parse.urlencode()
函数产生:
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:
因此,不仅您的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哈希错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!