-
Notifications
You must be signed in to change notification settings - Fork 114
Commit
Use as many constant-time comparisons as practical in the `rsa.pkcs1.decrypt` function. `cleartext.index(b'\x00', 2)` will still be non-constant-time. The alternative would be to iterate over all the data byte by byte in Python, which is several orders of magnitude slower. Given that a perfect constant-time implementation is very hard or even impossible to do in Python [1], I chose the more performant option here. [1]: https://securitypitfalls.wordpress.com/2018/08/03/constant-time-compare-in-python/
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -30,6 +30,7 @@ | |
import os | ||
import sys | ||
import typing | ||
from hmac import compare_digest | ||
|
||
from . import common, transform, core, key | ||
|
||
|
@@ -251,17 +252,20 @@ def decrypt(crypto: bytes, priv_key: key.PrivateKey) -> bytes: | |
# Detect leading zeroes in the crypto. These are not reflected in the | ||
# encrypted value (as leading zeroes do not influence the value of an | ||
# integer). This fixes CVE-2020-13757. | ||
if len(crypto) > blocksize: | ||
raise DecryptionError('Decryption failed') | ||
crypto_len_bad = len(crypto) > blocksize | ||
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong.
tomato42
|
||
|
||
# If we can't find the cleartext marker, decryption failed. | ||
if cleartext[0:2] != b'\x00\x02': | ||
raise DecryptionError('Decryption failed') | ||
cleartext_marker_bad = not compare_digest(cleartext[:2], b'\x00\x02') | ||
|
||
# Find the 00 separator between the padding and the message | ||
try: | ||
sep_idx = cleartext.index(b'\x00', 2) | ||
except ValueError: | ||
This comment has been minimized.
Sorry, something went wrong.
tomato42
|
||
sep_idx = -1 | ||
sep_idx_bad = sep_idx < 0 | ||
|
||
anything_bad = crypto_len_bad | cleartext_marker_bad | sep_idx_bad | ||
if anything_bad: | ||
raise DecryptionError('Decryption failed') | ||
This comment has been minimized.
Sorry, something went wrong.
tomato42
|
||
|
||
return cleartext[sep_idx + 1:] | ||
|
this is operating on publicly known information, it doesn't have to be done in side-channel free manner