--- tags: 網頁設計社 109 --- # 網頁設計社 課前預習 Crypto [TOC] ## ROT-3 `ROT-X` 通常指的是明文(Plain Text) 經過 `Caesar` 加密位移 X 的這個過程 所以 `ROT-3` 就是明文往後移 3 位 `ABC` -> `DEF` 所以題目給的是往後移 3 位的結果 那就往後移 23 位 (等於往前移 3 位) 的方式還原明文 可以使用線上工具 [Online Caesar Solver](https://www.dcode.fr/caesar-cipher) Cipher Text : `IODJ{i1U57_7Ub_0i_fUbs70}` Plain Text : `FLAG{f1R57_7Ry_0f_cRyp70}` ## ROT-13 原理等同上面 只是 `ROT-13` 常會被獨立拉出來講 一個明文經過兩次 `ROT-13` 一樣等於明文 因為 `13 + 13 == 26` 所以用同樣的工具解即可 Cipher Text : `SYNT{13_1f_3dh4Y_70_3_1a_E07!?!?}` Plain Text : `FLAG{13_1s_3qu4L_70_3_1n_R07!?!?}` ## ROT-47 普通的 `ROT-1` ~ `ROT-26` 基本上都是將單位限制在字母 ``` ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz ``` `ROT-47` 則是增加了其他的單位 ``` !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO PQRSTUVWXYZ[\]^_\`abcdefghijklmnopqrstuvwxyz{|}~ ``` 但是 ROT-47 已經不再是位移的加密法了 而是有自己固定的表 所以不會存在 Key 的問題 `ABC` 經過 ROT-47 必定是 `pqr` `pqr` 經過 ROT-47 必定是 `ABC` [Online ROT-47 Solver](https://www.dcode.fr/rot-47-cipher) Cipher Text : ```u{pvL~z04cb$cC0$bC:tD0xd0f@_0bcdJN``` Plain Text : `FLAG{OK_c43S4r_S3riEs_I5_7o0_345y}` ## Substitution Cipher (替換式密碼) Substitution 就跟他名字一樣 會將某個字全部改成另外一個字 可是通常我們不會拿到所謂的 AlphaBet 這時候就要透過 `詞頻分析(Frequency Analysis)` 去猜測哪個字轉換成哪個字 不過詞頻分析必須在足夠多文字的狀況下準確率才會高 [Online Substition Solver](https://www.guballa.de/substitution-solver) ## RSA RSA 通常會產一個質數 p 跟質數 q 並且 $p * q$ 產生 N 生成一個公鑰 e 明文為 M $C = M ^{e}\ mod\ N$ 這樣就生成了密文 C 如果要解密 則需要先將 N 分解 為 p q 並且產生 N 的 phi $\phi(N) = (p - 1) * (q - 1)$ 這時候要生成私鑰 d $e d \equiv 1\ mod\ \phi(N)$ $\rightarrow (e * d)\ mod\ (p - 1) * (q - 1) = 1$ $\rightarrow d \equiv e ^ {\phi(N)^ {-1}}$ 所以 d 為 e 在 mod $\phi(N)$ 下的模反元素 反解密文就是 $M = C^{d}\ mod\ N$ ### EZ :::spoiler 題目生成腳本 ```python= from Crypto.Util.number import getPrime , bytes_to_long from gmpy2 import invert p = getPrime(300) q = getPrime(300) n = p * q e = 65537 d = invert(e , phi) flag = "<CENSORED>" m = bytes_to_long(flag) c = pow(m , e , n) print("d = {}\nn = {}\nc = {}".format(d , n , c)) ``` ::: 這題已經給了 c d n 所以照著最上面的做法做就好 :::spoiler Solve ```python= from Crypto.Util.number import long_to_bytes d = 1344939239776366990935622463961489359140452856321101516248708348578875896102438797450331586598999829539928031430749836055341616561771081285548126081116282354929872955174989209125377 n = 2471907649257495189997977716659490945369562478117562119871882860530982937990507921602512235774768141756158636840136723491042834034904344968108565557024434327520349498588752709967189 c = 819215704696949569378048307065024357817709672340647740001167828559855162549632702602380242339988471062471053844009762193707843808932617292741534009610491063461280050418643276060343 print(long_to_bytes(pow(c , d , n))) ``` ::: Plain Text : `FLAG{RSA_15_tO()_EZZZZZZZZZZZZZZZZZZZZZ}` ### Medium :::spoiler 題目生成腳本 ```python= from Crypto.Util.number import getPrime , bytes_to_long p = getPrime(200) q = getPrime(200) n = p * q e = 65537 flag = "<CENSORED>" m = bytes_to_long(flag) c = pow(m , e , n) print("c = {}\ne = {}\nn = {}".format(c , e , n)) ``` ::: 這次只有給 c e n 了 所以需要自行分解 n 去計算 $\phi(N)$ 接著算 d 我們可以透過 factorDB 去尋找已知的分解結果 ![](https://i.imgur.com/N6lA9IH.png) 把 n 丟上去就會看到這個 n 剛好有結果 :::spoiler Solve ```python= from gmpy2 import invert from Crypto.Util.number import long_to_bytes c = 1746556679338870404898027611524787577185747794969695663566697818653136706087741777676885930621912564690645654197639142252 e = 65537 n = 1891069273714264626402743793841358723166679597286337462645411575494175032702564905530101985949449542560475109474409423001 p = 1312638725457843296441325087628683365692505445859637479943363 q = n // p phi = (p - 1) * (q - 1) d = invert(e , phi) # e 在模 phi(n) 下的模反 m = pow(c , d , n) flag = long_to_bytes(m) print(flag) ``` ::: Plain Text : `FLAG{A_L1tTl3_H4rD_w1th_0n1y_c_e_n}` RSA 還有很多可以玩的 像是 `Padding Oracle` , `Known High Bit` ... 不過這些都要有很好的數學基礎 如果想要了解上面的計算過程 可以去看 > 費馬小定理 > 擴展歐幾里得 > 其他現代數論 因為我不知道你們課程中間上了啥 所以我就隨便寫 然後你們社長說想要有 HomeWork 所以那題我會在一個禮拜後寫解答 請先不要互相討論 ## HomeWork :::spoiler 完整題目生成腳本 ```python= from Crypto.Util.number import getPrime , bytes_to_long flag = "<CENSORED>" m = bytes_to_long(flag) p = getPrime(500) q1 = getPrime(500) q2 = getPrime(500) e = 0x10001 n1 = p * q1 n2 = p * q2 c1 = pow(m , e , n1) c2 = pow(m , e , n2) print("e = {}".format(e)) print("n1 = {}\nc1 = {}".format(n1 , c1)) print("n2 = {}\nc2 = {}".format(n2 , c2)) ``` ::: 我們先觀察一下內容 先把 `flag` 轉成數值的型態 接著 `getPrime` 生成 3 個 500 bit 的質數 `n1 = p * q1` `n2 = p * q2` 這題攻擊點還滿明顯的 因為這次數值沒有辦法在 `factorDB` 上找到分解結果 (因為我沒上傳 所以直接像 `Medium` 硬解是不行的 不果可以觀察到 `n1` 跟 `n2` 共用了 p 這個質數 這就導致可以用輾轉相除法 直接得出 p ```python p = gcd(n1 , n2) ``` 這樣我們就能夠直接求出 `q1` 跟 `q2` ```python q1 = n1 // p q2 = n2 // p ``` 然後選擇其中一項解即可 :::spoiler Solve ```python= #!/usr/bin/python3 #!/usr/bin/python3 from Crypto.Util.number import long_to_bytes , GCD as gcd , inverse e = 65537 n1 = 6068861093630746873768044688355298853083933009151961959188398961991863662151040864023339960011762462716389408933643989595286625007357793284214976356220021947194167010841038712605936232976686304351806381912214526638889234734932206094279579468712928780599596867762144892875118061985287887022646785837931 c1 = 3037342385739340367945904507379234973270735346973053423827283532096686615043623553094270264773951241329919873680487591181900409596948892088978158885683349009824512337304501764385989949839227854473143867071614764567958934212454211569051348678228551927885263001839701881982410839250993400652882230084374 n2 = 5342614899878968582043167026416417823904513647814239187008523122799106581332751539182555882626616040374365092831435269204997935976083420121296343605521759051815011705404929317993638111725882462301884186561624155889947445993847694026184453321304168163893381032745245492630042587897319519455229019629677 c2 = 4892329037617392667911100636460358752067797545427681944944031663995636089331976974525766744337299190728976024830034200179220287873870550272911108078586491953686309057949022354733449281629082848435441476115806898250285872623607409488277068004805238437982434359757500505773657567770686411309217984543755 p = gcd(n1 , n2) q1 = n1 // p q2 = n2 // p d1 = inverse(e , (p - 1) * (q1 - 1)) d2 = inverse(e , (p - 1) * (q2 - 1)) m1 = pow(c1 , d1 , n1) m2 = pow(c2 , d2 , n2) print(long_to_bytes(m1).decode("utf-8")) print(long_to_bytes(m2).decode("utf-8")) ``` :::