Add __eq__ to HashAlgorithm and padding instances#13271
Conversation
631283d to
2be27b4
Compare
| instances of classes in | ||
| :mod:`~cryptography.hazmat.primitives.asymmetric.padding` | ||
| comparable. | ||
| * Added `salt_length` property to |
There was a problem hiding this comment.
Let's put these in a separate PR. Whether or not we want to do __eq__ is possibly debateable, but if you want these properties to be public that's a separate discussion.
There was a problem hiding this comment.
Hi @reaperhulk
Thanks for the feedback - I've updated this PR to only include the __eq__ instances. I'll make a separate PR for the extra properties.
kr, Mat
2be27b4 to
a68beff
Compare
|
Looking at the test failures here the issue is that scapy creates its own HashAlgorithm, which now fails because they don't implement |
|
Or it could be a breaking change and that lib would need to implement the method. Open to implement any solution, just let me know what you prefer! |
|
@alex do you have an opinion here? I'm reluctant to spend breakage budget on this when we could avoid it with a concrete implementation, but I'm interested in other opinions. |
|
I'm pretty ambivalent about this. We have a few choices:
Of these I think (1) is probably best. |
|
For 3 the default impl could raise NotImplementedError so you wouldn’t need to have a potentially incorrect impl |
|
That can break existing applications, to the extent they're relying on the default |
|
I'm also ambivalent, I defer to your call and will adapt as requested. Just option three (default Implementation) seems like a bad idea to me. Mat |
|
After thinking for too long, I'm okay with option 1 here. |
|
Are you still interested in this PR? Happy to review/land with option 1 + a rebase to fix the changelog conflict |
a68beff to
7dd838f
Compare
alex
left a comment
There was a problem hiding this comment.
I think a question is whether we should be returning NotImplemented or False for diffefrent types
| eq_salt_length = self._salt_length is other._salt_length | ||
|
|
||
| return ( | ||
| isinstance(other, PSS) |
There was a problem hiding this comment.
We need to do this check first (otherwise you get an AttributeError) and return NotImplemented
|
|
||
| def __eq__(self, other: typing.Any) -> bool: | ||
| return ( | ||
| isinstance(other, OAEP) |
There was a problem hiding this comment.
Actually not correct in this case:
>>> h = hashes.SHA256()
>>> mgf = MGF1(h)
>>> OAEP(mgf, h, None) == h
False
| * Make instances of | ||
| :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` as well as | ||
| instances of classes in | ||
| :mod:`~cryptography.hazmat.primitives.asymmetric.padding` | ||
| comparable. |
There was a problem hiding this comment.
This isn't quite right for the behavior we implemented. I'd probably document it as "builtin hash classes can now be compared with =="
There was a problem hiding this comment.
agreed. will be updated.
7dd838f to
8fd3f3b
Compare
I don't know of any classes that do that. Standard python certainly doesn't: |
8fd3f3b to
c0e6409
Compare
:-) |
To quote official documentation - emphasis mine:
So I can implement it, it's just lots of extra code with no benefit that I'm aware of. |
d8d41e4 to
45d3bac
Compare
|
|
||
| def __eq__(self, other: typing.Any) -> bool: | ||
| return isinstance(other, DummyMGF) | ||
|
|
There was a problem hiding this comment.
This class is more-or-less duplicated in test_openssl as well!
I would offer to move it to tests.doubles.py for shorter code - if you approve.
45d3bac to
d71c7ac
Compare
|
Sorry to let this drop off our radar. After discussion @alex and I still think there's value in supporting |
|
Hi there! This also dropped of my radar, so no worries! I'll try to follow up soon, but busy in June. I hope July is still okay. Mat |
* Add __eq__ and __hash__ to hash algorithm and padding classes This incorporates the work from #13271, implementing __eq__ on all concrete HashAlgorithm subclasses and on the classes in the asymmetric padding module (PKCS1v15, PSS, OAEP, MGF1). Per review discussion on that PR, the implementations follow the pattern used by other __eq__ impls across the codebase: they return NotImplemented for non-matching types rather than False, and the ABCs are left untouched so third-party subclasses are unaffected. __hash__ is defined alongside __eq__ so instances remain hashable. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WsrSAAABRsHFpHtQxZ1sjs * Remove __hash__ from hash algorithm and padding classes Keep only the __eq__ implementations, matching the scope of the original PR. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WsrSAAABRsHFpHtQxZ1sjs * Test hash algorithm inequality x509-ext style Replace the direct __eq__ NotImplemented assertion with a test_ne matching the pattern used in test_x509_ext.py. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WsrSAAABRsHFpHtQxZ1sjs * Restructure equality tests to match test_x509_ext.py conventions Split == and != assertions into separate test_eq/test_ne methods, rename test_eq_different_* to test_ne_different_*, and assert inequality against object() in test_ne. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WsrSAAABRsHFpHtQxZ1sjs * Collapse redundant test_eq/test_ne methods Merge test_ne assertions into test_eq where both were parameterized over the same values or trivially small. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WsrSAAABRsHFpHtQxZ1sjs --------- Co-authored-by: Claude <noreply@anthropic.com>
|
#15153 takes this over, thanks! |
This PR:
__eq__()to all subclasses of HashAlgorithm.__eq__()to all padding classes.My primary use case is testing. First, it's really un-pythonic to me (obviously very subjective, but it feels just not right to me) to write
assert isinstance(cert.cert.signature_hash_algorithm, hashes.SHA256()), when I could writeassert cert.cert.signature_hash_algorithm == hashes.SHA256(). But once you start comparing to other data structures, it gets even uglier:I think this just looks a lot better and readable: