AMM算法
题目:
from Crypto.Util.number import *
import os
from gmpy2 import *
def getMyPrime(nbits):
while True:
n = 2*1009*getPrime(nbits//2)*getPrime(nbits//2)
if is_prime(n+1):
return n+1
p = getMyPrime(700)
q = getMyPrime(700)
n = p*q
e = 1009
flag = b'NSSCTF{******}' + os.urandom(100)
m = bytes_to_long(flag)
assert m.bit_length() < n.bit_length()
c = pow(m, e, n)
print(f'n = {n}')
print(f'c = {c}')
print(f'p = {p}')
print(f'q = {q}')
'''
n = 38041020633815871156456469733983765765506895617311762629687651104582466286930269704125415948922860928755218376007606985275046819516740493733602776653724917044661666016759231716059415706703608364873041098478331738686843910748962386378250780017056206432910543374411668835255040201640020726710967482627384460424737495938659004753604600674521079949545966815918391090355556787926276553281009472950401599151788863393804355849499551329
c = 2252456587771662978440183865248648532442503596913181525329434089345680311102588580009450289493044848004270703980243056178363045412903946651952904162045861994915982599488021388197891419171012611795147125799759947942753772847866647801312816514803861011346523945623870123406891646751226481676463538137263366023714001998348605629756519894600802504515051642140147685496526829541501501664072723281466792594858474882239889529245732945
p = 5220649501756432310453173296020153841505609640978826669340282938895377093244978215488158231209243571089268416199675077647719021740691293187913372884975853901554910056350739745148711689601574920977808625399309470283
q = 7286645200183879820325990521698389973072307061827784645416472106180161656047009812712987400850001340478084529480635891468153462119149259083604029658605921695587836792877281924620444742434168448594010024363257554563
'''
解题思路:
- 首先我们发现e和phi不互素,遇到此类题型时可以用如下做法(结果不对)
先求出e和phi的最大公约数gcd1=2然后e//gcd1和phi互素
- 还发现e和每个因子的欧拉值即p-1和q-1也不互素
- 因此参考基础RSA_不互素-e与(p-1)或(q-1)均不互素的做法吗?
这里的e同时不与(p-1)或(q-1)或phi均互素
- 以上做法都行不通
知识拓展:
AMM(全称为Adleman-Mander-Miller Method)
AMM里开平方根的算法与Tonelli–Shanks算法几乎一样,只不过后面乘积时一个是从大到小一个是从小到大
开平方根的思路:
但是这只能解决平方的情况
对于任意次方,即x^e ≡ r (mod p)此时分为两组情况
- gcd(e,p−1)=1
显然我们每天的RSA都属于这种情况,直接通过求逆元当作RSA解密即可
- e∣(p−1)
解答:
from Crypto.Util.number import *
from gmpy2 import *
import random
import math
n = 38041020633815871156456469733983765765506895617311762629687651104582466286930269704125415948922860928755218376007606985275046819516740493733602776653724917044661666016759231716059415706703608364873041098478331738686843910748962386378250780017056206432910543374411668835255040201640020726710967482627384460424737495938659004753604600674521079949545966815918391090355556787926276553281009472950401599151788863393804355849499551329
c = 2252456587771662978440183865248648532442503596913181525329434089345680311102588580009450289493044848004270703980243056178363045412903946651952904162045861994915982599488021388197891419171012611795147125799759947942753772847866647801312816514803861011346523945623870123406891646751226481676463538137263366023714001998348605629756519894600802504515051642140147685496526829541501501664072723281466792594858474882239889529245732945
p = 5220649501756432310453173296020153841505609640978826669340282938895377093244978215488158231209243571089268416199675077647719021740691293187913372884975853901554910056350739745148711689601574920977808625399309470283
q = 7286645200183879820325990521698389973072307061827784645416472106180161656047009812712987400850001340478084529480635891468153462119149259083604029658605921695587836792877281924620444742434168448594010024363257554563
e = 1009
def onemod(e, q):
p = random.randint(1, q-1)
while(powmod(p, (q-1)//e, q) == 1): # (r,s)=1
p = random.randint(1, q)
return p
def AMM_rth(o, r, q): # r|(q-1)
assert((q-1) % r == 0)
p = onemod(r, q)
t = 0
s = q-1
while(s % r == 0):
s = s//r
t += 1
k = 1
while((s*k+1) % r != 0):
k += 1
alp = (s*k+1)//r
a = powmod(p, r**(t-1)*s, q)
b = powmod(o, r*a-1, q)
c = powmod(p, s, q)
h = 1
for i in range(1, t-1):
d = powmod(int(b), r**(t-1-i), q)
if d == 1:
j = 0
else:
j = (-math.log(d, a)) % r
b = (b*(c**(r*j))) % q
h = (h*c**j) % q
c = (c*r) % q
result = (powmod(o, alp, q)*h)
return result
def ALL_Solution(m, q, rt, cq, e):
mp = []
for pr in rt:
r = (pr*m) % q
# assert(pow(r, e, q) == cq)
mp.append(r)
return mp
def calc(mp, mq, e, p, q):
i = 1
j = 1
t1 = invert(q, p)
t2 = invert(p, q)
for mp1 in mp:
for mq1 in mq:
j += 1
if j % 100000 == 0:
print(j)
ans = (mp1*t1*q+mq1*t2*p) % (p*q)
if check(ans):
return
return
def check(m):
try:
a = long_to_bytes(m)
if b'NSSCTF' in a:
print(a)
return True
else:
return False
except:
return False
def ALL_ROOT2(r, q): # use function set() and .add() ensure that the generated elements are not repeated
li = set()
while(len(li) < r):
p = powmod(random.randint(1, q-1), (q-1)//r, q)
li.add(p)
return li
cp = c % p
cq = c % q
mp = AMM_rth(cp, e, p) # AMM算法得到一个解
mq = AMM_rth(cq, e, q)
rt1 = ALL_ROOT2(e, p) # 得到所有的ri,即(ri*mp)^e%p = 1
rt2 = ALL_ROOT2(e, q)
amp = ALL_Solution(mp, p, rt1, cp, e) # 得到所有的mp
amq = ALL_Solution(mq, q, rt2, cq, e)
calc(amp, amq, e, p, q) # 俩俩CRT
#NSSCTF{ee5cb1a5-9d62-257a-9ef5-48b06ff0651a}\xbc\xbaw\xfe\xb8\x04A\x8es\xdct#\x1a\x91\x82\xbd\x0f\xfc<\xc4\xb0$\x01\xd0\xc8/\xd9d#\x9baf=\xf1\xfd\xde'\x0e=\xcfX\xd1\xdbM\x9f\xba\xaf\x8a\xb9\xf0\xd7\xaa{\xbf`:DY\xf5|\x11_R\x92\xa1\x9d\xc81\x12\xe9`\x17\xe3\n@K\\\xa5\x1f\xa7?\xdb\xf7p\x8aH\xba(\x02\xad\xf8n\xbe\xea\xcdTu\xac\xc4\xa1"