[TOC] # Tóm lược về RSA ## Thuật toán ![image](https://hackmd.io/_uploads/H1irK18ikl.png) RSA là thuật toán mã hóa công khai cho nên sẽ gồm có 2 cặp khóa công khai và khóa bí mật. Các khóa công khai có dạng $\displaystyle ( n,e)$ được khởi tạo như sau: - Ta chọn $\displaystyle n=pq$ là tích của hai số nguyên tố lớn $\displaystyle p$ và $\displaystyle q$ - Số mũ lập mã của ta sẽ là số nguyên dương $\displaystyle e$ thỏa mãn $\displaystyle \gcd( e,( p-1)( q-1)) =1$. Tiếp theo là cặp khóa bí mật $\displaystyle ( n,d)$: - $\displaystyle d$ là số nguyên dương thỏa mãn $\displaystyle ed\equiv 1(\bmod( p-1)( q-1))$ - $\displaystyle n$ là số ban đầu mà ta chọn Bây giờ, nếu hai người Alice và Bob muốn truyền tin cho nhau thì đầu tiên Alice sẽ tính toán các khóa công khai $\displaystyle ( n,e)$ và gửi cho Bob (khóa được công khai và ai cũng có thể sử dụng được). Sau đó Bob sẽ xử lí plaintext mà mình muốn gửi, chuyển nó về một số nguyên dương $\displaystyle m< n$. Nếu tin nhắn quá dài và $\displaystyle m >n$ thì có thể chia nhỏ ra để xử lí từng phần. Tiếp theo Bob sẽ tính $\displaystyle c=m^{e}\bmod n$ là ciphertext được mã hóa bằng cặp khóa công khai $\displaystyle ( n,e)$ và gửi cho Alice. Alice nhận được $\displaystyle c$ và sẽ sử dụng cặp khóa bí mật của mình để giải mã. Cụ thể \begin{equation*} c^{d} \equiv \left( m^{e}\right)^{d} \equiv m\bmod n \end{equation*} Do $\displaystyle m< n$ nên $\displaystyle m\bmod n=m$. Như vậy nếu tìm được khóa $d$ thì ta có thể bẻ khóa được hệ mật RSA. Người ta cũng chứng minh được rằng độ khó của bài toán tìm khóa bí mật $d$ dựa vào cặp khóa công khai tương đương với bài toán phân tích thừa số nguyên tố của $n$. ## Về mặt toán học Về cơ bản thuật toán mã hóa RSA hoạt động dựa trên tính chất của phi hàm Euler và định lí Euler. Cụ thể như sau: **Định nghĩa 1.** Cho $\displaystyle n\geqslant 1$ là một số nguyên dương. Số các số nguyên dương không vượt quá $\displaystyle n$ và nguyên tố cùng nhau với $\displaystyle n$ chính là $\displaystyle \varphi ( n)$ hay còn gọi là phi hàm Euler của $\displaystyle n$. **Định nghĩa 2.** Tập hợp các số nguyên $\displaystyle A=\{a_{1} ,a_{2} ,...,a_{n}\}$ được gọi là hệ thặng dư đầy đủ modulo $\displaystyle n$ khi và chỉ khi hai số bất kì trong tập hợp không đồng dư với nhau theo modulo $\displaystyle n$. Nói cách khác tập số dư $\displaystyle r_{i}$ của $\displaystyle a_{i}$ khi chia cho $\displaystyle n$ sẽ trùng với tập $\displaystyle \{0,1,...,n-1\}$. **Định nghĩa 3.** Tập hợp các số nguyên $\displaystyle B=\{b_{1} ,...,b_{\varphi ( n)}\}$ được gọi là hệ thặng dư thu gọn modulo $\displaystyle n$ khi và chỉ khi $\displaystyle ( b_{i} ,n) =1,\forall i=1,...,\varphi ( n)$ và $\displaystyle b_{i}\not{\equiv } b_{j}(\bmod n) ,\forall i,j$. Từ các định nghĩa trên ta sẽ đi chứng minh định lí Euler như sau: **Định lí Euler.** Cho $\displaystyle a,m$ là các số nguyên dương và $\displaystyle \gcd( a,m) =1$. Khi đó \begin{equation*} a^{\varphi ( m)} \equiv 1(\bmod m) \end{equation*} Chứng minh. Gọi $\displaystyle M=\{m_{1} ,...,m_{\varphi ( m)}\}$ là hệ thặng dư thu gọn modulo $\displaystyle m$. Khi đó với $\displaystyle ( a,m) =1$ thì ta cũng có $\displaystyle aM$ là hệ thặng dư thu gọn modulo $\displaystyle m$. Thật vậy, xét $\displaystyle am_{i} ,am_{j} \in aM$ và giả sử $\displaystyle am_{i} \equiv am_{j}\bmod m$ thì khi đó \begin{gather*} a( m_{i} -m_{j}) \equiv 0\bmod m\\ \leftrightarrow m_{i} \equiv m_{j}\bmod m \end{gather*} là điều vô lí vì $\displaystyle m_{i} \neq m_{j}$. Lấy tích lần lượt các phần tử của hai tập thì ta có \begin{gather*} am_{1} am_{2} ...am_{\varphi ( m)} \equiv m_{1} m_{2} ...m_{\varphi ( m)}\bmod m\\ \leftrightarrow a^{\varphi ( m)} \equiv 1(\bmod m) \end{gather*} Vậy ta có điều phải chứng mimh. Cách tính cụ thể cho phi hàm Euler thì mọi người tham khảo ở [Wikipedia](https://vi.wikipedia.org/wiki/H%C3%A0m_phi_Euler) hoặc trong phần tài liệu tham khảo. Như vậy ta thấy, để tính được $d$ thì ta phải tính được $\varphi(n)$, nhưng để tính được $\varphi(n)$ thì ta phải phân tích được $n$. Ta để ý thêm rằng $\displaystyle m^{ed} \equiv m^{1+k\varphi ( n)} \equiv m\cdot \left( m^{k}\right)^{\varphi ( n)} \equiv m\bmod n$ tức là ta có $\displaystyle \left( m^{k}\right)^{\varphi ( n)} \equiv 1(\bmod n)$? Điều này không hẳn đúng vì ta không chắc $\displaystyle ( m,n) =1$ hay không. Nếu như $\displaystyle ( m,n) \neq 1$ thì đẳng thức $\displaystyle \left( m^{k}\right)^{\varphi ( n)} \equiv 1(\bmod n)$ là sai. Vậy làm sao ta đảm bảo được rằng trong quá trình truyền dữ liệu, số $\displaystyle m$ mà ta chọn luôn thỏa $\displaystyle ( m,n) =1$ (nếu tính toán lại thì sẽ rất lâu). Mình có đọc được bài viết này trên [Crypto StackExchange](https://crypto.stackexchange.com/questions/25648/how-do-we-guarantee-plaintext-is-coprime-in-rsa) Tác giả bài viết chỉ ra rằng xác suất để "bốc trúng" một số nhỏ hơn $n$ mà không nguyên tố cùng nhau với nó là rất thấp. Cụ thể với $n=pq$ thì xác suất sẽ là $\displaystyle \frac{p+q-1}{pq} < \frac{p+q}{pq} =\frac{1}{p} +\frac{1}{q} \ \sim 0$, gần như không thể xảy ra với $p,q$ là các số nguyên tố rất lớn. # Starter ## Modular Exponentiation Dùng hàm `pow` trong `pycryptodome` ```python= from Cryptodome.Util.number import * print(pow(101,17,22663)) ``` ## Public Keys ```python= from Cryptodome.Util.number import * pt=12 e=65537 p=17 q=23 n=p*q print(pow(pt,e,n)) ``` ## Euler's Totient Để bài yêu cầu tính phi hàm Euler của số $n$. ```python= from Cryptodome.Util.number import * p= 857504083339712752489993810777 q= 1029224947942998075080348647219 print((p-1)*(q-1)) ``` P/s: một số thuật tính phi hàm Euler của $n$ cho trước: ```python= def sieve(limit): A=[True for _ in range(limit+1)] A[0]=A[1]=False p=2 while (p*p<=limit): if A[p]==True: for j in range(p*p,limit+1,p): A[j]=False p+=1 prime=[] for p in range (2,limit+1): if A[p]==True: prime.append(p) return prime def prime_fac_sieve(n): factors={} prime=sieve(n//2) for p in prime: if p * p >= n: break while n % p == 0: if p in factors: factors[p] +=1 else: factors[p]=1 n//=p if n > 1 : factors[n]=1 return factors def euler_totient(n): prime_factors=prime_fac_sieve(n) result=1 for p,exp in prime_factors.items(): result *= (p**(exp)-p**(exp-1)) return result def faster_phi(n): res=n i=2 while i * i <= n: # vì các ước nguyên tố #của n nếu có ước lớn nhất thì cũng không thể vượt quá n / 2 trừ khi n chính là một số nguyên tố. if n % i == 0 : while n % i == 0: n//=i res-=res//i i += 1 if n > 1: res-=res//n # xử lí trường hợp n là số nguyên tố, hoặc n có ước nguyên tố lớn hơn căn n return res ``` ## Private Keys Tính khóa bí mật $d$ trong mã hóa RSA từ các khóa công khai: ```python= from Cryptodome.Util.number import * e = 65537 p = 857504083339712752489993810777 q = 1029224947942998075080348647219 phi=((p-1)*(q-1)) d=inverse(e,phi) print(d) ``` ## RSA Decryption Bài cho cặp khóa công khai $(N,e)$. Có thể dùng Sage để factor: ![image](https://hackmd.io/_uploads/HkGx25Ijke.png) ```python= from Cryptodome.Util.number import * n=882564595536224140639625987659416029426239230804614613279163 e=65537 p=857504083339712752489993810777 q=1029224947942998075080348647219 phi=(p-1)*(q-1) d=inverse(e,phi) ct=77578995801157823671636298847186723593814843845525223303932 pt=pow(ct,d,n) print(pt) ``` ## RSA Signatures Chall cho ta cặp khóa bí mật: ``` N = 15216583654836731327639981224133918855895948374072384050848479908982286890731769486609085918857664046075375253168955058743185664390273058074450390236774324903305663479046566232967297765731625328029814055635316002591227570271271445226094919864475407884459980489638001092788574811554149774028950310695112688723853763743238753349782508121985338746755237819373178699343135091783992299561827389745132880022259873387524273298850340648779897909381979714026837172003953221052431217940632552930880000919436507245150726543040714721553361063311954285289857582079880295199632757829525723874753306371990452491305564061051059885803 d = 11175901210643014262548222473449533091378848269490518850474399681690547281665059317155831692300453197335735728459259392366823302405685389586883670043744683993709123180805154631088513521456979317628012721881537154107239389466063136007337120599915456659758559300673444689263854921332185562706707573660658164991098457874495054854491474065039621922972671588299315846306069845169959451250821044417886630346229021305410340100401530146135418806544340908355106582089082980533651095594192031411679866134256418292249592135441145384466261279428795408721990564658703903787956958168449841491667690491585550160457893350536334242689 ``` Và dùng cặp khóa này để kí văn bản ![image](https://hackmd.io/_uploads/Sy0XT5Iike.png) Code: ```python= from Cryptodome.Util.number import * from hashlib import sha256 n = 15216583654836731327639981224133918855895948374072384050848479908982286890731769486609085918857664046075375253168955058743185664390273058074450390236774324903305663479046566232967297765731625328029814055635316002591227570271271445226094919864475407884459980489638001092788574811554149774028950310695112688723853763743238753349782508121985338746755237819373178699343135091783992299561827389745132880022259873387524273298850340648779897909381979714026837172003953221052431217940632552930880000919436507245150726543040714721553361063311954285289857582079880295199632757829525723874753306371990452491305564061051059885803 d = 11175901210643014262548222473449533091378848269490518850474399681690547281665059317155831692300453197335735728459259392366823302405685389586883670043744683993709123180805154631088513521456979317628012721881537154107239389466063136007337120599915456659758559300673444689263854921332185562706707573660658164991098457874495054854491474065039621922972671588299315846306069845169959451250821044417886630346229021305410340100401530146135418806544340908355106582089082980533651095594192031411679866134256418292249592135441145384466261279428795408721990564658703903787956958168449841491667690491585550160457893350536334242689 msg=b'crypto{Immut4ble_m3ssag1ng}' msg=sha256(msg).hexdigest() msg_bytes=bytes.fromhex(msg) m=pow(bytes_to_long(msg_bytes),d,n) print(m) ``` # Primes Part 1 ## Factoring Bài yêu cầu ta phân tích thừa số nguyên tố. Ta có thể sử dụng FactorDB ![image](https://hackmd.io/_uploads/BJGsDXPoJl.png) ## Inferius Prime Source code của bài: ```python= #!/usr/bin/env python3 from Crypto.Util.number import getPrime, inverse, bytes_to_long, long_to_bytes, GCD e = 0x10001 # n will be 8 * (100 + 100) = 1600 bits strong (I think?) which is pretty good p = getPrime(100) q = getPrime(100) phi = (p - 1) * (q - 1) d = inverse(e, phi) n = p * q FLAG = b"crypto{???????????????}" pt = bytes_to_long(FLAG) ct = pow(pt, e, n) print(f"n = {n}") print(f"e = {e}") print(f"ct = {ct}") pt = pow(ct, d, n) decrypted = long_to_bytes(pt) assert decrypted == FLAG ``` và file output.txt ``` n = 984994081290620368062168960884976209711107645166770780785733 e = 65537 ct = 948553474947320504624302879933619818331484350431616834086273 ``` $n$ của bài này khá nhỏ nên ta có thể dùng hàm `factor` của `sagemath` để phân tích. ```python= from Cryptodome.Util.number import * from sage.all import * e=65537 ct=948553474947320504624302879933619818331484350431616834086273 n=984994081290620368062168960884976209711107645166770780785733 factors=factor(n) p,q=factors[0][0],factors[1][0] phi=(p-1)*(q-1) d=inverse(e,phi) result=(pow(ct,d,n)) print(long_to_bytes(result)) ``` ## Monoprime output.txt ``` n = 171731371218065444125482536302245915415603318380280392385291836472299752747934607246477508507827284075763910264995326010251268493630501989810855418416643352631102434317900028697993224868629935657273062472544675693365930943308086634291936846505861203914449338007760990051788980485462592823446469606824421932591 e = 65537 ct = 161367550346730604451454756189028938964941280347662098798775466019463375610700074840105776873791605070092554650190486030367121011578171525759600774739890458414593857709994072516290998135846956596662071379067305011746842247628316996977338024343628757374524136260758515864509435302781735938531030576289086798942 ``` $n$ ở bài này chính là một số nguyên tố ```python= from Cryptodome.Util.number import * from sage.all import * e=65537 ct=161367550346730604451454756189028938964941280347662098798775466019463375610700074840105776873791605070092554650190486030367121011578171525759600774739890458414593857709994072516290998135846956596662071379067305011746842247628316996977338024343628757374524136260758515864509435302781735938531030576289086798942 n=171731371218065444125482536302245915415603318380280392385291836472299752747934607246477508507827284075763910264995326010251268493630501989810855418416643352631102434317900028697993224868629935657273062472544675693365930943308086634291936846505861203914449338007760990051788980485462592823446469606824421932591 phi=n-1 d=inverse(e,phi) result=(pow(ct,d,n)) print(long_to_bytes(result)) ``` ## Square Eyes Bài này cho ta một file output.txt Từ đề bài ta biết được gợi ý $n$ là một số chính phương. Dùng FactorDB thì lấy được $p$ thỏa $p^{2}=n$. ``` n = 535860808044009550029177135708168016201451343147313565371014459027743491739422885443084705720731409713775527993719682583669164873806842043288439828071789970694759080842162253955259590552283047728782812946845160334801782088068154453021936721710269050985805054692096738777321796153384024897615594493453068138341203673749514094546000253631902991617197847584519694152122765406982133526594928685232381934742152195861380221224370858128736975959176861651044370378539093990198336298572944512738570839396588590096813217791191895941380464803377602779240663133834952329316862399581950590588006371221334128215409197603236942597674756728212232134056562716399155080108881105952768189193728827484667349378091100068224404684701674782399200373192433062767622841264055426035349769018117299620554803902490432339600566432246795818167460916180647394169157647245603555692735630862148715428791242764799469896924753470539857080767170052783918273180304835318388177089674231640910337743789750979216202573226794240332797892868276309400253925932223895530714169648116569013581643192341931800785254715083294526325980247219218364118877864892068185905587410977152737936310734712276956663192182487672474651103240004173381041237906849437490609652395748868434296753449 e = 65537 ct = 222502885974182429500948389840563415291534726891354573907329512556439632810921927905220486727807436668035929302442754225952786602492250448020341217733646472982286222338860566076161977786095675944552232391481278782019346283900959677167026636830252067048759720251671811058647569724495547940966885025629807079171218371644528053562232396674283745310132242492367274184667845174514466834132589971388067076980563188513333661165819462428837210575342101036356974189393390097403614434491507672459254969638032776897417674577487775755539964915035731988499983726435005007850876000232292458554577437739427313453671492956668188219600633325930981748162455965093222648173134777571527681591366164711307355510889316052064146089646772869610726671696699221157985834325663661400034831442431209123478778078255846830522226390964119818784903330200488705212765569163495571851459355520398928214206285080883954881888668509262455490889283862560453598662919522224935145694435885396500780651530829377030371611921181207362217397805303962112100190783763061909945889717878397740711340114311597934724670601992737526668932871436226135393872881664511222789565256059138002651403875484920711316522536260604255269532161594824301047729082877262812899724246757871448545439896 ``` ```python= from Cryptodome.Util.number import * n = ... e = 65537 ct = 222502885974182429500948389840563415291534726891354573907329512556439632810921927905220486727807436668035929302442754225952786602492250448020341217733646472982286222338860566076161977786095675944552232391481278782019346283900959677167026636830252067048759720251671811058647569724495547940966885025629807079171218371644528053562232396674283745310132242492367274184667845174514466834132589971388067076980563188513333661165819462428837210575342101036356974189393390097403614434491507672459254969638032776897417674577487775755539964915035731988499983726435005007850876000232292458554577437739427313453671492956668188219600633325930981748162455965093222648173134777571527681591366164711307355510889316052064146089646772869610726671696699221157985834325663661400034831442431209123478778078255846830522226390964119818784903330200488705212765569163495571851459355520398928214206285080883954881888668509262455490889283862560453598662919522224935145694435885396500780651530829377030371611921181207362217397805303962112100190783763061909945889717878397740711340114311597934724670601992737526668932871436226135393872881664511222789565256059138002651403875484920711316522536260604255269532161594824301047729082877262812899724246757871448545439896 p = q = 23148667521998097720857168827790771337662483716348435477360567409355026169165934446949809664595523770853897203103759106983985113264049057416908191166720008503275951625738975666019029172377653170602440373579593292576530667773951407647222757756437867216095193174201323278896027294517792607881861855264600525772460745259440301156930943255240915685718552334192230264780355799179037816026330705422484000086542362084006958158550346395941862383925942033730030004606360308379776255436206440529441711859246811586652746028418496020145441513037535475380962562108920699929022900677901988508936509354385660735694568216631382653107 phi = (p-1)*(q) d = inverse(e,phi) decrypt = pow(ct,d,n) print(long_to_bytes(decrypt)) ``` ## Manyprime output.txt ``` n = 171731371218065444125482536302245915415603318380280392385291836472299752747934607246477508507827284075763910264995326010251268493630501989810855418416643352631102434317900028697993224868629935657273062472544675693365930943308086634291936846505861203914449338007760990051788980485462592823446469606824421932591 e = 65537 ct = 161367550346730604451454756189028938964941280347662098798775466019463375610700074840105776873791605070092554650190486030367121011578171525759600774739890458414593857709994072516290998135846956596662071379067305011746842247628316996977338024343628757374524136260758515864509435302781735938531030576289086798942 ``` Bài này thì $n$ là tích của nhiều số nguyên tố nhỏ nên ta sẽ dùng `sage` để phân tích. ```python= from Cryptodome.Util.number import * from sage.all import * n = 580642391898843192929563856870897799650883152718761762932292482252152591279871421569162037190419036435041797739880389529593674485555792234900969402019055601781662044515999210032698275981631376651117318677368742867687180140048715627160641771118040372573575479330830092989800730105573700557717146251860588802509310534792310748898504394966263819959963273509119791037525504422606634640173277598774814099540555569257179715908642917355365791447508751401889724095964924513196281345665480688029639999472649549163147599540142367575413885729653166517595719991872223011969856259344396899748662101941230745601719730556631637 e = 65537 ct = 320721490534624434149993723527322977960556510750628354856260732098109692581338409999983376131354918370047625150454728718467998870322344980985635149656977787964380651868131740312053755501594999166365821315043312308622388016666802478485476059625888033017198083472976011719998333985531756978678758897472845358167730221506573817798467100023754709109274265835201757369829744113233607359526441007577850111228850004361838028842815813724076511058179239339760639518034583306154826603816927757236549096339501503316601078891287408682099750164720032975016814187899399273719181407940397071512493967454225665490162619270814464 def euler_totient(n): result=1 factors=factor(n) for prime, exponent in factors: result*=prime**(exponent-1)*(prime-1) return result phi=euler_totient(n) d=inverse(e,phi) decrypt = pow(ct,d,n) print(long_to_bytes(decrypt)) ``` # Public exponent ## Salty Soucre code của bài: ```python= #!/usr/bin/env python3 from Crypto.Util.number import getPrime, inverse, bytes_to_long, long_to_bytes e = 1 d = -1 while d == -1: p = getPrime(512) q = getPrime(512) phi = (p - 1) * (q - 1) d = inverse(e, phi) n = p * q flag = b"XXXXXXXXXXXXXXXXXXXXXXX" pt = bytes_to_long(flag) ct = pow(pt, e, n) print(f"n = {n}") print(f"e = {e}") print(f"ct = {ct}") pt = pow(ct, d, n) decrypted = long_to_bytes(pt) assert decrypted == flag ``` Và file ouput.txt ``` n = 110581795715958566206600392161360212579669637391437097703685154237017351570464767725324182051199901920318211290404777259728923614917211291562555864753005179326101890427669819834642007924406862482343614488768256951616086287044725034412802176312273081322195866046098595306261781788276570920467840172004530873767 e = 1 ct = 44981230718212183604274785925793145442655465025264554046028251311164494127485 ``` Do bài này $e=1$ nên $d=1$ luôn. ```python= from Cryptodome.Util.number import * ct = 44981230718212183604274785925793145442655465025264554046028251311164494127485 print(long_to_bytes(ct).decode()) ``` `crypto{saltstack_fell_for_this!}` ## Modulus Inutilis Source code của bài: ```python= #!/usr/bin/env python3 from Crypto.Util.number import getPrime, inverse, bytes_to_long, long_to_bytes e = 3 d = -1 while d == -1: p = getPrime(1024) q = getPrime(1024) phi = (p - 1) * (q - 1) d = inverse(e, phi) n = p * q flag = b"XXXXXXXXXXXXXXXXXXXXXXX" pt = bytes_to_long(flag) ct = pow(pt, e, n) print(f"n = {n}") print(f"e = {e}") print(f"ct = {ct}") pt = pow(ct, d, n) decrypted = long_to_bytes(pt) assert decrypted == flag ``` Output.txt ``` n = 17258212916191948536348548470938004244269544560039009244721959293554822498047075403658429865201816363311805874117705688359853941515579440852166618074161313773416434156467811969628473425365608002907061241714688204565170146117869742910273064909154666642642308154422770994836108669814632309362483307560217924183202838588431342622551598499747369771295105890359290073146330677383341121242366368309126850094371525078749496850520075015636716490087482193603562501577348571256210991732071282478547626856068209192987351212490642903450263288650415552403935705444809043563866466823492258216747445926536608548665086042098252335883 e = 3 ct = 243251053617903760309941844835411292373350655973075480264001352919865180151222189820473358411037759381328642957324889519192337152355302808400638052620580409813222660643570085177957 ``` Bài này số mũ lập mã $e=3$ bé nên ta có thể dùng hàm `iroot` của `gmpy2` để lấy căn bậc 3. Code giải: ```python= from Cryptodome.Util.number import * from sage.all import * from gmpy2 import * ct = 243251053617903760309941844835411292373350655973075480264001352919865180151222189820473358411037759381328642957324889519192337152355302808400638052620580409813222660643570085177957 plaintext=gmpy2.iroot(ct,3)[0] flag=long_to_bytes(plaintext) print(flag) ``` `crypto{N33d_m04R_p4dd1ng}` Nhưng cách này thì khá may rủi, thực ra lí do mà mình ra được đúng flag là vì trong bài thì $ct$ đúng bằng $m^{3}$ mà không bị reduced modulo $n$. Nếu như $m^{3}>n$ và lấy modulo $n$ thì cách trên phá sản. Nếu trường hợp như trên xảy ra thì ta sẽ cộng dần một bội nguyên dương của $n$ vào $ct$ cho tới khi ra đúng một số lập phương. ## Everything is Big Source code của bài: ```python= #!/usr/bin/env python3 from Crypto.Util.number import getPrime, bytes_to_long FLAG = b"crypto{?????????????????????????}" m = bytes_to_long(FLAG) def get_huge_RSA(): p = getPrime(1024) q = getPrime(1024) N = p*q phi = (p-1)*(q-1) while True: d = getPrime(256) e = pow(d,-1,phi) if e.bit_length() == N.bit_length(): break return N,e N, e = get_huge_RSA() c = pow(m, e, N) print(f'N = {hex(N)}') print(f'e = {hex(e)}') print(f'c = {hex(c)}') ``` Đối với bài này ta để ý rằng khóa bí mật $d$ được khởi tạo trước từ đầu và ta dễ dàng kiểm tra điều kiện của $d$ thỏa mãn để ta sử dụng Wiener's Attack. Trước tiên ta cài thư viện ở đây để attack: https://github.com/orisano/owiener Chi tiết về cơ sở toán học của thuật toán mọi người có thể xem ở đây: https://hackmd.io/@dvck13/rydikXp1ke Code giải: ```python= import owiener from Cryptodome.Util.number import * e = 0x9ab58dbc8049b574c361573955f08ea69f97ecf37400f9626d8f5ac55ca087165ce5e1f459ef6fa5f158cc8e75cb400a7473e89dd38922ead221b33bc33d6d716fb0e4e127b0fc18a197daf856a7062b49fba7a86e3a138956af04f481b7a7d481994aeebc2672e500f3f6d8c581268c2cfad4845158f79c2ef28f242f4fa8f6e573b8723a752d96169c9d885ada59cdeb6dbe932de86a019a7e8fc8aeb07748cfb272bd36d94fe83351252187c2e0bc58bb7a0a0af154b63397e6c68af4314601e29b07caed301b6831cf34caa579eb42a8c8bf69898d04b495174b5d7de0f20cf2b8fc55ed35c6ad157d3e7009f16d6b61786ee40583850e67af13e9d25be3 n = 0xb8af3d3afb893a602de4afe2a29d7615075d1e570f8bad8ebbe9b5b9076594cf06b6e7b30905b6420e950043380ea746f0a14dae34469aa723e946e484a58bcd92d1039105871ffd63ffe64534b7d7f8d84b4a569723f7a833e6daf5e182d658655f739a4e37bd9f4a44aff6ca0255cda5313c3048f56eed5b21dc8d88bf5a8f8379eac83d8523e484fa6ae8dbcb239e65d3777829a6903d779cd2498b255fcf275e5f49471f35992435ee7cade98c8e82a8beb5ce1749349caa16759afc4e799edb12d299374d748a9e3c82e1cc983cdf9daec0a2739dadcc0982c1e7e492139cbff18c5d44529407edfd8e75743d2f51ce2b58573fea6fbd4fe25154b9964d d = owiener.attack(e, n) if d is None: print("Failed") else: print("Hacked d={}".format(d)) c=0x3f984ff5244f1836ed69361f29905ca1ae6b3dcf249133c398d7762f5e277919174694293989144c9d25e940d2f66058b2289c75d1b8d0729f9a7c4564404a5fd4313675f85f31b47156068878e236c5635156b0fa21e24346c2041ae42423078577a1413f41375a4d49296ab17910ae214b45155c4570f95ca874ccae9fa80433a1ab453cbb28d780c2f1f4dc7071c93aff3924d76c5b4068a0371dff82531313f281a8acadaa2bd5078d3ddcefcb981f37ff9b8b14c7d9bf1accffe7857160982a2c7d9ee01d3e82265eec9c7401ecc7f02581fd0d912684f42d1b71df87a1ca51515aab4e58fab4da96e154ea6cdfb573a71d81b2ea4a080a1066e1bc3474 m=pow(c,d,n) print(long_to_bytes(m)) ``` ## Crossed Wires Source code của bài: ```python= from Crypto.Util.number import getPrime, long_to_bytes, bytes_to_long, inverse import math from gmpy2 import next_prime FLAG = b"crypto{????????????????????????????????????????????????}" p = getPrime(1024) q = getPrime(1024) N = p*q phi = (p-1)*(q-1) e = 0x10001 d = inverse(e, phi) my_key = (N, d) friends = 5 friend_keys = [(N, getPrime(17)) for _ in range(friends)] cipher = bytes_to_long(FLAG) for key in friend_keys: cipher = pow(cipher, key[1], key[0]) print(f"My private key: {my_key}") print(f"My Friend's public keys: {friend_keys}") print(f"Encrypted flag: {cipher}") ``` Và một file output.txt ``` My private key: (21711308225346315542706844618441565741046498277716979943478360598053144971379956916575370343448988601905854572029635846626259487297950305231661109855854947494209135205589258643517961521594924368498672064293208230802441077390193682958095111922082677813175804775628884377724377647428385841831277059274172982280545237765559969228707506857561215268491024097063920337721783673060530181637161577401589126558556182546896783307370517275046522704047385786111489447064794210010802761708615907245523492585896286374996088089317826162798278528296206977900274431829829206103227171839270887476436899494428371323874689055690729986771, 2734411677251148030723138005716109733838866545375527602018255159319631026653190783670493107936401603981429171880504360560494771017246468702902647370954220312452541342858747590576273775107870450853533717116684326976263006435733382045807971890762018747729574021057430331778033982359184838159747331236538501849965329264774927607570410347019418407451937875684373454982306923178403161216817237890962651214718831954215200637651103907209347900857824722653217179548148145687181377220544864521808230122730967452981435355334932104265488075777638608041325256776275200067541533022527964743478554948792578057708522350812154888097) My Friend's public keys: [(21711308225346315542706844618441565741046498277716979943478360598053144971379956916575370343448988601905854572029635846626259487297950305231661109855854947494209135205589258643517961521594924368498672064293208230802441077390193682958095111922082677813175804775628884377724377647428385841831277059274172982280545237765559969228707506857561215268491024097063920337721783673060530181637161577401589126558556182546896783307370517275046522704047385786111489447064794210010802761708615907245523492585896286374996088089317826162798278528296206977900274431829829206103227171839270887476436899494428371323874689055690729986771, 106979), (21711308225346315542706844618441565741046498277716979943478360598053144971379956916575370343448988601905854572029635846626259487297950305231661109855854947494209135205589258643517961521594924368498672064293208230802441077390193682958095111922082677813175804775628884377724377647428385841831277059274172982280545237765559969228707506857561215268491024097063920337721783673060530181637161577401589126558556182546896783307370517275046522704047385786111489447064794210010802761708615907245523492585896286374996088089317826162798278528296206977900274431829829206103227171839270887476436899494428371323874689055690729986771, 108533), (21711308225346315542706844618441565741046498277716979943478360598053144971379956916575370343448988601905854572029635846626259487297950305231661109855854947494209135205589258643517961521594924368498672064293208230802441077390193682958095111922082677813175804775628884377724377647428385841831277059274172982280545237765559969228707506857561215268491024097063920337721783673060530181637161577401589126558556182546896783307370517275046522704047385786111489447064794210010802761708615907245523492585896286374996088089317826162798278528296206977900274431829829206103227171839270887476436899494428371323874689055690729986771, 69557), (21711308225346315542706844618441565741046498277716979943478360598053144971379956916575370343448988601905854572029635846626259487297950305231661109855854947494209135205589258643517961521594924368498672064293208230802441077390193682958095111922082677813175804775628884377724377647428385841831277059274172982280545237765559969228707506857561215268491024097063920337721783673060530181637161577401589126558556182546896783307370517275046522704047385786111489447064794210010802761708615907245523492585896286374996088089317826162798278528296206977900274431829829206103227171839270887476436899494428371323874689055690729986771, 97117), (21711308225346315542706844618441565741046498277716979943478360598053144971379956916575370343448988601905854572029635846626259487297950305231661109855854947494209135205589258643517961521594924368498672064293208230802441077390193682958095111922082677813175804775628884377724377647428385841831277059274172982280545237765559969228707506857561215268491024097063920337721783673060530181637161577401589126558556182546896783307370517275046522704047385786111489447064794210010802761708615907245523492585896286374996088089317826162798278528296206977900274431829829206103227171839270887476436899494428371323874689055690729986771, 103231)] Encrypted flag: 20304610279578186738172766224224793119885071262464464448863461184092225736054747976985179673905441502689126216282897704508745403799054734121583968853999791604281615154100736259131453424385364324630229671185343778172807262640709301838274824603101692485662726226902121105591137437331463201881264245562214012160875177167442010952439360623396658974413900469093836794752270399520074596329058725874834082188697377597949405779039139194196065364426213208345461407030771089787529200057105746584493554722790592530472869581310117300343461207750821737840042745530876391793484035024644475535353227851321505537398888106855012746117 ``` Về cơ bản thì ở bài này ta được cho biết cả 2 cặp khóa private và public $(N,e,d)$ và được cho thêm 5 cặp public key khác từ Friends như sau: `friend_keys = [(N, getPrime(17)) for _ in range(friends)]` Điểm đáng nói ở bài này là tất cả dùng chung một modulo là $N$ cho nên ta chỉ cần phân tích được $N$ là có thể decrypt ra được flag. Để phân tích $N$ ta sử dụng thuật toán ở đây: [Factor N given d](https://www.di-mgt.com.au/rsa_factorize_n.html) ![image](https://github.com/user-attachments/assets/0857e705-f215-46b4-bf90-3a8491f8140a) Script cho thuật như sau: ```python= from Cryptodome.Util.number import * from sage.misc.prandom import randint from sage.all import * def factor_modulo(N,e,d): k=d*e-1 while True: t=k g=randint(2,N-1) % N while t%2==0: t=t//2 x=pow(g,t,N) y=gcd(x-1,N) if (x > 1 and y > 1): p=y q=int(N)//int(p) return int(p),int(q) N=21711308225346315542706844618441565741046498277716979943478360598053144971379956916575370343448988601905854572029635846626259487297950305231661109855854947494209135205589258643517961521594924368498672064293208230802441077390193682958095111922082677813175804775628884377724377647428385841831277059274172982280545237765559969228707506857561215268491024097063920337721783673060530181637161577401589126558556182546896783307370517275046522704047385786111489447064794210010802761708615907245523492585896286374996088089317826162798278528296206977900274431829829206103227171839270887476436899494428371323874689055690729986771 d=2734411677251148030723138005716109733838866545375527602018255159319631026653190783670493107936401603981429171880504360560494771017246468702902647370954220312452541342858747590576273775107870450853533717116684326976263006435733382045807971890762018747729574021057430331778033982359184838159747331236538501849965329264774927607570410347019418407451937875684373454982306923178403161216817237890962651214718831954215200637651103907209347900857824722653217179548148145687181377220544864521808230122730967452981435355334932104265488075777638608041325256776275200067541533022527964743478554948792578057708522350812154888097 e=0x10001 p,q=factor_modulo(N,e,d) print(p) print(q) ``` Nhưng trên thực tế ta không cần phải factor $N$ ra để tính private key cho bài này. Ví dụ trong trường hợp ta có sẵn $\displaystyle ( N,e,d)$ và ta muốn encrypt một plaintext sử dụng một public key khác, ta tạm gọi public key đó là $\displaystyle e'$. Thì lúc này ta có $$\begin{equation*} c=m^{e'} \end{equation*}$$ Ta đã biết $\displaystyle e,d$ thì ta có thể tính được $\displaystyle ed-1=k\varphi ( N)$ và nếu ta tính nghịch đảo của $\displaystyle e'$ theo modulo $\displaystyle k\varphi ( N)$ là $\displaystyle d'$ chẳng hạn thì ta sẽ có $$\begin{equation*} e'd'\equiv 1(\bmod k\varphi ( N)) \end{equation*}$$ Lúc này ta được $$\begin{equation*} c^{d'} =m^{e'd'} \equiv m^{1+k\varphi ( N)} \equiv m\bmod N \end{equation*}$$ Ta sử dụng tính chất $\displaystyle a^{b} \equiv a^{c}\bmod N$ thì $\displaystyle b\equiv c(\bmod \varphi ( N))$ và ngoài ra do $\displaystyle ( m,N) =1$ cho nên $\displaystyle \left( m^{k} ,N\right) =1$ và ta có được đẳng thức ở trên. Cuối cùng script giải bài này sẽ như sau: ```python= from Cryptodome.Util.number import * from sage.misc.prandom import randint from sage.all import * N=21711308225346315542706844618441565741046498277716979943478360598053144971379956916575370343448988601905854572029635846626259487297950305231661109855854947494209135205589258643517961521594924368498672064293208230802441077390193682958095111922082677813175804775628884377724377647428385841831277059274172982280545237765559969228707506857561215268491024097063920337721783673060530181637161577401589126558556182546896783307370517275046522704047385786111489447064794210010802761708615907245523492585896286374996088089317826162798278528296206977900274431829829206103227171839270887476436899494428371323874689055690729986771 d=2734411677251148030723138005716109733838866545375527602018255159319631026653190783670493107936401603981429171880504360560494771017246468702902647370954220312452541342858747590576273775107870450853533717116684326976263006435733382045807971890762018747729574021057430331778033982359184838159747331236538501849965329264774927607570410347019418407451937875684373454982306923178403161216817237890962651214718831954215200637651103907209347900857824722653217179548148145687181377220544864521808230122730967452981435355334932104265488075777638608041325256776275200067541533022527964743478554948792578057708522350812154888097 e=0x10001 keys = [106979, 108533, 69557, 97117, 103231] encflag=20304610279578186738172766224224793119885071262464464448863461184092225736054747976985179673905441502689126216282897704508745403799054734121583968853999791604281615154100736259131453424385364324630229671185343778172807262640709301838274824603101692485662726226902121105591137437331463201881264245562214012160875177167442010952439360623396658974413900469093836794752270399520074596329058725874834082188697377597949405779039139194196065364426213208345461407030771089787529200057105746584493554722790592530472869581310117300343461207750821737840042745530876391793484035024644475535353227851321505537398888106855012746117 prod=1 for k in keys: prod*=k dd=inverse(prod,e*d-1) m=pow(encflag,dd,N) print(long_to_bytes(m)) ``` ```crypto{3ncrypt_y0ur_s3cr3t_w1th_y0ur_fr1end5_publ1c_k3y}``` ## Everything is Still Big Bài cho ta một file python ```python= #!/usr/bin/env python3 from Crypto.Util.number import getPrime, bytes_to_long, inverse from random import getrandbits from math import gcd FLAG = b"crypto{?????????????????????????????????????}" m = bytes_to_long(FLAG) def get_huge_RSA(): p = getPrime(1024) q = getPrime(1024) N = p*q phi = (p-1)*(q-1) while True: d = getrandbits(512) if (3*d)**4 > N and gcd(d,phi) == 1: e = inverse(d, phi) break return N,e N, e = get_huge_RSA() c = pow(m, e, N) print(f'N = {hex(N)}') print(f'e = {hex(e)}') print(f'c = {hex(c)}') ``` Và một file output.txt ``` N = 0xb12746657c720a434861e9a4828b3c89a6b8d4a1bd921054e48d47124dbcc9cfcdcc39261c5e93817c167db818081613f57729e0039875c72a5ae1f0bc5ef7c933880c2ad528adbc9b1430003a491e460917b34c4590977df47772fab1ee0ab251f94065ab3004893fe1b2958008848b0124f22c4e75f60ed3889fb62e5ef4dcc247a3d6e23072641e62566cd96ee8114b227b8f498f9a578fc6f687d07acdbb523b6029c5bbeecd5efaf4c4d35304e5e6b5b95db0e89299529eb953f52ca3247d4cd03a15939e7d638b168fd00a1cb5b0cc5c2cc98175c1ad0b959c2ab2f17f917c0ccee8c3fe589b4cb441e817f75e575fc96a4fe7bfea897f57692b050d2b e = 0x9d0637faa46281b533e83cc37e1cf5626bd33f712cc1948622f10ec26f766fb37b9cd6c7a6e4b2c03bce0dd70d5a3a28b6b0c941d8792bc6a870568790ebcd30f40277af59e0fd3141e272c48f8e33592965997c7d93006c27bf3a2b8fb71831dfa939c0ba2c7569dd1b660efc6c8966e674fbe6e051811d92a802c789d895f356ceec9722d5a7b617d21b8aa42dd6a45de721953939a5a81b8dffc9490acd4f60b0c0475883ff7e2ab50b39b2deeedaefefffc52ae2e03f72756d9b4f7b6bd85b1a6764b31312bc375a2298b78b0263d492205d2a5aa7a227abaf41ab4ea8ce0e75728a5177fe90ace36fdc5dba53317bbf90e60a6f2311bb333bf55ba3245f c = 0xa3bce6e2e677d7855a1a7819eb1879779d1e1eefa21a1a6e205c8b46fdc020a2487fdd07dbae99274204fadda2ba69af73627bdddcb2c403118f507bca03cb0bad7a8cd03f70defc31fa904d71230aab98a10e155bf207da1b1cac1503f48cab3758024cc6e62afe99767e9e4c151b75f60d8f7989c152fdf4ff4b95ceed9a7065f38c68dee4dd0da503650d3246d463f504b36e1d6fafabb35d2390ecf0419b2bb67c4c647fb38511b34eb494d9289c872203fa70f4084d2fa2367a63a8881b74cc38730ad7584328de6a7d92e4ca18098a15119baee91237cea24975bdfc19bdbce7c1559899a88125935584cd37c8dd31f3f2b4517eefae84e7e588344fa5 ``` Ở bài này ta thấy khóa bí mật $d$ vẫn khá nhỏ so với modulo $N$ nhưng có thêm điều kiện $\displaystyle 3d^{4} >N$ nên ta không thể sử dụng Wiener's Attack được mà phải chuyển sang sử dụng một thuật toán khác. Ở đây mình sử dụng thuật Boneh & Durfee RSA Low Private Exponent Recovery. Cụ thể code để implement thuật như dưới đây, được mình lấy từ trang https://github.com/jvdsn/crypto-attacks/blob/master/attacks/rsa/boneh_durfee.py ```python= import logging import os import sys from sage.all import RR from sage.all import ZZ path = os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(os.path.abspath(__file__))))) if sys.path[1] != path: sys.path.insert(1, path) from attacks.factorization import known_phi from shared.small_roots import herrmann_may def attack(N, e, factor_bit_length, partial_p=None, delta=0.25, m=1, t=None): """ Recovers the prime factors if the private exponent is too small. This implementation exploits knowledge of least significant bits of prime factors, if available. More information: Boneh D., Durfee G., "Cryptanalysis of RSA with Private Key d Less than N^0.292" :param N: the modulus :param e: the public exponent :param factor_bit_length: the bit length of the prime factors :param partial_p: the partial prime factor p (PartialInteger) (default: None) :param delta: a predicted bound on the private exponent (d < N^delta) (default: 0.25) :param m: the m value to use for the small roots method (default: 1) :param t: the t value to use for the small roots method (default: automatically computed using m) :return: a tuple containing the prime factors, or None if the factors were not found """ # Use additional information about factors to speed up Boneh-Durfee. p_lsb, p_lsb_bit_length = (0, 0) if partial_p is None else partial_p.get_known_lsb() q_lsb = (pow(p_lsb, -1, 2 ** p_lsb_bit_length) * N) % (2 ** p_lsb_bit_length) A = ((N >> p_lsb_bit_length) + pow(2, -p_lsb_bit_length, e) * (p_lsb * q_lsb - p_lsb - q_lsb + 1)) x, y = ZZ["x", "y"].gens() f = x * (A + y) + pow(2, -p_lsb_bit_length, e) X = int(RR(e) ** delta) Y = int(2 ** (factor_bit_length - p_lsb_bit_length + 1)) t = int((1 - 2 * delta) * m) if t is None else t logging.info(f"Trying {m = }, {t = }...") for x0, y0 in herrmann_may.modular_bivariate(f, e, m, t, X, Y): z = int(f(x0, y0)) if z % e == 0: k = pow(x0, -1, e) s = (N + 1 + k) % e phi = N - s + 1 factors = known_phi.factorize(N, phi) if factors: return factors return None def attack_multi_prime(N, e, factor_bit_length, factors, delta=0.25, m=1, t=None): """ Recovers the prime factors if the private exponent is too small. This method works for a modulus consisting of any number of primes. :param N: the modulus :param e: the public exponent :param factor_bit_length: the bit length of the prime factors :param factors: the number of prime factors in the modulus :param delta: a predicted bound on the private exponent (d < n^delta) (default: 0.25) :param m: the m value to use for the small roots method (default: 1) :param t: the t value to use for the small roots method (default: automatically computed using m) :return: a tuple containing the prime factors, or None if the factors were not found """ x, y = ZZ["x", "y"].gens() A = N + 1 f = x * (A + y) + 1 X = int(RR(e) ** delta) Y = int(2 ** ((factors - 1) * factor_bit_length + 1)) t = int((1 - 2 * delta) * m) if t is None else t logging.info(f"Trying {m = }, {t = }...") for x0, y0 in herrmann_may.modular_bivariate(f, e, m, t, X, Y): z = int(f(x0, y0)) if z % e == 0: k = pow(x0, -1, e) s = (N + 1 + k) % e phi = N - s + 1 factors = known_phi.factorize_multi_prime(N, phi) if factors: return factors return None import logging # Some logging so we can see what's happening. logging.basicConfig(level=logging.DEBUG) N = 0xb12746657c720a434861e9a4828b3c89a6b8d4a1bd921054e48d47124dbcc9cfcdcc39261c5e93817c167db818081613f57729e0039875c72a5ae1f0bc5ef7c933880c2ad528adbc9b1430003a491e460917b34c4590977df47772fab1ee0ab251f94065ab3004893fe1b2958008848b0124f22c4e75f60ed3889fb62e5ef4dcc247a3d6e23072641e62566cd96ee8114b227b8f498f9a578fc6f687d07acdbb523b6029c5bbeecd5efaf4c4d35304e5e6b5b95db0e89299529eb953f52ca3247d4cd03a15939e7d638b168fd00a1cb5b0cc5c2cc98175c1ad0b959c2ab2f17f917c0ccee8c3fe589b4cb441e817f75e575fc96a4fe7bfea897f57692b050d2b e = 0x9d0637faa46281b533e83cc37e1cf5626bd33f712cc1948622f10ec26f766fb37b9cd6c7a6e4b2c03bce0dd70d5a3a28b6b0c941d8792bc6a870568790ebcd30f40277af59e0fd3141e272c48f8e33592965997c7d93006c27bf3a2b8fb71831dfa939c0ba2c7569dd1b660efc6c8966e674fbe6e051811d92a802c789d895f356ceec9722d5a7b617d21b8aa42dd6a45de721953939a5a81b8dffc9490acd4f60b0c0475883ff7e2ab50b39b2deeedaefefffc52ae2e03f72756d9b4f7b6bd85b1a6764b31312bc375a2298b78b0263d492205d2a5aa7a227abaf41ab4ea8ce0e75728a5177fe90ace36fdc5dba53317bbf90e60a6f2311bb333bf55ba3245f p_bits = 1024 delta = 0.26 p, q = attack(N, e, p_bits, delta=delta, m=3) assert p * q == N print(f"Found {p = } and {q = }") ``` Sau khi tìm được $p,q$ thì mình tìm $d$ để giải ra flag thôi ```python= from Cryptodome.Util.number import * p=126941806460244095377115101056215170200213929484090514615615360791047815508282999312547430020357429932308768712158161906404559758053111268332560036207583087350177765905028171368043071041697143783557751018420251412743117633405829486334952312669390185416378995607092112979722242788438125727258195819223984881293 q=176171647623796415963359037459080158279832338949959164916683927127298628490481547783271812783698644240568426097637418877451963005025506022174220789400439434207167210194263661330803801184790705595672502832081604208722809411817374316086936064983248582792693864440342630864686435882656704880417413599728301262999 N = 0xb12746657c720a434861e9a4828b3c89a6b8d4a1bd921054e48d47124dbcc9cfcdcc39261c5e93817c167db818081613f57729e0039875c72a5ae1f0bc5ef7c933880c2ad528adbc9b1430003a491e460917b34c4590977df47772fab1ee0ab251f94065ab3004893fe1b2958008848b0124f22c4e75f60ed3889fb62e5ef4dcc247a3d6e23072641e62566cd96ee8114b227b8f498f9a578fc6f687d07acdbb523b6029c5bbeecd5efaf4c4d35304e5e6b5b95db0e89299529eb953f52ca3247d4cd03a15939e7d638b168fd00a1cb5b0cc5c2cc98175c1ad0b959c2ab2f17f917c0ccee8c3fe589b4cb441e817f75e575fc96a4fe7bfea897f57692b050d2b e = 0x9d0637faa46281b533e83cc37e1cf5626bd33f712cc1948622f10ec26f766fb37b9cd6c7a6e4b2c03bce0dd70d5a3a28b6b0c941d8792bc6a870568790ebcd30f40277af59e0fd3141e272c48f8e33592965997c7d93006c27bf3a2b8fb71831dfa939c0ba2c7569dd1b660efc6c8966e674fbe6e051811d92a802c789d895f356ceec9722d5a7b617d21b8aa42dd6a45de721953939a5a81b8dffc9490acd4f60b0c0475883ff7e2ab50b39b2deeedaefefffc52ae2e03f72756d9b4f7b6bd85b1a6764b31312bc375a2298b78b0263d492205d2a5aa7a227abaf41ab4ea8ce0e75728a5177fe90ace36fdc5dba53317bbf90e60a6f2311bb333bf55ba3245f c = 0xa3bce6e2e677d7855a1a7819eb1879779d1e1eefa21a1a6e205c8b46fdc020a2487fdd07dbae99274204fadda2ba69af73627bdddcb2c403118f507bca03cb0bad7a8cd03f70defc31fa904d71230aab98a10e155bf207da1b1cac1503f48cab3758024cc6e62afe99767e9e4c151b75f60d8f7989c152fdf4ff4b95ceed9a7065f38c68dee4dd0da503650d3246d463f504b36e1d6fafabb35d2390ecf0419b2bb67c4c647fb38511b34eb494d9289c872203fa70f4084d2fa2367a63a8881b74cc38730ad7584328de6a7d92e4ca18098a15119baee91237cea24975bdfc19bdbce7c1559899a88125935584cd37c8dd31f3f2b4517eefae84e7e588344fa5 phi=(p-1)*(q-1) d=inverse(e,phi) m=pow(c,d,N) print(long_to_bytes(m)) ``` ```crypto{bon3h5_4tt4ck_i5_sr0ng3r_th4n_w13n3r5}``` Về cơ sở toán học của thuật toán trên, mọi người tham khảo tại đây: https://link.springer.com/content/pdf/10.1007/3-540-48910-X_1.pdf ## Endless Emails Chall cho ta một file python như sau: ```python= #!/usr/bin/env python3 from Crypto.Util.number import bytes_to_long, getPrime from secret import messages def RSA_encrypt(message): m = bytes_to_long(message) p = getPrime(1024) q = getPrime(1024) N = p * q e = 3 c = pow(m, e, N) return N, e, c for m in messages: N, e, c = RSA_encrypt(m) print(f"n = {N}") print(f"e = {e}") print(f"c = {c}") ``` Và một file output.txt ```= n = 14528915758150659907677315938876872514853653132820394367681510019000469589767908107293777996420037715293478868775354645306536953789897501630398061779084810058931494642860729799059325051840331449914529594113593835549493208246333437945551639983056810855435396444978249093419290651847764073607607794045076386643023306458718171574989185213684263628336385268818202054811378810216623440644076846464902798568705083282619513191855087399010760232112434412274701034094429954231366422968991322244343038458681255035356984900384509158858007713047428143658924970374944616430311056440919114824023838380098825914755712289724493770021 e = 3 c = 6965891612987861726975066977377253961837139691220763821370036576350605576485706330714192837336331493653283305241193883593410988132245791554283874785871849223291134571366093850082919285063130119121338290718389659761443563666214229749009468327825320914097376664888912663806925746474243439550004354390822079954583102082178617110721589392875875474288168921403550415531707419931040583019529612270482482718035497554779733578411057633524971870399893851589345476307695799567919550426417015815455141863703835142223300228230547255523815097431420381177861163863791690147876158039619438793849367921927840731088518955045807722225 n = 20463913454649855046677206889944639231694511458416906994298079596685813354570085475890888433776403011296145408951323816323011550738170573801417972453504044678801608709931200059967157605416809387753258251914788761202456830940944486915292626560515250805017229876565916349963923702612584484875113691057716315466239062005206014542088484387389725058070917118549621598629964819596412564094627030747720659155558690124005400257685883230881015636066183743516494701900125788836869358634031031172536767950943858472257519195392986989232477630794600444813136409000056443035171453870906346401936687214432176829528484662373633624123 e = 3 c = 5109363605089618816120178319361171115590171352048506021650539639521356666986308721062843132905170261025772850941702085683855336653472949146012700116070022531926476625467538166881085235022484711752960666438445574269179358850309578627747024264968893862296953506803423930414569834210215223172069261612934281834174103316403670168299182121939323001232617718327977313659290755318972603958579000300780685344728301503641583806648227416781898538367971983562236770576174308965929275267929379934367736694110684569576575266348020800723535121638175505282145714117112442582416208209171027273743686645470434557028336357172288865172 n = 19402640770593345339726386104915705450969517850985511418263141255686982818547710008822417349818201858549321868878490314025136645036980129976820137486252202687238348587398336652955435182090722844668488842986318211649569593089444781595159045372322540131250208258093613844753021272389255069398553523848975530563989367082896404719544411946864594527708058887475595056033713361893808330341623804367785721774271084389159493974946320359512776328984487126583015777989991635428744050868653379191842998345721260216953918203248167079072442948732000084754225272238189439501737066178901505257566388862947536332343196537495085729147 e = 3 c = 5603386396458228314230975500760833991383866638504216400766044200173576179323437058101562931430558738148852367292802918725271632845889728711316688681080762762324367273332764959495900563756768440309595248691744845766607436966468714038018108912467618638117493367675937079141350328486149333053000366933205635396038539236203203489974033629281145427277222568989469994178084357460160310598260365030056631222346691527861696116334946201074529417984624304973747653407317290664224507485684421999527164122395674469650155851869651072847303136621932989550786722041915603539800197077294166881952724017065404825258494318993054344153 n = 12005639978012754274325188681720834222130605634919280945697102906256738419912110187245315232437501890545637047506165123606573171374281507075652554737014979927883759915891863646221205835211640845714836927373844277878562666545230876640830141637371729405545509920889968046268135809999117856968692236742804637929866632908329522087977077849045608566911654234541526643235586433065170392920102840518192803854740398478305598092197183671292154743153130012885747243219372709669879863098708318993844005566984491622761795349455404952285937152423145150066181043576492305166964448141091092142224906843816547235826717179687198833961 e = 3 c = 1522280741383024774933280198410525846833410931417064479278161088248621390305797210285777845359812715909342595804742710152832168365433905718629465545306028275498667935929180318276445229415104842407145880223983428713335709038026249381363564625791656631137936935477777236936508600353416079028339774876425198789629900265348122040413865209592074731028757972968635601695468594123523892918747882221891834598896483393711851510479989203644477972694520237262271530260496342247355761992646827057846109181410462131875377404309983072358313960427035348425800940661373272947647516867525052504539561289941374722179778872627956360577 n = 17795451956221451086587651307408104001363221003775928432650752466563818944480119932209305765249625841644339021308118433529490162294175590972336954199870002456682453215153111182451526643055812311071588382409549045943806869173323058059908678022558101041630272658592291327387549001621625757585079662873501990182250368909302040015518454068699267914137675644695523752851229148887052774845777699287718342916530122031495267122700912518207571821367123013164125109174399486158717604851125244356586369921144640969262427220828940652994276084225196272504355264547588369516271460361233556643313911651916709471353368924621122725823 e = 3 c = 8752507806125480063647081749506966428026005464325535765874589376572431101816084498482064083887400646438977437273700004934257274516197148448425455243811009944321764771392044345410680448204581679548854193081394891841223548418812679441816502910830861271884276608891963388657558218620911858230760629700918375750796354647493524576614017731938584618983084762612414591830024113057983483156974095503392359946722756364412399187910604029583464521617256125933111786441852765229820406911991809039519015434793656710199153380699319611499255869045311421603167606551250174746275803467549814529124250122560661739949229005127507540805 n = 25252721057733555082592677470459355315816761410478159901637469821096129654501579313856822193168570733800370301193041607236223065376987811309968760580864569059669890823406084313841678888031103461972888346942160731039637326224716901940943571445217827960353637825523862324133203094843228068077462983941899571736153227764822122334838436875488289162659100652956252427378476004164698656662333892963348126931771536472674447932268282205545229907715893139346941832367885319597198474180888087658441880346681594927881517150425610145518942545293750127300041942766820911120196262215703079164895767115681864075574707999253396530263 e = 3 c = 23399624135645767243362438536844425089018405258626828336566973656156553220156563508607371562416462491581383453279478716239823054532476006642583363934314982675152824147243749715830794488268846671670287617324522740126594148159945137948643597981681529145611463534109482209520448640622103718682323158039797577387254265854218727476928164074249568031493984825273382959147078839665114417896463735635546290504843957780546550577300001452747760982468547756427137284830133305010038339400230477403836856663883956463830571934657200851598986174177386323915542033293658596818231793744261192870485152396793393026198817787033127061749 n = 19833203629283018227011925157509157967003736370320129764863076831617271290326613531892600790037451229326924414757856123643351635022817441101879725227161178559229328259469472961665857650693413215087493448372860837806619850188734619829580286541292997729705909899738951228555834773273676515143550091710004139734080727392121405772911510746025807070635102249154615454505080376920778703360178295901552323611120184737429513669167641846902598281621408629883487079110172218735807477275590367110861255756289520114719860000347219161944020067099398239199863252349401303744451903546571864062825485984573414652422054433066179558897 e = 3 c = 15239683995712538665992887055453717247160229941400011601942125542239446512492703769284448009141905335544729440961349343533346436084176947090230267995060908954209742736573986319254695570265339469489948102562072983996668361864286444602534666284339466797477805372109723178841788198177337648499899079471221924276590042183382182326518312979109378616306364363630519677884849945606288881683625944365927809405420540525867173639222696027472336981838588256771671910217553150588878434061862840893045763456457939944572192848992333115479951110622066173007227047527992906364658618631373790704267650950755276227747600169403361509144 ``` Như đã thấy trong bài thì đây là hệ mật mã RSA nhưng có số mũ lập mã $\displaystyle e$ bé, cụ thể là $\displaystyle e=3$. Ngoài ra ta còn biết thêm thông tin là có một vài plaintext trong số 5 plaintext ở trên bị lặp lại tức là có một số $\displaystyle m$ để mà $$\begin{equation*} c_{i} =m^{3}(\bmod n_{i}) \end{equation*}$$ trong đó $\displaystyle i$ chạy trên một họ tập hợp nào đó. Bây giờ ta sẽ nói về thuật toán để giải quyết bài toán trên. Đầu tiên ta giả sử có tình huống mà ba người tham gia chọn ba khóa công khai là $\displaystyle ( n_{1} ,e) ,( n_{2} ,e) ,( n_{3} ,e)$ với $\displaystyle e=3$. Và ta muốn gửi một đoạn tin nhắn $\displaystyle x$ đến cho cả ba người đó thì ta sẽ sử dụng khóa công khai là $\displaystyle e$ để tính toán $\displaystyle c_{1} \equiv x^{3}\bmod n_{1}$ và tương tự như vậy với $\displaystyle c_{2} ,c_{3}$. Nhiệm vụ của ta bây giờ là sử dụng định lí thặng dư Trung Hoa để tính toán $$\begin{equation*} \begin{cases} m\equiv c_{1}(\bmod n_{1})\\ m\equiv c_{2}(\bmod n_{2})\\ m\equiv c_{3}(\bmod n_{3}) \end{cases} \end{equation*}$$ Hệ sẽ có họ nghiệm duy nhất theo modulo $\displaystyle n_{1} n_{2} n_{3}$ dẫn tới $\displaystyle m=x^{3} +kn_{1} n_{2} n_{3} ,k\in \mathbb{Z}^{*}$ nhưng ta có $\displaystyle x\leqslant n_{i} ,\forall i$ cho nên $\displaystyle x^{3} \leqslant n_{1} n_{2} n_{3}$ kéo theo $\displaystyle m=x^{3}$. Như vậy ta sẽ chọn ra cặp 3 số bất kì từ 5 số ở trên và giải hệ phương trình thặng dư cho tới khi ra được flag. Tổng cộng ta cần giải $\displaystyle \binom{7}{3}$ hệ phương trình. Thuật toán trên là một trường hợp đặc biệt của Hastad Broadcast Attack Code giải như sau : ```python= from Cryptodome.Util.number import * from sage.all import * from itertools import combinations from sympy.ntheory.modular import crt from gmpy2 import iroot def extract_nc_pairs(file_path): nc_pairs = [] with open(file_path, 'r') as file: lines = file.readlines() n = c = None for line in lines: line = line.strip() if line.startswith("n ="): n = int(line.split("=", 1)[1].strip()) elif line.startswith("c ="): c = int(line.split("=", 1)[1].strip()) if n is not None and c is not None: nc_pairs.append((n, c)) n = c = None return nc_pairs def find_m_with_nc(nc_pairs): for combo in combinations(nc_pairs, 3): moduli = [n for n, c in combo] remainders = [c for n, c in combo] result = crt(moduli, remainders) if result is not None: m = result[0] root, is_exact = iroot(m, 3) if is_exact: decode_message=long_to_bytes(int(root)) print(f"m = {m}, cube root = {int(root)}") print(f"Flag là: {decode_message}") file_path = "/home/duc112006/cryptohack/RSA/publicexp/output.txt" nc_pairs = extract_nc_pairs(file_path) find_m_with_nc(nc_pairs) ``` # Primes Part 2 ## Infinite Descent Chall cho ta một file python như sau : ```python= #!/usr/bin/env python3 import random from Crypto.Util.number import bytes_to_long, isPrime FLAG = b"crypto{???????????????????}" def getPrimes(bitsize): r = random.getrandbits(bitsize) p, q = r, r while not isPrime(p): p += random.getrandbits(bitsize//4) while not isPrime(q): q += random.getrandbits(bitsize//8) return p, q m = bytes_to_long(FLAG) p, q = getPrimes(2048) n = p * q e = 0x10001 c = pow(m, e, n) print(f"n = {n}") print(f"e = {e}") print(f"c = {c}") ``` Và một file output.txt ``` n = 383347712330877040452238619329524841763392526146840572232926924642094891453979246383798913394114305368360426867021623649667024217266529000859703542590316063318592391925062014229671423777796679798747131250552455356061834719512365575593221216339005132464338847195248627639623487124025890693416305788160905762011825079336880567461033322240015771102929696350161937950387427696385850443727777996483584464610046380722736790790188061964311222153985614287276995741553706506834906746892708903948496564047090014307484054609862129530262108669567834726352078060081889712109412073731026030466300060341737504223822014714056413752165841749368159510588178604096191956750941078391415634472219765129561622344109769892244712668402761549412177892054051266761597330660545704317210567759828757156904778495608968785747998059857467440128156068391746919684258227682866083662345263659558066864109212457286114506228470930775092735385388316268663664139056183180238043386636254075940621543717531670995823417070666005930452836389812129462051771646048498397195157405386923446893886593048680984896989809135802276892911038588008701926729269812453226891776546037663583893625479252643042517196958990266376741676514631089466493864064316127648074609662749196545969926051 e = 65537 c = 98280456757136766244944891987028935843441533415613592591358482906016439563076150526116369842213103333480506705993633901994107281890187248495507270868621384652207697607019899166492132408348789252555196428608661320671877412710489782358282011364127799563335562917707783563681920786994453004763755404510541574502176243896756839917991848428091594919111448023948527766368304503100650379914153058191140072528095898576018893829830104362124927140555107994114143042266758709328068902664037870075742542194318059191313468675939426810988239079424823495317464035252325521917592045198152643533223015952702649249494753395100973534541766285551891859649320371178562200252228779395393974169736998523394598517174182142007480526603025578004665936854657294541338697513521007818552254811797566860763442604365744596444735991732790926343720102293453429936734206246109968817158815749927063561835274636195149702317415680401987150336994583752062565237605953153790371155918439941193401473271753038180560129784192800351649724465553733201451581525173536731674524145027931923204961274369826379325051601238308635192540223484055096203293400419816024111797903442864181965959247745006822690967920957905188441550106930799896292835287867403979631824085790047851383294389 ``` Vấn đề của bài này nằm ở đoạn code: ```p += random.getrandbits(bitsize//4)``` và ```q += random.getrandbits(bitsize//8)```. Tức là nếu như $p$ không là số nguyên tố thì khi đó ta sẽ cộng thêm $p$ bởi một giá có độ lớn bằng với `bitsize//4` và tiếp tục cho tới khi $p$ là số nguyên tố. Với cách định nghĩa $p,q$ như vậy thì ta có thể nhận thấy rằng $p,q$ khá gần nhau và ta có thể thử khai thác giả thiết này để phân tích được $n$. Tham khảo tại link sau: [RSA and prime difference](https://crypto.stackexchange.com/questions/5262/rsa-and-prime-difference) Sau một hồi tìm hiểu thì mình biết được bài này sẽ sử dụng thuật Fermat's Factorization tại đây: [Fermat's Method](https://eprint.iacr.org/2009/318.pdf) ![image](https://github.com/user-attachments/assets/02673fc8-bdf8-40f4-a1c6-897c89151d53) ```python= from Cryptodome.Util.number import * from sage.all import * def fermat_factor(n): a=ceil(sqrt(n)) b2= a**2 - n while not b2.is_square(): a+=1 b2=a**2-n b=sqrt(b2) p=int(a-b) q=int(a+b) return [p,q] n = 383347712330877040452238619329524841763392526146840572232926924642094891453979246383798913394114305368360426867021623649667024217266529000859703542590316063318592391925062014229671423777796679798747131250552455356061834719512365575593221216339005132464338847195248627639623487124025890693416305788160905762011825079336880567461033322240015771102929696350161937950387427696385850443727777996483584464610046380722736790790188061964311222153985614287276995741553706506834906746892708903948496564047090014307484054609862129530262108669567834726352078060081889712109412073731026030466300060341737504223822014714056413752165841749368159510588178604096191956750941078391415634472219765129561622344109769892244712668402761549412177892054051266761597330660545704317210567759828757156904778495608968785747998059857467440128156068391746919684258227682866083662345263659558066864109212457286114506228470930775092735385388316268663664139056183180238043386636254075940621543717531670995823417070666005930452836389812129462051771646048498397195157405386923446893886593048680984896989809135802276892911038588008701926729269812453226891776546037663583893625479252643042517196958990266376741676514631089466493864064316127648074609662749196545969926051 e = 65537 c = 98280456757136766244944891987028935843441533415613592591358482906016439563076150526116369842213103333480506705993633901994107281890187248495507270868621384652207697607019899166492132408348789252555196428608661320671877412710489782358282011364127799563335562917707783563681920786994453004763755404510541574502176243896756839917991848428091594919111448023948527766368304503100650379914153058191140072528095898576018893829830104362124927140555107994114143042266758709328068902664037870075742542194318059191313468675939426810988239079424823495317464035252325521917592045198152643533223015952702649249494753395100973534541766285551891859649320371178562200252228779395393974169736998523394598517174182142007480526603025578004665936854657294541338697513521007818552254811797566860763442604365744596444735991732790926343720102293453429936734206246109968817158815749927063561835274636195149702317415680401987150336994583752062565237605953153790371155918439941193401473271753038180560129784192800351649724465553733201451581525173536731674524145027931923204961274369826379325051601238308635192540223484055096203293400419816024111797903442864181965959247745006822690967920957905188441550106930799896292835287867403979631824085790047851383294389 result=fermat_factor(n) p=result[0] q=result[1] phi=(p-1)*(q-1) d=int(inverse(e,phi)) m=pow(int(c),d,int(n)) print(long_to_bytes(m)) ``` ```crypto{f3rm47_w45_4_g3n1u5}``` (các bài tập về RSA trên CryptoHack cũng có khá lâu rồi nên có một số bài tác giả sau khi solve xong thì đẩy database factor(n) lên FactorDB. Kết quả là có vài bài trong phần bài tập giải theo cách này được :))) bài này là một trong số đó) ## Marin's Secrets Bài cho ta một file source code như sau: ```python= #!/usr/bin/env python3 import random from Crypto.Util.number import bytes_to_long from secret import secrets, flag def get_prime(secret): prime = 1 for _ in range(secret): prime = prime << 1 return prime - 1 random.shuffle(secrets) m = bytes_to_long(flag) p = get_prime(secrets[0]) q = get_prime(secrets[1]) n = p * q e = 0x10001 c = pow(m, e, n) print(f"n = {n}") print(f"e = {e}") print(f"c = {c}") ``` Và file output.txt ``` n: 658416274830184544125027519921443515789888264156074733099244040126213682497714032798116399288176502462829255784525977722903018714434309698108208388664768262754316426220651576623731617882923164117579624827261244506084274371250277849351631679441171018418018498039996472549893150577189302871520311715179730714312181456245097848491669795997289830612988058523968384808822828370900198489249243399165125219244753790779764466236965135793576516193213175061401667388622228362042717054014679032953441034021506856017081062617572351195418505899388715709795992029559042119783423597324707100694064675909238717573058764118893225111602703838080618565401139902143069901117174204252871948846864436771808616432457102844534843857198735242005309073939051433790946726672234643259349535186268571629077937597838801337973092285608744209951533199868228040004432132597073390363357892379997655878857696334892216345070227646749851381208554044940444182864026513709449823489593439017366358869648168238735087593808344484365136284219725233811605331815007424582890821887260682886632543613109252862114326372077785369292570900594814481097443781269562647303671428895764224084402259605109600363098950091998891375812839523613295667253813978434879172781217285652895469194181218343078754501694746598738215243769747956572555989594598180639098344891175879455994652382137038240166358066403475457 e: 65537 c: 400280463088930432319280359115194977582517363610532464295210669530407870753439127455401384569705425621445943992963380983084917385428631223046908837804126399345875252917090184158440305503817193246288672986488987883177380307377025079266030262650932575205141853413302558460364242355531272967481409414783634558791175827816540767545944534238189079030192843288596934979693517964655661507346729751987928147021620165009965051933278913952899114253301044747587310830419190623282578931589587504555005361571572561916866063458812965314474160499067525067495140150092119620928363007467390920130717521169105167963364154636472055084012592138570354390246779276003156184676298710746583104700516466091034510765027167956117869051938116457370384737440965109619578227422049806566060571831017610877072484262724789571076529586427405780121096546942812322324807145137017942266863534989082115189065560011841150908380937354301243153206428896320576609904361937035263985348984794208198892615898907005955403529470847124269512316191753950203794578656029324506688293446571598506042198219080325747328636232040936761788558421528960279832802127562115852304946867628316502959562274485483867481731149338209009753229463924855930103271197831370982488703456463385914801246828662212622006947380115549529820197355738525329885232170215757585685484402344437894981555179129287164971002033759724456 ``` Phân tích đoạn code trên: Hàm `get_prime` sinh ra các số nguyên có dạng $\displaystyle 2^{secret} -1$ và số $\displaystyle n$ của ta cũng có dạng $\displaystyle \left( 2^{a} -1\right)\left( 2^{b} -1\right)$ với $\displaystyle a,b$ được lấy ngẫu nhiên từ secrets. Vấn đề ở đây ta không biết $\displaystyle 2^{a} -1$ và $\displaystyle 2^{b} -1$ có phải là số nguyên tố hay không. Điều kiện cần để $\displaystyle 2^{a} -1$ là một số nguyên tố đó chính là $\displaystyle a$ cũng phải là số nguyên tố. Vậy ta cần phải xác định cách để phân tích $\displaystyle n$ nếu ta biết $\displaystyle n$ có dạng $\displaystyle n=\left( 2^{a} -1\right)\left( 2^{b} -1\right)$. Trước tiên ta đi giải quyết bài toán dễ trước đó chính là giả sử $\displaystyle 2^{a} -1,2^{b} -1$ đều là các số nguyên tố thì ta sẽ phân tích như thế nào. Cách đầu tiên là xài [FactorDb](https://factordb.com/index.php?query=658416274830184544125027519921443515789888264156074733099244040126213682497714032798116399288176502462829255784525977722903018714434309698108208388664768262754316426220651576623731617882923164117579624827261244506084274371250277849351631679441171018418018498039996472549893150577189302871520311715179730714312181456245097848491669795997289830612988058523968384808822828370900198489249243399165125219244753790779764466236965135793576516193213175061401667388622228362042717054014679032953441034021506856017081062617572351195418505899388715709795992029559042119783423597324707100694064675909238717573058764118893225111602703838080618565401139902143069901117174204252871948846864436771808616432457102844534843857198735242005309073939051433790946726672234643259349535186268571629077937597838801337973092285608744209951533199868228040004432132597073390363357892379997655878857696334892216345070227646749851381208554044940444182864026513709449823489593439017366358869648168238735087593808344484365136284219725233811605331815007424582890821887260682886632543613109252862114326372077785369292570900594814481097443781269562647303671428895764224084402259605109600363098950091998891375812839523613295667253813978434879172781217285652895469194181218343078754501694746598738215243769747956572555989594598180639098344891175879455994652382137038240166358066403475457) thì ra luôn 2 thừa số nguyên tố =)) Cụ thể như này: ```python= from Cryptodome.Util.number import * n=658416274830184544125027519921443515789888264156074733099244040126213682497714032798116399288176502462829255784525977722903018714434309698108208388664768262754316426220651576623731617882923164117579624827261244506084274371250277849351631679441171018418018498039996472549893150577189302871520311715179730714312181456245097848491669795997289830612988058523968384808822828370900198489249243399165125219244753790779764466236965135793576516193213175061401667388622228362042717054014679032953441034021506856017081062617572351195418505899388715709795992029559042119783423597324707100694064675909238717573058764118893225111602703838080618565401139902143069901117174204252871948846864436771808616432457102844534843857198735242005309073939051433790946726672234643259349535186268571629077937597838801337973092285608744209951533199868228040004432132597073390363357892379997655878857696334892216345070227646749851381208554044940444182864026513709449823489593439017366358869648168238735087593808344484365136284219725233811605331815007424582890821887260682886632543613109252862114326372077785369292570900594814481097443781269562647303671428895764224084402259605109600363098950091998891375812839523613295667253813978434879172781217285652895469194181218343078754501694746598738215243769747956572555989594598180639098344891175879455994652382137038240166358066403475457 e=65537 c=400280463088930432319280359115194977582517363610532464295210669530407870753439127455401384569705425621445943992963380983084917385428631223046908837804126399345875252917090184158440305503817193246288672986488987883177380307377025079266030262650932575205141853413302558460364242355531272967481409414783634558791175827816540767545944534238189079030192843288596934979693517964655661507346729751987928147021620165009965051933278913952899114253301044747587310830419190623282578931589587504555005361571572561916866063458812965314474160499067525067495140150092119620928363007467390920130717521169105167963364154636472055084012592138570354390246779276003156184676298710746583104700516466091034510765027167956117869051938116457370384737440965109619578227422049806566060571831017610877072484262724789571076529586427405780121096546942812322324807145137017942266863534989082115189065560011841150908380937354301243153206428896320576609904361937035263985348984794208198892615898907005955403529470847124269512316191753950203794578656029324506688293446571598506042198219080325747328636232040936761788558421528960279832802127562115852304946867628316502959562274485483867481731149338209009753229463924855930103271197831370982488703456463385914801246828662212622006947380115549529820197355738525329885232170215757585685484402344437894981555179129287164971002033759724456 p=2**2203-1 q=2**2281-1 phi=(p-1)*(q-1) d=inverse(e,phi) m=pow(c,d,n) print(long_to_bytes(m)) ``` Bây giờ giả sử như tool của ta không hoạt động thì ta phải làm sao? Các số nguyên tố có dạng $\displaystyle 2^{a} -1$ được gọi là các số nguyên tố Mersenne. Ngoài ra với $\displaystyle n=\left( 2^{a} -1\right)\left( 2^{b} -1\right)$ thì $\displaystyle n\sim 2^{a+b}$ cho nên nếu ta lấy phần nguyên của logarit cơ số 2 của $\displaystyle n$ sẽ ra được tổng của hai số nguyên tố. ```python= from math import * n=658416274830184544125027519921443515789888264156074733099244040126213682497714032798116399288176502462829255784525977722903018714434309698108208388664768262754316426220651576623731617882923164117579624827261244506084274371250277849351631679441171018418018498039996472549893150577189302871520311715179730714312181456245097848491669795997289830612988058523968384808822828370900198489249243399165125219244753790779764466236965135793576516193213175061401667388622228362042717054014679032953441034021506856017081062617572351195418505899388715709795992029559042119783423597324707100694064675909238717573058764118893225111602703838080618565401139902143069901117174204252871948846864436771808616432457102844534843857198735242005309073939051433790946726672234643259349535186268571629077937597838801337973092285608744209951533199868228040004432132597073390363357892379997655878857696334892216345070227646749851381208554044940444182864026513709449823489593439017366358869648168238735087593808344484365136284219725233811605331815007424582890821887260682886632543613109252862114326372077785369292570900594814481097443781269562647303671428895764224084402259605109600363098950091998891375812839523613295667253813978434879172781217285652895469194181218343078754501694746598738215243769747956572555989594598180639098344891175879455994652382137038240166358066403475457 print(floor(log2(n))) print(bin(n)[2:]) ``` Tiếp theo ta viết lại $\displaystyle n=\left( 2^{a} -1\right)\left( 2^{b} -1\right) =2^{a+b} -2^{a} -2^{b} +1=\left( 2^{a+b} -1\right) -\left( 2^{a} -1\right) -\left( 2^{b} -1\right)$. Bây giờ các số $\displaystyle 2^{t} -1$ khi biểu diễn nhị phân chỉ toàn gồm các số 1. Khi đó ta xét $\displaystyle 2^{a+b} -1$ gồm toàn các chữ số 1. Khi ta lấy số trên trừ cho $\displaystyle 2^{a} -1$ thì $\displaystyle a$ bit đầu tiên trong số $\displaystyle a+b$ bit của số $\displaystyle 2^{a+b} -1$ sẽ trở về 0. Sau đó nếu ta lấy số trên trừ tiếp cho $\displaystyle 2^{b} -1$ thì ta sẽ được một số có bit đầu tiên là 1, sau đó tiếp tục đi từ phải sang trái thực hiện phép trừ, nếu như bit bị trừ là 0 thì khi trừ kết quả sẽ ra 0 và nếu bit bị trừ là 1 thì kết quả sẽ trả về 1, phép toán sẽ dừng tại một bit mà kể từ bit đó về sau không còn số 0 nào nữa. Khi viết $\displaystyle n$ về dưới dạng nhị phân ta để ý thấy có một vị trí mà tại đó các bit còn lại không có bit nào bằng 0 nữa ![image](https://github.com/user-attachments/assets/f4522332-cb52-49a8-9821-316a712c2f4b) Như vậy ta sẽ lấy các bit ở phía sau số 0 này và chuyển thành số thập phân, tiếp theo lấy phần nguyên của log2 thì sẽ ra được 1 trong 2 số nguyên tố. Tới đây thì ta coi như giải quyết được bài tập. ```python= from math import * n=658416274830184544125027519921443515789888264156074733099244040126213682497714032798116399288176502462829255784525977722903018714434309698108208388664768262754316426220651576623731617882923164117579624827261244506084274371250277849351631679441171018418018498039996472549893150577189302871520311715179730714312181456245097848491669795997289830612988058523968384808822828370900198489249243399165125219244753790779764466236965135793576516193213175061401667388622228362042717054014679032953441034021506856017081062617572351195418505899388715709795992029559042119783423597324707100694064675909238717573058764118893225111602703838080618565401139902143069901117174204252871948846864436771808616432457102844534843857198735242005309073939051433790946726672234643259349535186268571629077937597838801337973092285608744209951533199868228040004432132597073390363357892379997655878857696334892216345070227646749851381208554044940444182864026513709449823489593439017366358869648168238735087593808344484365136284219725233811605331815007424582890821887260682886632543613109252862114326372077785369292570900594814481097443781269562647303671428895764224084402259605109600363098950091998891375812839523613295667253813978434879172781217285652895469194181218343078754501694746598738215243769747956572555989594598180639098344891175879455994652382137038240166358066403475457 print(floor(log2(n))) print(bin(n)[2:]) def binary_to_decimal(binary_str): return int(binary_str, 2) binary = "01111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001" print(binary_to_decimal(binary)) p=floor(log2(binary_to_decimal(binary))) print(floor(log2(binary_to_decimal(binary)))) q=floor(log2(n))-p print(f"2 số nguyên tố cần tìm là {p},{q}") ``` Một tài liệu khá thú vị [A New Public-Key Cryptosystem via Mersenne Numbers](https://eprint.iacr.org/2017/481.pdf) ## Fast Primes Source code của bài: ```python= #!/usr/bin/env python3 import math import random from Crypto.Cipher import PKCS1_OAEP from Crypto.PublicKey import RSA from Crypto.Util.number import bytes_to_long, inverse from gmpy2 import is_prime FLAG = b"crypto{????????????}" primes = [] def sieve(maximum=10000): # In general Sieve of Sundaram, produces primes smaller # than (2*x + 2) for a number given number x. Since # we want primes smaller than maximum, we reduce maximum to half # This array is used to separate numbers of the form # i+j+2ij from others where 1 <= i <= j marked = [False]*(int(maximum/2)+1) # Main logic of Sundaram. Mark all numbers which # do not generate prime number by doing 2*i+1 for i in range(1, int((math.sqrt(maximum)-1)/2)+1): for j in range(((i*(i+1)) << 1), (int(maximum/2)+1), (2*i+1)): marked[j] = True # Since 2 is a prime number primes.append(2) # Print other primes. Remaining primes are of the # form 2*i + 1 such that marked[i] is false. for i in range(1, int(maximum/2)): if (marked[i] == False): primes.append(2*i + 1) def get_primorial(n): result = 1 for i in range(n): result = result * primes[i] return result def get_fast_prime(): M = get_primorial(40) while True: k = random.randint(2**28, 2**29-1) a = random.randint(2**20, 2**62-1) p = k * M + pow(e, a, M) if is_prime(p): return p sieve() e = 0x10001 m = bytes_to_long(FLAG) p = get_fast_prime() q = get_fast_prime() n = p * q phi = (p - 1) * (q - 1) d = inverse(e, phi) key = RSA.construct((n, e, d)) cipher = PKCS1_OAEP.new(key) ciphertext = cipher.encrypt(FLAG) assert cipher.decrypt(ciphertext) == FLAG exported = key.publickey().export_key() with open("key.pem", 'wb') as f: f.write(exported) with open('ciphertext.txt', 'w') as f: f.write(ciphertext.hex()) ``` ciphertext.txt ``` 249d72cd1d287b1a15a3881f2bff5788bc4bf62c789f2df44d88aae805b54c9a94b8944c0ba798f70062b66160fee312b98879f1dd5d17b33095feb3c5830d28 ``` Và file key.pem ``` -----BEGIN PUBLIC KEY----- MFswDQYJKoZIhvcNAQEBBQADSgAwRwJATKIe3jfj1qY7zuX5Eg0JifAUOq6RUwLz Ruiru4QKcvtW0Uh1KMp1GVt4MmKDiQksTok/pKbJsBFCZugFsS3AjQIDAQAB -----END PUBLIC KEY----- ``` Phần lớn thời gian giải bài này mình dùng để đi xử lí cái file key.pem :cry: Đọc doc về [PKCS#1 OAEP](https://pycryptodome.readthedocs.io/en/latest/src/cipher/oaep.html) Đọc lại source code thì trong file `key.pem` lưu cặp public key là $(n,e)$. Để lấy cặp khóa công khai thì ta dùng thư viện `RSA` và `PKCS1_OAEP` của `pycryptodome`. Sau khi có $n$ thì có mình có lên FactorDB để lấy hai thừa số nguyên tố $p,q$. ```python= from Cryptodome.PublicKey import RSA from Cryptodome.Cipher import PKCS1_OAEP from sage.all import factor from Cryptodome.Util.number import * ciphertext="249d72cd1d287b1a15a3881f2bff5788bc4bf62c789f2df44d88aae805b54c9a94b8944c0ba798f70062b66160fee312b98879f1dd5d17b33095feb3c5830d28" enc_flag=bytes.fromhex(ciphertext) key=RSA.import_key(open('key.pem').read()) n=key.n e=key.e p=51894141255108267693828471848483688186015845988173648228318286999011443419469 q=77342270837753916396402614215980760127245056504361515489809293852222206596161 phi=(p-1)*(q-1) d=inverse(e,phi) dec_key=RSA.construct((n,e,d,p,q)) cipher=PKCS1_OAEP.new(dec_key) flag=cipher.decrypt(enc_flag) print(flag.decode()) ``` ```crypto{p00R_3570n14}``` ## Ron was Wrong, Whit is Right Source code của bài này: ```python= from Crypto.Cipher import PKCS1_OAEP from Crypto.PublicKey import RSA msg = "???" with open('21.pem') as f: key = RSA.importKey(f.read()) cipher = PKCS1_OAEP.new(key) ciphertext = cipher.encrypt(msg) with open('21.ciphertext', 'w') as f: f.write(ciphertext.hex()) ``` ![image](https://hackmd.io/_uploads/ry2bdhSoye.png) Bài này về cơ bản giống bài trước, trong source có ghi rõ 2 file `21.pem` với `21.ciphertext` thì mình lấy data về rồi làm tương tự. ```python= from Cryptodome.Util.number import * from Cryptodome.Cipher import PKCS1_OAEP from Cryptodome.PublicKey import RSA with open("/home/duc112006/cryptohack/RSA/primes2/ronwhit/keys_and_messages/21.ciphertext",'r') as f: ciphertext=f.read().strip() enc_flag=bytes.fromhex(ciphertext) key=RSA.import_key(open("/home/duc112006/cryptohack/RSA/primes2/ronwhit/keys_and_messages/21.pem").read()) n=key.n e=key.e p=919031168254299342928662994540730760042229248845820491699169870943314884504551963184014786520812939038906152950817942941469675496074887272906954399256046690838233813273902630076899906873722574023918253104149453601408405078374008695616160025877687382663027910687942091698042309812910101246025081363544171351624307177908410700904833438480012985928358897861427063761678614898919524867442676631453135379994570031284289815099294504127712924001149921480778993635917803466637717023744788311275545126346774536416864472035644211758788016642401235014385037912224180351022196262011724157012443048941426178651665266181311662824205620324073087330858064769424755443807165558567191049013947419763315902476674266627953223373671797370373786249718677582213173537848582863398367624397247597103174897140005790273296171101569756006898658668311846034013183862374297777882433967015111727139360441681664840944403450472574336901043555319067050153928231938431298082827397506406624964952344826628463723499263165279281720105570577138817805451223334196017505528543229067732013216932022575286870744622250293712218581458417969597311485156075637589299870500738770767213366940656708757081771498126771190548298648709527029056697749965377697006723247968508680596118923 q=991430390905926023965735525726256769345153760248048478891327804533279477721590201738061124861790305326884541900044434890157058142414306020739922709698601329762087825767461256626800629782378634339618941488765491437487541851308806651586976069659042714378353883168031522106709494592827914376213512564492771821921367377484213072867988877925314809325159382342584541006645302760204539354879391605736604946702073863673524002591877977949645618863730441482821840664748508050205004505250025193611888170440612737112479006348533153568103452396596042639466753099280111709882461562564978070397786887446291916733276692400981917025361391646188802038772976331121474570242334921390569285834250256522656433623912544555266998750630136756355560927237594975904642791712318215315246754105993145827690531584325461597482035600919501967088106457091199733024323755210212616553447076697617349235377466327471959683763796707566328536834402308887105044128592177681553611608618850780128709949316259039664054913946726480968288231015999572777436469163437066403964134928735809253108394078092917006632332098357725950865697047565284013456253933234017983509582245874130968218422573483012858388392588302838940565560162598810462310034964473576147200222580784694005333482381 phi=(p-1)*(q-1) d=inverse(e,phi) dec_key=RSA.construct((n,e,d,p,q)) cipher=PKCS1_OAEP.new(dec_key) flag=cipher.decrypt(enc_flag) print(flag.decode()) ``` ```crypto{3ucl1d_w0uld_b3_pr0ud}``` # Padding ## Bespoke Padding Source code của bài: ```python= #!/usr/bin/env python3 from utils import listener from Crypto.Util.number import bytes_to_long, getPrime import random FLAG = b'crypto{???????????????????????????}' class Challenge(): def __init__(self): self.before_input = "Come back as much as you want! You'll never get my flag.\n" self.p = getPrime(1024) self.q = getPrime(1024) self.N = self.p * self.q self.e = 11 def pad(self, flag): m = bytes_to_long(flag) a = random.randint(2, self.N) b = random.randint(2, self.N) return (a, b), a*m+b def encrypt(self, flag): pad_var, pad_msg = self.pad(flag) encrypted = (pow(pad_msg, self.e, self.N), self.N) return pad_var, encrypted def challenge(self, your_input): if not 'option' in your_input: return {"error": "You must send an option to this server"} elif your_input['option'] == 'get_flag': pad_var, encrypted = self.encrypt(FLAG) return {"encrypted_flag": encrypted[0], "modulus": encrypted[1], "padding": pad_var} else: return {"error": "Invalid option"} import builtins; builtins.Challenge = Challenge # hack to enable challenge to be run locally, see https://cryptohack.org/faq/#listener """ When you connect, the 'challenge' function will be called on your JSON input. """ listener.start_server(port=13386) ``` Đọc sơ qua source code ta thấy có một số điểm cần lưu ý như sau: Khi ta gửi payload `{"option" : "get_flag"}` tới server thì server sẽ trả về các giá trị $a,b,(a\times m +b)^{11}$ và modulo $n$. ![image](https://hackmd.io/_uploads/ByerHy7do1g.png) Ta sẽ gửi hai lần để lấy 2 bộ số khác nhau và lấy gcd của chúng để có lại flag Code exploit: ```python= from sage.all import * import sys def HGCD(a, b): if 2 * b.degree() <= a.degree() or a.degree() == 1: return 1, 0, 0, 1 m = a.degree() // 2 a_top, a_bot = a.quo_rem(x^m) b_top, b_bot = b.quo_rem(x^m) R00, R01, R10, R11 = HGCD(a_top, b_top) c = R00 * a + R01 * b d = R10 * a + R11 * b q, e = c.quo_rem(d) d_top, d_bot = d.quo_rem(x^(m // 2)) e_top, e_bot = e.quo_rem(x^(m // 2)) S00, S01, S10, S11 = HGCD(d_top, e_top) RET00 = S01 * R00 + (S00 - q * S01) * R10 RET01 = S01 * R01 + (S00 - q * S01) * R11 RET10 = S11 * R00 + (S10 - q * S11) * R10 RET11 = S11 * R01 + (S10 - q * S11) * R11 return RET00, RET01, RET10, RET11 def GCD(a, b): print(a.degree(), b.degree()) q, r = a.quo_rem(b) if r == 0: return b R00, R01, R10, R11 = HGCD(a, b) c = R00 * a + R01 * b d = R10 * a + R11 * b if d == 0: return c.monic() q, r = c.quo_rem(d) if r == 0: return d return GCD(d, r) sys.setrecursionlimit(50000) N= p1=... a1=... b1=... p2=... a2=... b2=... P.<x>=PolynomialRing(Zmod(N)) f=(a1*x+b1)^11-p1 g=(a2*x+b2)^11-p2 print(GCD(f,g)) ``` ```python= from Cryptodome.Util.number import * a=12657344838822568851509784228175108576435734294384614625348726284310843959714707634133487770657910655191463620755980459495489494472841767118366311527566239368266347080519905540941177319754836009001361865615932911791937361878909272062189408820287804067583808718375167348246437229018340997505497250048416371314448941176632729935794025594657080086231085613846746664059346363507527557555554476599407486065714754262102441756279472569220118834546301492068101474135392502719581667481534656037586117667379629930998141271085644412479068190285953517013765055181230873772953568052013105018766233570596827529086772321072481811563 b=4042580057131472091314248970803785803073948469522429534465991994624753854632053376850302314624607682069634835520722266510024234730404600400696915519576015482164459213392809088043033286682153420924833795013172825426364798689952787990638864929150971467776104045739032205632634038928769799138244945970441625172537257848511033067397574611668862782721703208024860750318246952182129583948813024596056990345805794037048470742455803123312430321632681399987828646748583596602906337402592935864363220680184089278865521124673568834520998539721998446857492993859139927815027352362987781771544908552672906618984176902863044030427 n=13329181839130552833554997725443499883004895074921614214963769026443408005433731176536630565084987877454566762866250882447016505196099609181864582925418185875025316555731201495213061183763463507154777983053816638762359183262747071468666575258551028413438651667838756861760026939001969118948769300510219971503220073806368290926010984874245492317016068033552659573183987048274118007356411744556272702629475023349100493759818764024291351663054108819125217117484184976057538169893259888924565225318059661883883882455822605555467512386744735681326755140085054174577150109495246225935971790848351213960429677080069426722873 d=(-b*inverse(a,n)) % n print(long_to_bytes(d)) ``` ```crypto{linear_padding_isnt_padding}``` ## Null or Never Source code: ```python= #!/usr/bin/env python3 from Crypto.PublicKey import RSA from Crypto.Util.number import bytes_to_long FLAG = b"crypto{???????????????????????????????????}" def pad100(msg): return msg + b'\x00' * (100 - len(msg)) key = RSA.generate(1024, e=3) n, e = key.n, key.e m = bytes_to_long(pad100(FLAG)) c = pow(m, e, n) print(f"n = {n}") print(f"e = {e}") print(f"c = {c}") ``` File output.txt: ``` n = 95341235345618011251857577682324351171197688101180707030749869409235726634345899397258784261937590128088284421816891826202978052640992678267974129629670862991769812330793126662251062120518795878693122854189330426777286315442926939843468730196970939951374889986320771714519309125434348512571864406646232154103 e = 3 c = 63476139027102349822147098087901756023488558030079225358836870725611623045683759473454129221778690683914555720975250395929721681009556415292257804239149809875424000027362678341633901036035522299395660255954384685936351041718040558055860508481512479599089561391846007771856837130233678763953257086620228436828 ``` Mấu chốt của bài nằm ở dòng đoạn code ```python= def pad100(msg): return msg + b'\x00' * (100 - len(msg)) ``` Trước hết thì ta cần kiểm tra xem thử việc cộng thêm các bytes `b'\x00` vào `msg` thì `msg` sẽ thay đổi như thế nào khi chuyển từ bytes sang long. Demo: ![image](https://hackmd.io/_uploads/HyY7bews1l.png) Và sau khi đệm thêm `b'\x00'` vào ![image](https://hackmd.io/_uploads/HJSvGgPoyl.png) Đầu tiên ta có ``` 't' -> 0x74 'e' -> 0x65 's' -> 0x73 't' -> 0x74 => bytes_to_long chuyển 0x74657374 dưới dạng hex về 1952805748 Khi ta thêm vào sau \x00 thì chuỗi hex sẽ trở thành 0x7465737400 Các kí tự bị dịch sang trái 2 vị trí nên giá trị của new_text sau khi chuyển sang thập phân sẽ gấp 256 = 16*16 lần text ``` Tới đây thì em nghĩ ngay tới ý tưởng lấy nghiệm của một đa thức nhận `flag` ban đầu là nghiệm bởi vì ta biết được mối quan hệ giữa `msg` và `flag` nên ta có thể viết được đa thức và nghiệm này khá nhỏ so với modulo $n$ nên khả năng cao nó là cái [này](https://doc.sagemath.org/html/en/reference/polynomial_rings/sage/rings/polynomial/polynomial_modn_dense_ntl.html#sage.rings.polynomial.polynomial_modn_dense_ntl.small_roots): ![image](https://hackmd.io/_uploads/ByNOT7pikl.png) Chuối hơn nữa là bài này không cho ta biết `len(flag)` nên ta phải đi bruteforce. ```python= ``` # Tài liệu tham khảo Note: Sách về các kiến thức số học sử dụng trong mật mã học https://drive.google.com/file/d/1MeAP73-ZWjRtKkFK-kRfdaUlaNQH4YCa/view