Improve third party interop with __subclasshook__ #735

Closed
lvh opened this Issue Mar 5, 2014 · 5 comments

Projects

None yet

4 participants

@lvh
Python Cryptographic Authority member
lvh commented Mar 5, 2014

A play in several acts, involving a Python interpreter:

>>> from cryptography.hazmat.backends import default_backend
>>> backend = default_backend()
>>> from pyblake2 import blake2b
>>> from cryptography.hazmat.primitives.kdf.hkdf import HKDF
>>> hkdf = HKDF(blake2b(),length=32, salt=b"hello", info=b"world", backend=backend)

Victory! Except: hkdf.derive("secret"):

Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File "/usr/local/Cellar/python/2.7.5/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-pa
ckages/cryptography/hazmat/primitives/kdf/hkdf.py", line 87, in derive
    return self._expand(self._extract(key_material))
  File "/usr/local/Cellar/python/2.7.5/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-pa
ckages/cryptography/hazmat/primitives/kdf/hkdf.py", line 58, in _extract
    h = hmac.HMAC(self._salt, self._algorithm, backend=self._backend)
  File "/usr/local/Cellar/python/2.7.5/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-pa
ckages/cryptography/hazmat/primitives/hmac.py", line 27, in __init__
    raise TypeError("Expected instance of interfaces.HashAlgorithm.")
TypeError: Expected instance of interfaces.HashAlgorithm.

What is this HashAlgorithm? It is a name, digest_size and block_size. But:

>>> h = blake2b()
>>> h.block_size
128
>>> h.digest_size
64
>>> h.name
'blake2b'

Perhaps I will inform the ABC of blake2b's special powers:

>>> from cryptography.hazmat.primitives.interfaces import HashAlgorithm
>>> HashAlgorithm.register(blake2b)
Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File "/usr/local/Cellar/python/2.7.5/Frameworks/Python.framework/Versions/2.7/lib/python2.7/abc.py"
, line 108, in register
    raise TypeError("Can only register classes")
TypeError: Can only register classes

Alas!

Of course, another way would be an adapter in cryptography :)

@public
Python Cryptographic Authority member

I am tentatively +1 on this idea. My main concern is that simply having the right names doesn't tell you that e.g. block_size is specified in the correct units.

Also this is unlikely to actually work how you expect it to anyway as the backend HMACContext for OpenSSL will raise UnsupportedAlgorithm for blake2b. You'll need a backend type that actually supports that digest.

@lvh
Python Cryptographic Authority member
lvh commented Mar 5, 2014

Hm, that's a good point. For HashAlgorithm, at least, I think it'll be less of an issue, since we're using the same definitions as hashlib, so anything that uses the wrong units was probably already entirely broken. For other interfaces like block ciphers etc this could definitely lead to issues, but IIUC we're not copying any interfaces there, so we're less likely to run into objects that can be converted verbatim? (that's a lot of maybes and question marks)

@dreid
Python Cryptographic Authority member
MultiBackend([Blake2Backend(), default_backend()])
@lvh
Python Cryptographic Authority member
lvh commented Mar 5, 2014

Related to what @dreid just said, @public pointed out earlier on IRC that even with __subclasshook__ this particular example wouldn't fly, because underlying HMAC-BLAKE2 calls would be handed to OpenSSL. which doesn't know about BLAKE2.

@reaperhulk
Python Cryptographic Authority member

I think we've generally decided not to do this based on the length of time this issue has been sitting (and the difficulty of composing primitives across backends), so I'll close this for now.

@reaperhulk reaperhulk closed this Jun 21, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment