RSA attack
ctf common rsa attacks are the following
- Low encryption exponent attack
- Low encryption exponent broadcast attacks
- Low decryption exponent attack
- Common Mode attack
- Known high attack
0x00 low encryption exponent attack
When e is too small, if the plaintext is too small, resulting in a clear cube is still less than n, then the cipher text directly prescribing three, to obtain the plaintext.
If the plaintext cubic larger than n, but not big enough, then let k, we are:
c= m^e+kn
Blasting k, if c-kn able to open three times radical, it can be obtained directly plaintext.
# 低加密指数攻击
import gmpy2
import time
n = 22885480907469109159947272333565375109310485067211461543881386718201442106967914852474989176175269612229966461160065872310916096148216253429849921988412342732706875998100337754561586600637594798877898552625378551427864501926224989873772743227733285336042475675299391051376624685754547818835551263597996620383338263448888107691240136257201191331617560711786674975909597833383395574686942099700631002290836152972352041024137872983284691831292216787307841877839674258086005814225532597955826353796634417780156185485054141684249037538570742860026295194559710972266059844824388916869414355952432189722465103299013237588737
c = 15685364647213619014219110070569189770745535885901269792039052046431067708991036961644224230125219358149236447900927116989931929305133870392430610563331490276096858863490412102016758082433435355613099047001069687409209484751075897343335693872741
e = 3
i = 0
s = time.clock()
while 1:
m, b = gmpy2.iroot(c+i*n, e)
if b:
print('[-]m is:', m)
print('[!]Timer:', round(time.clock()-s, 2), 's')
break
i+=1
0x01 low encryption exponent broadcast attacks
If the selected encryption exponent is low, and uses the same encryption exponent transmitting to a recipient group of the same information, it may be broadcast to obtain the plaintext attack
c1 = m ^ e mod n1
c2 = m^e mod n2
c3 = m^e mod n3
We can use Chinese Remainder Theorem to solve the above equation
0x02 low decryption exponent attack
Here can not read, use wienerAttack, if e looks great, then it may be a small d
# 低解密指数攻击
import gmpy2
def continuedFra(x, y):
cF = []
while y:
cF += [x // y]
x, y = y, x % y
return cF
def Simplify(ctnf):
numerator = 0
denominator = 1
for x in ctnf[::-1]:
numerator, denominator = denominator, x * denominator + numerator
return (numerator, denominator)
def calculateFrac(x, y):
cF = continuedFra(x, y)
cF = list(map(Simplify, (cF[0:i] for i in range(1, len(cF)))))
return cF
def solve_pq(a, b, c):
par = gmpy2.isqrt(b * b - 4 * a * c)
return (-b + par) / (2 * a), (-b - par) / (2 * a)
def wienerAttack(e, n):
for (d, k) in calculateFrac(e, n):
print(e)
print(d)
print(k)
if k == 0:
continue
if (e * d - 1) % k != 0:
continue
phi = (e * d - 1) // k
p, q = solve_pq(1, n - phi + 1, n)
if p * q == n:
return abs(int(p)), abs(int(q))
print('[!]not find!')
n = 12238605063252292170613110607692779326628090745751955692266649177882959231822580682548279800443278979485092243645806337103841086023159482786712759291169541633901936290854044069486201989034158882661270017305064348254800318759062921744741432214818915527537124001063995865927527037625277330117588414586505635959411443039463168463608235165929831344586283875119363703480280602514451713723663297066810128769907278246434745483846869482536367912810637275405943566734099622063142293421936734750356828712268385319217225803602442033960930413469179550331907541244416573641309943913383658451409219852933526106735587605884499707827
e = 11850552481503020257392808424743510851763548184936536180317707155841959788151862976445957810691568475609821000653594584717037528429828330763571556164988619635320288125983463358648887090031957900011546300841211712664477474767941406651977784177969001025954167441377912326806132232375497798238928464025466905201977180541053129691501120197010080001677260814313906843670652972019631997467352264392296894192998971542816081534808106792758008676039929763345402657578681818891775091140555977382868531202964486261123748663752490909455324860302967636149379567988941803701512680099398021640317868259975961261408500449965277690517
c = 9472193174575536616954091686751964873836697237500198884451530469300324470671555310791335185133679697207007374620225900775502162690848135615431624557389304657410880981454777737587420426091879654002644281066474715074536611611252677882396384453641127487515845176069574754606670518031472235144795376526854484442135299818868525539923568705203042265537204111153151119105287648912908771710419648445826883069030285651763726003413418764301988228077415599665616637501056116290476861280240577145515875430665394216054222788697052979429015400411487342877096677666406389711074591330476335174211990429870900468249946600544116793793
p, q = wienerAttack(e, n)
print('[+]Found!')
print('[-]p =', p)
print('[-]q =', q)
d = gmpy2.invert(e, (p-1)*(q-1))
print('[-]m is:', pow(c, d, n))
0x03 common-mode attack
In use in the same RSA modulus n the same plaintext m is encrypted, it can restore the plaintext m in the case where the value of n without decomposition
c1 = m^e1 mod n
c2 = m^e2 mod n
# 共模攻击
import gmpy2
n = 158052722013789461456896900244510199169216575693048895162538548356466884311543740968048825149608833390255268602486435690724338965409521812963337715301197225841194835534751041470231293288252951274190599189716955573428884560130364021535005115652592074445852835422027406556727605302404510264249211145063332337043
e1 = 665213
e2 = 368273
c1 = 16698617641888248664694980135332125531792692516788088682722832061393117609508765284473236240256421599515450690670639565968165473479697383505401285976148490839526672808730165847471005704945978274496508928460578173068717106075169723401049489389383596761956301440156581021583368058047939083755488885694261340425
c2 = 59192887933967939708054321952273893559113509451228797382728687616356609407020086787061368452871936378934964292805289941535766263083244529814852043063188312786173717046316177403357053871483983775362121186037776932260378728059531236711960979620603784044468207000654149190295060179235411429700710154759043236436
s0, s1, s2 = gmpy2.gcdext(e1, e2)
if s1 < 0:
s1 = -s1
c1 = gmpy2.invert(c1, n)
elif s2 < 0:
s2 = -s2
c2 = gmpy2.invert(c2, n)
m = gmpy2.powmod(c1, s1, n)*gmpy2.powmod(c2, s2, n) % n
print('[-]m is:', m)
Reference: https://github.com/yifeng-lee/RSA-In-CTF