kopia lustrzana https://github.com/micropython/micropython-lib
88 wiersze
2.8 KiB
Python
88 wiersze
2.8 KiB
Python
# Implements the hmac module from the Python standard library.
|
|
|
|
|
|
class HMAC:
|
|
def __init__(self, key, msg=None, digestmod=None):
|
|
if not isinstance(key, (bytes, bytearray)):
|
|
raise TypeError("key: expected bytes/bytearray")
|
|
|
|
import hashlib
|
|
|
|
if digestmod is None:
|
|
# TODO: Default hash algorithm is now deprecated.
|
|
digestmod = hashlib.md5
|
|
|
|
if callable(digestmod):
|
|
# A hashlib constructor returning a new hash object.
|
|
make_hash = digestmod # A
|
|
elif isinstance(digestmod, str):
|
|
# A hash name suitable for hashlib.new().
|
|
make_hash = lambda d=b"": hashlib.new(digestmod, d) # B
|
|
else:
|
|
# A module supporting PEP 247.
|
|
make_hash = digestmod.new # C
|
|
|
|
self._outer = make_hash()
|
|
self._inner = make_hash()
|
|
|
|
self.digest_size = getattr(self._inner, "digest_size", None)
|
|
# If the provided hash doesn't support block_size (e.g. built-in
|
|
# hashlib), 64 is the correct default for all built-in hash
|
|
# functions (md5, sha1, sha256).
|
|
self.block_size = getattr(self._inner, "block_size", 64)
|
|
|
|
# Truncate to digest_size if greater than block_size.
|
|
if len(key) > self.block_size:
|
|
key = make_hash(key).digest()
|
|
|
|
# Pad to block size.
|
|
key = key + bytes(self.block_size - len(key))
|
|
|
|
self._outer.update(bytes(x ^ 0x5C for x in key))
|
|
self._inner.update(bytes(x ^ 0x36 for x in key))
|
|
|
|
if msg is not None:
|
|
self.update(msg)
|
|
|
|
@property
|
|
def name(self):
|
|
return "hmac-" + getattr(self._inner, "name", type(self._inner).__name__)
|
|
|
|
def update(self, msg):
|
|
self._inner.update(msg)
|
|
|
|
def copy(self):
|
|
if not hasattr(self._inner, "copy"):
|
|
# Not supported for built-in hash functions.
|
|
raise NotImplementedError()
|
|
# Call __new__ directly to avoid the expensive __init__.
|
|
other = self.__class__.__new__(self.__class__)
|
|
other.block_size = self.block_size
|
|
other.digest_size = self.digest_size
|
|
other._inner = self._inner.copy()
|
|
other._outer = self._outer.copy()
|
|
return other
|
|
|
|
def _current(self):
|
|
h = self._outer
|
|
if hasattr(h, "copy"):
|
|
# built-in hash functions don't support this, and as a result,
|
|
# digest() will finalise the hmac and further calls to
|
|
# update/digest will fail.
|
|
h = h.copy()
|
|
h.update(self._inner.digest())
|
|
return h
|
|
|
|
def digest(self):
|
|
h = self._current()
|
|
return h.digest()
|
|
|
|
def hexdigest(self):
|
|
import binascii
|
|
|
|
return str(binascii.hexlify(self.digest()), "utf-8")
|
|
|
|
|
|
def new(key, msg=None, digestmod=None):
|
|
return HMAC(key, msg, digestmod)
|