Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
jvdsn
GitHub Repository: jvdsn/crypto-attacks
Path: blob/master/attacks/rsa/bleichenbacher.py
2589 views
1
import logging
2
import os
3
import sys
4
from random import randrange
5
6
path = os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(os.path.abspath(__file__)))))
7
if sys.path[1] != path:
8
sys.path.insert(1, path)
9
10
from shared import ceil_div
11
from shared import floor_div
12
13
14
def _insert(M, a, b):
15
for i, (a_, b_) in enumerate(M):
16
if a_ <= b and a <= b_:
17
a = min(a, a_)
18
b = max(b, b_)
19
M[i] = (a, b)
20
return
21
22
M.append((a, b))
23
return
24
25
26
# Step 1.
27
def _step_1(padding_oracle, n, e, c):
28
s0 = 1
29
c0 = c
30
while not padding_oracle(c0):
31
s0 = randrange(2, n)
32
c0 = (c * pow(s0, e, n)) % n
33
34
return s0, c0
35
36
37
# Step 2.a.
38
def _step_2a(padding_oracle, n, e, c0, B):
39
s = ceil_div(n, 3 * B)
40
while not padding_oracle((c0 * pow(s, e, n)) % n):
41
s += 1
42
43
return s
44
45
46
# Step 2.b.
47
def _step_2b(padding_oracle, n, e, c0, s):
48
s += 1
49
while not padding_oracle((c0 * pow(s, e, n)) % n):
50
s += 1
51
52
return s
53
54
55
# Step 2.c.
56
def _step_2c(padding_oracle, n, e, c0, B, s, a, b):
57
r = ceil_div(2 * (b * s - 2 * B), n)
58
while True:
59
left = ceil_div(2 * B + r * n, b)
60
right = floor_div(3 * B + r * n, a)
61
for s in range(left, right + 1):
62
if padding_oracle((c0 * pow(s, e, n)) % n):
63
return s
64
65
r += 1
66
67
68
# Step 3.
69
def _step_3(n, B, s, M):
70
M_ = []
71
for (a, b) in M:
72
left = ceil_div(a * s - 3 * B + 1, n)
73
right = floor_div(b * s - 2 * B, n)
74
for r in range(left, right + 1):
75
a_ = max(a, ceil_div(2 * B + r * n, s))
76
b_ = min(b, floor_div(3 * B - 1 + r * n, s))
77
_insert(M_, a_, b_)
78
79
return M_
80
81
82
def attack(padding_oracle, n, e, c):
83
"""
84
Recovers the plaintext using Bleichenbacher's attack.
85
More information: Bleichenbacher D., "Chosen Ciphertext Attacks Against Protocols Based on the RSA Encryption Standard PKCS #1"
86
:param padding_oracle: the padding oracle taking integers, returns True if the PKCS #1 v1.5 padding is correct, False otherwise
87
:param n: the modulus
88
:param e: the public exponent
89
:param c: the ciphertext (integer)
90
:return: the plaintext (integer)
91
"""
92
k = ceil_div(n.bit_length(), 8)
93
B = 2 ** (8 * (k - 2))
94
logging.info("Executing step 1...")
95
s0, c0 = _step_1(padding_oracle, n, e, c)
96
M = [(2 * B, 3 * B - 1)]
97
logging.info("Executing step 2.a...")
98
s = _step_2a(padding_oracle, n, e, c0, B)
99
M = _step_3(n, B, s, M)
100
logging.info("Starting while loop...")
101
while True:
102
if len(M) > 1:
103
s = _step_2b(padding_oracle, n, e, c0, s)
104
else:
105
(a, b) = M[0]
106
if a == b:
107
m = (a * pow(s0, -1, n)) % n
108
return m
109
s = _step_2c(padding_oracle, n, e, c0, B, s, a, b)
110
M = _step_3(n, B, s, M)
111
112