Bleichenbacher 1998¶
if there's an oracle that give it 0x0002
(PKCS#1).
let
Algorithm¶
let
be a set of intervals that
step 1¶
given an cipher
step 2¶
if
if
if
and
because
use these
step 3¶
after
and for
because
and for every
step 4¶
if
Code¶
def bleichenbacher_1998(n: int, e: int, c: int, oracle):
"""
- input : `n (int)`, `e (int)`, `c (int)`, `oracle (func)` , `c` is PKCS#1 conforming
- output : `m (int)` , `e`'s plain
- oracle func :
- input : `c (int)`
- output : `PKCS_conforming (bool)` , is `c` PKCS#1 conforming
"""
assert oracle(c)
B = 1 << (n.bit_length() // 8 - 1) * 8
def bleichenbacher_orifind_s(lower_bound: int):
si = lower_bound
while True:
new_c = (pow(si, e, n) * c) % n
if oracle(new_c):
return si
si += 1
def bleichenbacher_optfind_s(prev_si: int, a: int, b: int):
ri = ceil_int(2 * (b * prev_si - 2 * B), n)
while True:
low_bound = ceil_int(2 * B + ri * n, b)
high_bound = ceil_int(3 * B + ri * n, a)
for si in range(low_bound, high_bound):
new_c = (pow(si, e, n) * c) % n
if oracle(new_c):
return si
ri += 1
def bleichenbacher_merge_M(si: int, M: list):
new_M = []
for [a, b] in M:
r_low = ceil_int(a * si - 3 * B + 1, n)
r_high = floor_int(b * si - 2 * B, n) + 1
for ri in range(r_low, r_high):
interval_low = max(a, ceil_int(2 * B + ri * n, si))
interval_high = min(b, floor_int(3 * B + ri * n - 1, si))
if interval_high >= interval_low:
new_M.append([interval_low, interval_high])
return new_M
s = bleichenbacher_orifind_s(ceil_int(n, 3 * B))
M = bleichenbacher_merge_M(s, [[2 * B, 3 * B - 1]])
print(s, M)
while True:
if len(M) > 1:
s = bleichenbacher_orifind_s(s + 1)
else:
if M[0][0] == M[0][1]:
return M[0][0]
s = bleichenbacher_optfind_s(s, M[0][0], M[0][1])
M = bleichenbacher_merge_M(s, M)
print(s, M)