summaryrefslogtreecommitdiff
path: root/rsa
diff options
context:
space:
mode:
authorSybren A. Stüvel <sybren@stuvel.eu>2020-11-15 15:18:38 +0100
committerSybren A. Stüvel <sybren@stuvel.eu>2020-11-15 15:21:31 +0100
commitdae8ce0d85478e16f2368b2341632775313d41ed (patch)
treeb93513f2f24d50246410ab8379eb60a9fc2cdff0 /rsa
parent6f59ff07a317409fe68696935daf8549b1555c74 (diff)
downloadrsa-git-dae8ce0d85478e16f2368b2341632775313d41ed.tar.gz
Fix #165: CVE-2020-25658 - Bleichenbacher-style timing oracle
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/
Diffstat (limited to 'rsa')
-rw-r--r--rsa/pkcs1.py12
1 files changed, 8 insertions, 4 deletions
diff --git a/rsa/pkcs1.py b/rsa/pkcs1.py
index 57b0276..19e24c7 100644
--- a/rsa/pkcs1.py
+++ b/rsa/pkcs1.py
@@ -30,6 +30,7 @@ import hashlib
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
# 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:
+ 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')
return cleartext[sep_idx + 1:]