When I was browsing Python HMAC module source code today I found out that it contains global variable
# A unique object passed by HMAC.copy() to the HMAC constructor, in order
# that the latter return very quickly. HMAC("") in contrast is quite
_secret_backdoor_key = 
"""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
To create a copy of the HMAC instance, you need to create an empty instance first.
_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.
 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.