hmac on on lopy



  • Just came upon an issue with the micropython hmac library on pycom modules:

    https://github.com/micropython/micropython-lib/blob/master/hmac/hmac.py

    OSError: only one active hash operation is permitted at a time

    The problem is, that hmac lib does instantiate two hash objects at the same time (last two lines):

            if callable(digestmod):
                self.digest_cons = digestmod
            elif isinstance(digestmod, str):
                self.digest_cons = lambda d=b'': _hashlib.new(digestmod, d)
            else:
                self.digest_cons = lambda d=b'': digestmod.new(d)
    
            self.outer = self.digest_cons()
            self.inner = self.digest_cons()
    

    Anyone already solved that? Otherwise I'll do ... :-)



  • @this-wiederkehr
    Seems to work perfectly fine. Even calling it multiple times (from REPL at least) works. Thanks alot! Also for the quick response.



  • This code is 'works for me' not sure about the limitations anymore...

    Update: i think the limitation is that you can call digest only once.



  • """HMAC (Keyed-Hashing for Message Authentication) Python module.
    Implements the HMAC algorithm as described by RFC 2104.
    """
    
    import hashlib as _hashlib
    
    trans_5C = bytes((x ^ 0x5C) for x in range(256))
    trans_36 = bytes((x ^ 0x36) for x in range(256))
    
    def translate(d, t):
        return bytes(t[x] for x in d)
    
    # The size of the digests returned by HMAC depends on the underlying
    # hashing module used.  Use digest_size from the instance of HMAC instead.
    digest_size = None
    
    
    
    class HMAC:
        """RFC 2104 HMAC class.  Also complies with RFC 4231.
        This supports the API for Cryptographic Hash Functions (PEP 247).
        """
        blocksize = 64  # 512-bit HMAC; can be changed in subclasses.
    
        def __init__(self, key, msg = None, digestmod = None):
            """Create a new HMAC object.
            key:       key for the keyed hash object.
            msg:       Initial input for the hash, if provided.
            digestmod: A module supporting PEP 247.  *OR*
                       A hashlib constructor returning a new hash object. *OR*
                       A hash name suitable for hashlib.new().
                       Defaults to hashlib.md5.
                       Implicit default to hashlib.md5 is deprecated and will be
                       removed in Python 3.6.
            Note: key and msg must be a bytes or bytearray objects.
            """
    
            if not isinstance(key, (bytes, bytearray)):
                raise TypeError("key: expected bytes or bytearray, but got %r" % type(key).__name__)
    
            if digestmod is None:
                raise Exception("HMAC() without an explicit digestmod argument "
                               "is deprecated.")
    
            if callable(digestmod):
                self.digest_cons = digestmod
            elif isinstance(digestmod, str):
                self.digest_cons = lambda d=b'': _hashlib.new(digestmod, d)
            else:
                self.digest_cons = lambda d=b'': digestmod.new(d)
    
            self.inner = self.digest_cons()
            self.digest_size = 32
            self.block_size = 64
    
            if len(key) > self.block_size:
                raise Exception('key too long')
    
            key = key + bytes(self.block_size - len(key))
            self.inner.update(translate(key, trans_36))
            self.outer_key_translated = translate(key, trans_5C)
            if msg is not None:
                self.update(msg)
    
        @property
        def name(self):
            return "hmac-" + self.inner.name
    
        def update(self, msg):
            """Update this hashing object with the string msg.
            """
            self.inner.update(msg)
    
    
        def digest(self):
            """Return the hash value of this hashing object.
            This returns a string containing 8-bit data.  The object is
            not altered in any way by this function; you can continue
            updating the object after calling this function.
            """
            inner_digest = self.inner.digest()
            self.outer = self.digest_cons()
            self.outer.update(self.outer_key_translated)
            self.outer.update(inner_digest)
            return self.outer.digest()
    
    
    def new(key, msg = None, digestmod = None):
        """Create a new hashing object and return it.
        key: The starting key for the hash.
        msg: if available, will immediately be hashed into the object's starting
        state.
        You can now feed arbitrary strings into the object using its update()
        method, and can ask for the hash value at any time by calling its digest()
        method.
        """
        return HMAC(key, msg, digestmod)
    
    


  • Running into the same problem here. Did you solve it yet? Would appreciate if you could share your solution.


Log in to reply
 

Pycom on Twitter