diff --git a/RSA-encryption/Attack-LSBit-Oracle/README.md b/RSA-encryption/Attack-LSBit-Oracle/README.md index 5fa3f85..0edda0b 100644 --- a/RSA-encryption/Attack-LSBit-Oracle/README.md +++ b/RSA-encryption/Attack-LSBit-Oracle/README.md @@ -91,8 +91,9 @@ Consider two messages 2\*m and 4\*m [\[1\]](https://crypto.stackexchange.com/que You must be wondering how condition 3 and 4 above hold true. You will understand better when you see the script implementing this: ```python e = 65537 -upper_limit = N +upper_limit = 1 lower_limit = 0 +denominator = 1 flag = "" i = 1 @@ -100,16 +101,21 @@ i = 1 while i <= 1024: chosen_ct = long_to_bytes((bytes_to_long(flag_enc)*pow(2**i, e, N)) % N) output = _decrypt(chosen_ct) + delta = upper_limit - lower_limit + upper_limit *= 2 + lower_limit *= 2 + denominator *= 2 if ord(output[-1]) == 0: - upper_limit = (upper_limit + lower_limit)/2 + upper_limit -= delta elif ord(output[-1]) == 1: - lower_limit = (lower_limit + upper_limit)/2 + lower_limit += delta else: throw Exception i += 1 # Decrypted ciphertext -print long_to_bytes(upper_limit) +flag = upper_limit * N / denominator +print long_to_bytes(flag) ``` Now try understanding the conditions 3 and 4 using the above script: @@ -119,7 +125,7 @@ Now try understanding the conditions 3 and 4 using the above script: It is somewhat similar to binary search algorithm, because our attack is doing the same (lowering the range of `m` until we get `m`), hence the complexity of this attack is **log2n**. -Note that the above script messes up the last byte of the plaintext. I am trying to find out why, and will update the README as soon as I get it. +Note that we keep track of the numerators and denominators separately, or else we end up with a messed up last byte from truncating along the way. I have written a script illustrating a server vulnerable to this attack, which you can find here: [encrypt.py](encrypt.py). You can also find the script I wrote to attack the above vulnerable service, which you can find here: [exploit.py](exploit.py) diff --git a/RSA-encryption/Attack-LSBit-Oracle/exploit.py b/RSA-encryption/Attack-LSBit-Oracle/exploit.py index fe94d98..8dc3a3e 100644 --- a/RSA-encryption/Attack-LSBit-Oracle/exploit.py +++ b/RSA-encryption/Attack-LSBit-Oracle/exploit.py @@ -31,21 +31,25 @@ def _decrypt(ciphertext): print "\n\n" e = 65537 -upper_limit = N +upper_limit = 1 lower_limit = 0 +denominator = 1 flag = "" -i = 1 -while i <= 1034: +for i in range(1, N.bit_length()+1): chosen_ct = long_to_bytes((bytes_to_long(flag_enc)*pow(2**i, e, N)) % N) output = _decrypt(chosen_ct) + delta = upper_limit - lower_limit + upper_limit *= 2 + lower_limit *= 2 + denominator *= 2 if ord(output[-1]) == 0: - upper_limit = (upper_limit + lower_limit)/2 + upper_limit -= delta elif ord(output[-1]) == 1: - lower_limit = (lower_limit + upper_limit)/2 + lower_limit += delta else: break print "Unsuccessfull" - i += 1 -print "Flag : ", long_to_bytes(lower_limit) +flag = N * lower_limit / denominator +print "Flag : ", long_to_bytes(flag) diff --git a/RSA-encryption/Attack-LSBit-Oracle/lsbitoracle.py b/RSA-encryption/Attack-LSBit-Oracle/lsbitoracle.py index 5cf5fec..aa2c3f4 100644 --- a/RSA-encryption/Attack-LSBit-Oracle/lsbitoracle.py +++ b/RSA-encryption/Attack-LSBit-Oracle/lsbitoracle.py @@ -2,14 +2,12 @@ from Crypto.PublicKey import RSA -def lsbitoracle(flag_enc, _decrypt, e, N, upper_limit, lower_limit): +def lsbitoracle(flag_enc, _decrypt, e, N): """ Reference: https://crypto.stackexchange.com/questions/11053/rsa-least-significant-bit-oracle-attack Function implementing LSBit Oracle Attack - *Warning*: Function does not return the last byte of the final plaintext - :parameters: flag_enc : str Ciphertext you want to decrypt @@ -19,26 +17,27 @@ def lsbitoracle(flag_enc, _decrypt, e, N, upper_limit, lower_limit): Public Key exponent N : long Public Key Modulus - upper_limit: long - Maximum value of corresponding plaintext of flag_enc - lower_limit: long - Minimum value of corresponding plaintext of flag_enc - Since the attack messes up with the last byte of the plaintext, lsbitoracle - function returns only flag[:-1]. It returns -1 in case of any Exception + Returns -1 in case of any Exception """ flag = "" i = 1 - while lower_limit < upper_limit: + lower_limit = 0 + upper_limit = 1 + denominator = 1 + for i in range(1, N.bit_length()+1): chosen_ct = long_to_bytes((bytes_to_long(flag_enc)*pow(2**i, e, N)) % N) output = _decrypt(chosen_ct) + delta = upper_limit - lower_limit + upper_limit *= 2 + lower_limit *= 2 + denominator *= 2 if ord(output[-1]) == 0: - upper_limit = (upper_limit + lower_limit)/2 + upper_limit -= delta elif ord(output[-1]) == 1: - lower_limit = (lower_limit + upper_limit)/2 + lower_limit += delta else: return -1 i += 1 - # clearing the last byte from the flag - flag = lower_limit & (~0xff) + flag = N * lower_limit / denominator return long_to_bytes(flag)