diff options
author | Sybren A. Stüvel <sybren@stuvel.eu> | 2016-01-22 13:11:22 +0100 |
---|---|---|
committer | Sybren A. Stüvel <sybren@stuvel.eu> | 2016-01-22 13:14:40 +0100 |
commit | 2310b34bdb530e0bad793d42f589c9f848ff181b (patch) | |
tree | 7add9af08619ac491dadef6c0a9620794e5b68bd /rsa | |
parent | 15b69b38568cfe883180c397d408207b456e0e06 (diff) | |
download | rsa-git-2310b34bdb530e0bad793d42f589c9f848ff181b.tar.gz |
Fix #19: Implemented blinding when decrypting.
This prevents side-channel (such as timing) attacks, see:
https://en.wikipedia.org/wiki/Blinding_%28cryptography%29
Diffstat (limited to 'rsa')
-rw-r--r-- | rsa/key.py | 36 | ||||
-rw-r--r-- | rsa/pkcs1.py | 10 |
2 files changed, 44 insertions, 2 deletions
@@ -321,6 +321,42 @@ class PrivateKey(AbstractKey): def __ne__(self, other): return not (self == other) + def blind(self, message, r): + """Performs blinding on the message using random number 'r'. + + @param message: the message, as integer, to blind. + @param r: the random number to blind with. + @return: the blinded message. + + The blinding is such that message = unblind(decrypt(blind(encrypt(message))). + + See https://en.wikipedia.org/wiki/Blinding_%28cryptography%29 + + >>> pk = PrivateKey(3727264081, 65537, 3349121513, 65063, 57287) + >>> message = 12345 + >>> encrypted = rsa.core.encrypt_int(message, pk.e, pk.n) + >>> blinded = pk.blind(encrypted, 4134431) # blind before decrypting + >>> decrypted = rsa.core.decrypt_int(blinded, pk.d, pk.n) + >>> pk.unblind(decrypted, 4134431) + 12345 + """ + + return (message * pow(r, self.e, self.n)) % self.n + + def unblind(self, blinded, r): + """Performs blinding on the message using random number 'r'. + + @param blinded: the blinded message, as integer, to unblind. + @param r: the random number to unblind with. + @return: the original message. + + The blinding is such that message = unblind(decrypt(blind(encrypt(message))). + + See https://en.wikipedia.org/wiki/Blinding_%28cryptography%29 + """ + + return (rsa.common.inverse(r, self.n) * blinded) % self.n + @classmethod def _load_pkcs1_der(cls, keyfile): """Loads a key in PKCS#1 DER format. diff --git a/rsa/pkcs1.py b/rsa/pkcs1.py index 7d6814c..0b7982c 100644 --- a/rsa/pkcs1.py +++ b/rsa/pkcs1.py @@ -229,8 +229,14 @@ def decrypt(crypto, priv_key): blocksize = common.byte_size(priv_key.n) encrypted = transform.bytes2int(crypto) - decrypted = core.decrypt_int(encrypted, priv_key.d, priv_key.n) - cleartext = transform.int2bytes(decrypted, blocksize) + + # Perform blinded decryption to prevent side-channel attacks. + # See https://en.wikipedia.org/wiki/Blinding_%28cryptography%29 + blinded = priv_key.blind(encrypted, 4134431) # blind before decrypting + decrypted = core.decrypt_int(blinded, priv_key.d, priv_key.n) + unblinded = priv_key.unblind(decrypted, 4134431) + + cleartext = transform.int2bytes(unblinded, blocksize) # If we can't find the cleartext marker, decryption failed. if cleartext[0:2] != b('\x00\x02'): |