如果两个正整数a和n互质,则n的欧拉函数 φ(n) 可以让下面的等式成立: \[ a^{φ(n)}≡1 mod n \] 当n为质数时,欧拉定理可以化为: \[ a^{n-1}≡1 mod n \] 这就是费马小定理,它是欧拉定理的特例。
模反元素
当ab ≡ 1 mod n时,称b为a的模反元素,也称b为a在模n域下的逆。
RSA公私钥生成
加密者随机选择两个足够大的质数p和q(实际中通常选择512位)。
计算n = p*q。
计算φ(n) = (p-1)*(q-1)。
随机选择一个小于φ(n)且与φ(n)互质的e。
计算e在模n下的逆d,即e*d ≡ 1 mod φ(n)。
(n, e)封装为公钥,(p, q, d)封装为私钥。
至此所有数据计算完成。
加密与解密
将密文转码为十六进制数据m。
c ≡ m^e mod n,c 即为密文。
m ≡ c^d mod n。
解密算法证明
\[ m^{φ(n)}≡1 modn\ m^{kφ(n)+1}≡m modn\ m^{ed}≡ c^d≡ m modn \]
各种题型介绍
已知n,e,c(直接分解)
n = 5221752478228507746817749923851271656160818214576859501288944132584319293315684653488045907979899837193635911723726962945029941498626499202969421505409311
c = 3508639296102512450759730723246544089341766434632407076573093985251751867216058996957915991315405129764052410967805084651073059790045344575535583118277973
import gmpy2 from Crypto.Util.number import long_to_bytes
n = 5221752478228507746817749923851271656160818214576859501288944132584319293315684653488045907979899837193635911723726962945029941498626499202969421505409311 p = 72261694404632581565900073275105451175333931206466294424742649423557055375657 q = 72261694404632581565900073275105451175333931206466294424742649423557055375623 c = 3508639296102512450759730723246544089341766434632407076573093985251751867216058996957915991315405129764052410967805084651073059790045344575535583118277973 e = 65537 assert n == p*q phi = (p-1)*(q-1) d = gmpy2.invert(e, phi) print(long_to_bytes(pow(c, d, n)))
已知n,c,p,q(爆破e)
n = 117930806043507374325982291823027285148807239117987369609583515353889814856088099671454394340816761242974462268435911765045576377767711593100416932019831889059333166946263184861287975722954992219766493089630810876984781113645362450398009234556085330943125568377741065242183073882558834603430862598066786475299918395341014877416901185392905676043795425126968745185649565106322336954427505104906770493155723995382318346714944184577894150229037758434597242564815299174950147754426950251419204917376517360505024549691723683358170823416757973059354784142601436519500811159036795034676360028928301979780528294114933347127 c = 41971850275428383625653350824107291609587853887037624239544762751558838294718672159979929266922528917912189124713273673948051464226519605803745171340724343705832198554680196798623263806617998072496026019940476324971696928551159371970207365741517064295956376809297272541800647747885170905737868568000101029143923792003486793278197051326716680212726111099439262589341050943913401067673851885114314709706016622157285023272496793595281054074260451116213815934843317894898883215362289599366101018081513215120728297131352439066930452281829446586562062242527329672575620261776042653626411730955819001674118193293313612128 p = 139916095583110895133596833227506693679306709873174024876891023355860781981175916446323044732913066880786918629089023499311703408489151181886568535621008644997971982182426706592551291084007983387911006261442519635405457077292515085160744169867410973960652081452455371451222265819051559818441257438021073941183 q = 842868045681390934539739959201847552284980179958879667933078453950968566151662147267006293571765463137270594151138695778986165111380428806545593588078365331313084230014618714412959584843421586674162688321942889369912392031882620994944241987153078156389470370195514285850736541078623854327959382156753458569
from Crypto.Util.number import * from gmpy2 import *
n = 117930806043507374325982291823027285148807239117987369609583515353889814856088099671454394340816761242974462268435911765045576377767711593100416932019831889059333166946263184861287975722954992219766493089630810876984781113645362450398009234556085330943125568377741065242183073882558834603430862598066786475299918395341014877416901185392905676043795425126968745185649565106322336954427505104906770493155723995382318346714944184577894150229037758434597242564815299174950147754426950251419204917376517360505024549691723683358170823416757973059354784142601436519500811159036795034676360028928301979780528294114933347127 c = 41971850275428383625653350824107291609587853887037624239544762751558838294718672159979929266922528917912189124713273673948051464226519605803745171340724343705832198554680196798623263806617998072496026019940476324971696928551159371970207365741517064295956376809297272541800647747885170905737868568000101029143923792003486793278197051326716680212726111099439262589341050943913401067673851885114314709706016622157285023272496793595281054074260451116213815934843317894898883215362289599366101018081513215120728297131352439066930452281829446586562062242527329672575620261776042653626411730955819001674118193293313612128 p = 139916095583110895133596833227506693679306709873174024876891023355860781981175916446323044732913066880786918629089023499311703408489151181886568535621008644997971982182426706592551291084007983387911006261442519635405457077292515085160744169867410973960652081452455371451222265819051559818441257438021073941183 q = 842868045681390934539739959201847552284980179958879667933078453950968566151662147267006293571765463137270594151138695778986165111380428806545593588078365331313084230014618714412959584843421586674162688321942889369912392031882620994944241987153078156389470370195514285850736541078623854327959382156753458569 phi = (p - 1) * (q - 1)
e = 2 for e inrange(100000): if isPrime(e): try: d = invert(e, phi) flag = long_to_bytes(pow(c, d, n)) flag = str(flag) if"CTF"in flag or"flag"in flag: print(e, '\n', flag) break except ZeroDivisionError: continue
已知n,e,c,dp(dp ≡ d mod(p-1))
e = 65537 n = 156808343598578774957375696815188980682166740609302831099696492068246337198792510898818496239166339015207305102101431634283168544492984586566799996471150252382144148257236707247267506165670877506370253127695314163987084076462560095456635833650720606337852199362362120808707925913897956527780930423574343287847 c = 108542078809057774666748066235473292495343753790443966020636060807418393737258696352569345621488958094856305865603100885838672591764072157183336139243588435583104423268921439473113244493821692560960443688048994557463526099985303667243623711454841573922233051289561865599722004107134302070301237345400354257869 dp = 734763139918837027274765680404546851353356952885439663987181004382601658386317353877499122276686150509151221546249750373865024485652349719427182780275825
数学推导 \[ 已知dp ≡ d mod (p-1), e*d ≡ 1 mod(p-1)(q-1).\\可得edp ≡ ed mod(p-1).\\展开可得ed = edp +k_1(p-1) = 1 + k_2(p-1)(q-1).\\dp < p-1, e> k_2*(q-1)-k_1.\\ \]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
import gmpy2 from Crypto.Util.number import *
e = 65537 n = 156808343598578774957375696815188980682166740609302831099696492068246337198792510898818496239166339015207305102101431634283168544492984586566799996471150252382144148257236707247267506165670877506370253127695314163987084076462560095456635833650720606337852199362362120808707925913897956527780930423574343287847 c = 108542078809057774666748066235473292495343753790443966020636060807418393737258696352569345621488958094856305865603100885838672591764072157183336139243588435583104423268921439473113244493821692560960443688048994557463526099985303667243623711454841573922233051289561865599722004107134302070301237345400354257869 dp = 734763139918837027274765680404546851353356952885439663987181004382601658386317353877499122276686150509151221546249750373865024485652349719427182780275825
for i inrange(1, e): if (e * dp - 1) % i == 0and n % ((e * dp - 1) // i + 1) == 0: q = n // ((e * dp - 1) // i + 1) phi = (q - 1) * ((e * dp - 1) // i) d = gmpy2.invert(e, phi) m = gmpy2.powmod(c, d, n)
print(long_to_bytes(m))
提取公钥/flag信息
1 2 3 4 5 6 7 8 9 10 11
from Crypto.PublicKey import RSA path = r'C:\public.key' withopen(path) as f: key = RSA.import_key(f.read()) print('e = %d' % key.e) print('n = %d' % key.n) f = open('flag.enc', 'rb').read() print(f) e = 65537 tmp = int.from_bytes(f, byteorder='big') # 高位存储 print(tmp)
n = 22708078815885011462462049064339185898712439277226831073457888403129378547350292420267016551819052430779004755846649044001024141485283286483130702616057274698473611149508798869706347501931583117632710700787228016480127677393649929530416598686027354216422565934459015161927613607902831542857977859612596282353679327773303727004407262197231586324599181983572622404590354084541788062262164510140605868122410388090174420147752408554129789760902300898046273909007852818474030770699647647363015102118956737673941354217692696044969695308506436573142565573487583507037356944848039864382339216266670673567488871508925311154801
\[ 首先可知gcd(e_1, e_2) = 1,使用扩展欧几里得可以求出满足e_1*s_1+e_2*s_2 = 1的s_1和s_2。\ 又已知c_1 ≡ m^{e_1} mod n, c_2 ≡ m^{e_2} mod n,可得c_1^{s_1}*c_2^{s_2} mod n ≡ m^{(e_1*s_1+e_2*s_2)} ≡ m。 \]
for i inrange(len(n)): for j inrange(len(n)): if i != j: if gmpy2.gcd(n[i], n[j]) != 1: print(i, j) # 输出对应的n的序号 p = gmpy2.gcd(n[i], n[j]) print("p = ", p) q = n[i] // p print("q = ", q) d = gmpy2.invert(e, (p - 1) * (q - 1)) print("d = ", d) m = pow(c[i], d, n[i]) print("m = ", m)
解题思路2:中国剩余定理
数学基础
\[ 假设整数m_1,m_2,...m_n两两互素,则对于任意的整数a_1,a_2,...a_n,方程组\ \begin{equation} \begin{cases} x ≡ a_1 mod m_1 \ x ≡ a_2 mod m_2 \ ... \ x ≡ a_n mod m_n \end{cases} \end{equation} \]
\[ 都存在整数解,若X ,Y都满足该方程组,X ≡ Y modN,其中N=m_1*m_2*...*m_n。具体而言,\ x ≡ \sum_{i=1}^na_i\*\frac{N}{m_i}*[(\frac{N}{m_i})^{-1}]_{m_i}modN \]