Tags: factoring rsa 

Rating:

We are given the code (and the legend that someone was _very_ insistent we should use this code to generate RSA params and it's totally secure):
```
#!/usr/bin/env python3

from random import getrandbits, randrange

def generate():
IV = 5326453656607417485924926839199132413931736025515611536784196637666048763966950827721156230379191350953055349475955277628710716247141676818146987326676993279104387449130750616051134331541820233198166403132059774303658296195227464112071213601114885150668492425205790070658813071773332779327555516353982732641; seed = 0; temp = [0, 0]; key = 0
while(key != 2):
if key == 0:
seed = getrandbits(1024) | (2 ** 1023 + 1)
seed_ = seed ^ IV; n = seed_ << 1024 | getrandbits(1024); seed = n//seed | 1
while(1):
seed += 2; pi = seed - 1; b = 0; m = pi;
while (m & 1) == 0:
b += 1
m >>= 1
garbage = []; false_positive = 1
for i in range(min(10, seed - 2)):
a = randrange(2, seed)
while a in garbage:
a = randrange(2, seed)
garbage.append(a); z = pow(a, m, seed)
if z == 1 or z == pi:
continue
for r in range(b):
z = (z * z) % seed;
if z == 1:
break
elif z == pi:
false_positive = 0; break
if false_positive:
break
if not false_positive:
break
temp[key] = seed; key += 1
return(temp[0], temp[1])

def egcd(a, b):
if a == 0:
return (b, 0, 1)
else:
g, y, x = egcd(b % a, a)
return (g, x - (b // a) * y, y)

def inverse(a, m):
g, x, y = egcd(a, m)
if g != 1:
raise Exception('modular inverse does not exist')
else:
return x % m

def RSA():
(p, q) = (0, 0)
while(p == q):
(p, q) = generate()
n = p * q
e = 0x10001
d = inverse(e, (p - 1) * (q - 1))

return (n, e, d)
```
and the data generated by this code:
```
n: 31492593980972292127624243962770751972791586997559415119664067126352874455354554396825959492520866585425367347800693358768073355393830644370233119742738920691048174984688259647179867604016694194959178874017481204930806636137689428300906890690499460758884820784037362414109026624345965004388036791265355660637942956892135275111144499770662995342441666665963192321379766221844532877240853120099814348371659810248827790798567539193378235283620829716728221866131016495050641120781696656274043778657558111564011476899021178414456560902915167861941065608670797745473745460370154604158882840935421329890924498705681322154941
e: 65537
c: 31105943135542175872131854877903463541878591074483146885600982339634188894256348597314413875362761608401326213641601058666720123544299104566877513595233611507482373096711246358592143276357334231127437090663716106190589907211171164566820101003469295773837109380815526746746678580390779170877213166506863176846508933485178812858166031517243792487958635017917996626849408595921536238471169975280762677305759764602707285224588771643832335444552739959904673158661424651074772864245589406308229908379716500604590198490474257870603210120239125184805345188782082520055749851184516545898673495570079185198108523819932428027921
```

This is an example of a backdoor in RSA modulus; the modulus looks just fine and is hard to factor by itself, but the factorization becomes very easy for someone knowing a secret constant used in generation. Namely, the first prime p is random, but the second one is generated as the next prime after ((p ^ IV) \* 2\*\*1024 + randbits(1024)) / p, so the moduls n = p\*q = (p ^ IV) \* 2\*\*1024 + randbits(1024) + p\*(some small number due to search of the next prime); the most significant half of bits of n equals p ^ IV plus some small number.
```
import gmpy2
n = ...
e = 65537
c = ...
IV = ...
for i in range(10000):
p=((n>>1024)-i)^IV
if n%p == 0:
break
else:
print("Factorization not found!")

q = n//p
d = gmpy2.invert(e, (p-1)*(q-1))
print(bytes.fromhex('%x' % pow(c, d, n)))
# prints b'IJCTF{kl3pt0_n0th1n6_uP_mY_s133v3_numb3r5}'
```