When I was browsing Python HMAC module source code today I found out that it contains global variable _secret_backdoor_key
. This variable is then checked to interrupt object initialization.
The code looks like this
# A unique object passed by HMAC.copy() to the HMAC constructor, in order
# that the latter return very quickly. HMAC("") in contrast is quite
# expensive.
_secret_backdoor_key = []
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.
Defaults to hashlib.md5.
"""
if key is _secret_backdoor_key: # cheap
return
Full code is here.
Does anyone know what is the reason for this variable? Comment says it is there for HMAC to return quicker than blank string (""). But why would user want to pass empty key to HMAC function? Is variable naming just a joke from HMAC developer or is it really some sort of backdoor?
To create a copy of the HMAC instance, you need to create an empty instance first.
The _secret_backdoor_key
object is used as a sentinel to exit __init__
early and not run through the rest of the __init__
functionality. The copy
method then sets the instance attributes directly:
def copy(self):
"""Return a separate copy of this hashing object.
An update to this copy won't affect the original object.
"""
other = self.__class__(_secret_backdoor_key)
other.digest_cons = self.digest_cons
other.digest_size = self.digest_size
other.inner = self.inner.copy()
other.outer = self.outer.copy()
return other
You could get the same effect with self.__class__('')
(an empty string), but then HMAC.__init__
does a lot of unnecessary work as the attributes on the instance created are going to be replaced anyway. Note that using HMAC('')
is a valid way to create an instance, you'd not want an instance devoid of any state in that case. By passing in the sentinel, HMAC.copy()
can avoid all that extra work.
You could use a different 'flag' value, like False
, but it is way too easy to pass that in because of a bug in your own code. You'd want to be notified of such bugs instead. By using a 'secret' internal sentinel object instead, you avoid such accidental cases.
Using []
as a sentinel unique object is quite an old practice. These days you'd use object()
instead. The idea is that the sentinel is a unique, single object that you test against for identity with is
. You can't re-create that object elsewhere, the is
test only works if you pass in an reference to the exact same single object.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With