def add(a,b):
if(a<b):
a0 = str(b).encode()
b0 = str(a).encode()
else:
a0 = str(a).encode()
b0 = str(b).encode()
ans = 0
for i in range(len(a0)-len(b0)):
ans = ans*10+a0[i]-48
for i in range(len(b0)):
ans = ans*10+(a0[i+len(a0)-len(b0)]+b0[i]+4)%10
return ans
def mul(a,b):
if(a<b):
a0 = str(b).encode()
b0 = str(a).encode()
else:
a0 = str(a).encode()
b0 = str(b).encode()
ans = 0
for i in range(len(b0)):
ans = ans*10+((a0[i+len(a0)-len(b0)]+2)*(b0[i]+2))%10
return ans
m = bytes_to_long(flag)
e = 65537
p = getPrime(512)
q = getPrime(512)
n = p*q
c = pow(m,e,n)
print(add(p,q))
print(mul(p,q))
print(n)
print(c)
# 10399034381787849923326924881454040531711492204619924608227265350044149907274051734345037676383421545973249148286183660679683016947030357640361405556516408
# 6004903250672248020273453078045186428048881010508070095760634049430058892705564009054400328070528434060550830050010084328522605000400260581038846465000861
# 100457237809578238448997689590363740025639066957321554834356116114019566855447194466985968666777662995007348443263561295712530012665535942780881309520544097928921920784417859632308854225762469971326925931642031846400402355926637518199130760304347996335637140724757568332604740023000379088112644537238901495181
# 49042009464540753864186870038605696433949255281829439530955555557471951265762643642510403828448619593655860548966001304965902133517879714352191832895783859451396658166132732818620715968231113019681486494621363269268257297512939412717227009564539512793374347236183475339558666141579267673676878540943373877937
题目结构很简单,两个特殊条件add和mul的结果,这两个函数简单来说就是不进位的加和乘,分析好这个之后,就是算法题。以下来具体看看这道题的步骤。
题解
首先分析add和mul两个函数:直接放到pycharm里调试,带几个数进去试试很快就能明白函数的功能,add是不进位的加法,mul则是不进位的乘法。
根据不进位的特性,构造算法可以利用这一点,一位一位循环去写。
from Crypto.Util.number import*
c = 49042009464540753864186870038605696433949255281829439530955555557471951265762643642510403828448619593655860548966001304965902133517879714352191832895783859451396658166132732818620715968231113019681486494621363269268257297512939412717227009564539512793374347236183475339558666141579267673676878540943373877937
e = 65537
n = 100457237809578238448997689590363740025639066957321554834356116114019566855447194466985968666777662995007348443263561295712530012665535942780881309520544097928921920784417859632308854225762469971326925931642031846400402355926637518199130760304347996335637140724757568332604740023000379088112644537238901495181
ad = 10399034381787849923326924881454040531711492204619924608227265350044149907274051734345037676383421545973249148286183660679683016947030357640361405556516408
mu = 6004903250672248020273453078045186428048881010508070095760634049430058892705564009054400328070528434060550830050010084328522605000400260581038846465000861
p = [0]
q = [0]
maskn = 10
for i in range(154):
adx = ad*10 // maskn
mux = mu*10 // maskn
tmpp = []
tmpq = []
for j in range(len(p)):
for pbar in range(10):
for qbar in range(10):
if ((pbar + qbar) % 10 == adx % 10 and pbar * qbar % 10 == mux % 10):
到这里主要算法的前半段就写完了,实现的主要就是两点,一点是逐位判断,另一个就是利用约束。
但是a+b=m , a*b = n 这样的式子,每一位a,b都可能存在多解,积累下来,总共的情况会呈指数级上升,最后还是没法计算。这时我们就需要再去找一个约束——n这个条件其实很好,结合之前写的有关低位爆破的dfs博客,可以逐位操作的情形,比较适合用前缀和的乘积与n的低位相对比来实现约束:
temp2 = n % maskn
temp1 = (pbar * maskn//10 + p[j]) * (qbar * maskn//10 + q[j]) % maskn
if temp1 == temp2:
tmpp.append( pbar * maskn//10 + p[j])
tmpq.append( qbar * maskn//10 + q[j])
maskn *= 10
p = tmpp
q = tmpq
print(i,len(p))
这套代码整体的实现经过可以参照我之前写的dfs那篇博客。
5space signin(未知低位的dfs和coppersmith)_a5555678744的博客-优快云博客
最终达到的结果就是得到154位十进制数都符合条件的(p,q)的可能取值
最后拿这些p,q用n余一下试试,如果能整除,那就是这个p或者q了。
for i in p:
if(n%i==0):
print(i)
最后常规解密:
import gmpy2
q=12092931636613623040737253079065768977037831274116990695362696899634198318309588587556607732878944639910799730236593646983127255905400637167879667181506829
p=8307103755174226983699771812499382664784661030503034013965679561410051699975573257899430944515587916063550418050690024796566861042630720583592848475010689
phi = (p-1)*(q-1)
d= gmpy2.invert(0x10001,phi)
print(long_to_bytes(pow(c,d,n)))