Python HMAC: TypeError: la asignación de caracteres debe devolver entero, ninguno o unicode

Estoy teniendo un pequeño problema con HMAC. Al ejecutar este pedazo de código:

signature = hmac.new( key=secret_key, msg=string_to_sign, digestmod=sha1, ) 

Me sale un error extraño:

  File "/usr/local/Cellar/python/2.7.6/Frameworks/Python.framework/Versions/2.7/lib/python2.7/hmac.py", line 133, in new return HMAC(key, msg, digestmod) File "/usr/local/Cellar/python/2.7.6/Frameworks/Python.framework/Versions/2.7/lib/python2.7/hmac.py", line 72, in __init__ self.outer.update(key.translate(trans_5C)) TypeError: character mapping must return integer, None or unicode 

Cuando imprimo string_to_sign, es una cadena adecuada como esta:

 GET \n \n application/json \n \n \n 

¿Qué significa el error? ¿Es por nuevas líneas?

Como pregunté voy a publicar esto como una respuesta. El error al que te enfrentaste es una característica del HMAC de Python. No acepta unicode. Esta característica se describe aquí .

HMAC es una función que funciona a nivel de byte. Por esta razón en Python 3 solo acepta bytes . En Python 2 no tenemos bytes por lo que solo acepta str .

Asegúrese de que “clave” y “msg” sea una cadena de caracteres como:

s = hmac.new (str (secretkey), str (mensaje), digestmod = hashlib.sha1) .hexdigest ()

Como no quería escribir en nuestros documentos API que debería convertir la carga útil a ASCII o eliminar los caracteres Unicode antes de comparar resúmenes, he usado la siguiente solución:

 import hmac import hashlib def sign_request(self, secret, data): return hmac.new( key=bytearray(secret, 'utf-8'), msg=bytearray(data, 'utf-8'), digestmod=hashlib.sha256 ).hexdigest() 
  • bytearray convierte mi cadena Unicode en bytes usando la encoding utf-8 .
  • key y msg son parámetros de bytes (como lo hmac biblioteca hmac ).

En python 2

Si lo codificas como:

 from __future__ import unicode_literals import base64 import hashlib import hmac import time def gen_signature(key, strsome, expires=0): expires = int(time.time()) + 600 if expires == 0 else expires _2_signature = '%s\n%s\n' % (expires, strsome) # hmac.new(key, msg, digestmod) bytearray(secret, 'utf-8') signature = base64.b64encode(hmac.new(key, _2_signature, hashlib.sha1).digest()) return signature gen_signature('xxxxxxx', 'strsome') 

Obtienes un error como el que proporcionaste. Sin embargo, si usa bytearray(key, 'utf-8') en lugar de la variable de clave bruta y bytearray(_2_signature, 'utf-8') en lugar de la variable _2_signature, debería funcionar correctamente.

Por ejemplo:

 def gen_signature(key, strsome, expires=0): expires = int(time.time()) + 600 if expires == 0 else expires _2_signature = '%s\n%s\n' % (expires, strsome) # hmac.new(key, msg, digestmod) bytearray(secret, 'utf-8') signature = base64.b64encode(hmac.new(bytearray(key, 'utf-8'), bytearray(_2_signature, 'utf-8'), hashlib.sha1).digest()) return signature gen_signature('xxxxxxx', 'strsome')