一、題目
給出以下幾個檔案
py檔案程式碼如下
二、解題思路
1、聽C1,C2的音訊, 由長短聲很快確定是摩斯密碼,上網一搜,果然有線上摩斯密碼音訊解密網站,上去解密即可
這裡初步判斷可能是密文
2、進一步分析程式碼
分析程式碼發現這就是一個簡單的RSA加密演算法,並且有兩個不同公鑰的RSA加密過程,
但是可以發現他們的n中都有一個共同的q,由於p和q都是素數,所以可以從求解n1和n2的最大公因式入手。
3、但是公鑰都不知道,這時想起還有兩個檔案沒有用到,這不就是公鑰嗎
上網一查發現“.pem”檔案常常用來儲存公鑰,用檔案檢視器可以看到裡面的公鑰用base64的格式進行編碼。
但是這裡不進行解碼,因為公鑰只是一些無序的二進位制資料,並沒有什麼實際的文字意義,python的Crypto.PublicKey庫中的RSA模組提供公鑰檔案讀取函式,直接呼叫即可讀取入的公鑰有n和e,用圖示的辦法可以分別調出它們。
在安裝Crypto庫後出現了仍然無法呼叫庫函式的情況
上網查了一下找到了解決辦法:參考文章
4、有了n1和n2,現在可以利用歐幾里得輾轉相除法求取n1和n2的最大公約數q,這樣p1和p2就有了,一切都變得簡單。
5、由於n=p*q,求解出q後就可以求解p1和p2,需要注意的是使用整除符號“//”而不是除號“/”。
解釋:
- 普通除法 /:會返回一個浮動型別的結果,即使除數能夠整除。
- 整數除法 //:返回一個整數結果,去掉小數部分。
這裡可以驗證一下,如果使用“/”,可以看到p的型別是浮點數,而“//”的結果中p的型別是整數:
6、然後就是求解逆元d1和d2,最後利用d1和d2進行解密。第三方庫中的inverse()函式就是求解逆元d的函式,引數為e和尤拉數phi,引數只能接收整數,這也是之前需要使用整除符號的原因。
phi = (p-1)*(q-1) 這時RSA的常識
7、利用私鑰(n1,d1)和(n2,d2)解出明文m1和m2,再拼接即可得出flag
解密:m = e^d mod n
這裡需要注意Crypto.Util.number庫中的long_to_bytes模組,它是用來把這麼一大串長數字轉化為位元組串顯示。
補充:
- 位元組串(bytes)是二進位制資料的原始表示,每個位元組表示一個數字值,範圍從0到255。它們用於儲存影像、音訊、影片、加密密文等非文字型別的資料。這些位元組可以是列印字元的編碼,也可以是無法顯示的控制字元或其他資料。
- 位元組串中的每個位元組都可以用 \x 後跟十六進位制數字的形式表示,這些位元組值不一定對應於可列印字元。
- print函式在列印位元組串的時候會預設使用utf-8進行解碼,如果位元組串不能被utf-8正確解碼,就會出現如下形式:
這時可能要如果出現這種情況,要麼就是解密出現錯誤,要麼就是密文並不是簡單的文字形式,需要進行特殊的轉化。
8、指令碼程式碼
from Crypto.PublicKey import RSA
from Crypto.Util.number import inverse,long_to_bytes
with open("pubkey1.pem","rb") as f:
pk1_bit= f.read()
with open("pubkey2.pem","rb") as f:
pk2_bit =f.read();
pk1 = RSA.importKey(pk1_bit)
pk2 = RSA.importKey(pk2_bit)
n1 = pk1.n
e1 = pk1.e
n2 = pk2.n
e2 = pk2.e
c1 = 4314251881242803343641258350847424240197348270934376293792054938860756265727535163218661012756264314717591117355736219880127534927494986120542485721347351
c2 = 485162209351525800948941613977942416744737316759516157292410960531475083863663017229882430859161458909478412418639172249660818299099618143918080867132349
#求解兩數的最大公約數
def gcd(a,b):
while(b!=0):
r=a%b
a=b
b=r
return a
p = gcd(n1,n2)
q1 = n1//p
q2 = n2//p
phi_1 = (p-1)*(q1-1)
phi_2 = (p-1)*(q2-1)
d1= inverse(e1,phi_1)
d2= inverse(e2,phi_2)
m1_bit = pow(c1,d1,n1)
m2_bit = pow(c2,d2,n2)
m1 = long_to_bytes(m1_bit)
m2 = long_to_bytes(m2_bit)
print(m1+m2)
9、最終答案
b'UNCTF{ac01dff95336aa470e3b55d3fe43e9f6}'