前言
最近在學習RSA加解密過程中遇到一個這樣的難題:假設已知publickey公鑰文件和加密后的密文flag,如何對其密文進行解密,轉換成明文~~
分析
對於rsa算法的公鑰與私鑰的產生,我們可以了解到以下產生原理:
公鑰與私鑰的產生
- 隨機選擇兩個不同大質數 $p$ 和 $q$,計算 $N = p \times q$
- 根據歐拉函數,求得 $r=\varphi (N)=\varphi (p)\varphi (q)=(p-1)(q-1)$
- 選擇一個小於 $r$ 的整數 $e$,使 $e$ 和 $r$ 互質。並求得 $e$ 關於 $r$ 的模反元素,命名為 $d$,有 $ed\equiv 1 \pmod r$
- 將 $p$ 和 $q$ 的記錄銷毀
此時,$(N,e)$ 是公鑰,$(N,d)$ 是私鑰。
消息加密
首先需要將消息 $m$ 以一個雙方約定好的格式轉化為一個小於 $N$,且與 $N$ 互質的整數 $n$。如果消息太長,可以將消息分為幾段,這也就是我們所說的塊加密,后對於每一部分利用如下公式加密:
$$ n^{e}\equiv c\pmod N $$
消息解密
利用密鑰 $d$ 進行解密。
$$ c^{d}\equiv n\pmod N $$
我們可以知道,RSA公鑰主要有兩個信息:模數(modulus)和指數(exponent),也就是我們所說的N和e。只要有了這兩個信息,我們便可以生成公鑰,然后使用rsa庫對數據進行加密~
腳本實現如下:
#!/usr/bin/env python # -*- coding: utf-8 -*- import rsa key = rsa.PublicKey(modulus, exponent) print key
這時候我們有如下的publickey.pem文件:
-----BEGIN PUBLIC KEY----- MDwwDQYJKoZIhvcNAQEBBQADKwAwKAIhAMJjauXD2OQ/+5erCQKPGqxsC/bNPXDr yigb/+l/vjDdAgMBAAE= -----END PUBLIC KEY-----
現在我們需要做的就是從這段字符串中提出模數和指數。
首先我們得知道pem文件是什么?
簡單來講,pem文件這種格式就是用於ASCII(Base64)編碼的各種X.509 v3 證書。
文件開始由一行"-----BEGIN PUBLIC KEY-----“開始,由"-----END PUBLIC KEY-----"結束
pem類型的數據除去begin和end之外的內容,要根據base64編碼解碼后,得到的數據需要進行增加或裁剪特殊字符-、\n、\r、begin信息、end信息等。
這里有張圖片很清楚的解釋了這個問題~~
既然我們現在已經知道了pem這種文件格式,並且也知道其中的數據內容,我們該如何對這種文件內容進行解密呢?
我們可以做以下嘗試Base64解碼嘗試:
#!/usr/bin/env python # -*- coding: utf-8 -*- import base64 pubkey = "MDwwDQYJKoZIhvcNAQEBBQADKwAwKAIhAMJjauXD2OQ/+5erCQKPGqxsC/bNPXDr yigb/+l/vjDdAgMBAAE=" b64_str = base64.b64decode(pubkey) print b64_str print len(b64_str)
解碼以后如下:
很明顯,我們解出來一段亂碼,我們嘗試把這串亂碼轉換成16進制,這里我們用的是python自帶的binascii庫進行解碼
發現結尾是"\x01\x00\x01",10001,看多了rsa的公鑰,就知道這個數,多半是exponent了。
再看看解碼后的長度為162,我們找到偏移表,發現模數的偏移位置是159,長度是3,加起來正好162~
那么說明這段字符串就是指數和模數加密過后的結果,甚至比一般的pem文件中的信息還要簡單~
按照這個思路,對照偏移表我們找出指數e和模數N:
# /usr/bin/python # -*- coding: utf-8 -*- import base64 def str2key(s): # 對字符串解碼 b_str = base64.b64decode(s) if len(b_str) < 162: return False hex_str = '' # 按位轉換成16進制 for x in b_str: h = hex(ord(x))[2:] h = h.rjust(2, '0') hex_str += h # 找到模數和指數的開頭結束位置 m_start = 29 * 2 e_start = 159 * 2 m_len = 128 * 2 e_len = 3 * 2 modulus = hex_str[m_start:m_start + m_len] exponent = hex_str[e_start:e_start + e_len] return modulus,exponent if __name__ == "__main__": pubkey = "MDwwDQYJKoZIhvcNAQEBBQADKwAwKAIhAMJjauXD2OQ/+5erCQKPGqxsC/bNPXDr yigb/+l/vjDdAgMBAAE=" key = str2key(pubkey) print key
結果如下:
('C2636AE5C3D8E43FFB97AB09028F1AAC6C0BF6CD3D70EBCA281BFFE97FBE30DD', '010001')
這個即為我們求出來模數N和指數e。
當然我們也可以用一些比較方便的工具,Kali Linux里面自帶了openssl,其他版本的Linux官方也提供了源碼安裝:https://github.com/openssl/openssl
而在Windows下安裝大家可以參考這篇文章:https://bbs.csdn.net/topics/392193545?page=1,當然我還是不建議大家在Windows下進行操作,安裝過程相對麻煩,而且可能安裝過程中會出現各種狀況~~~
我們使用如下命令對pubkey.pem找出指數e和模數N:
openssl rsa -pubin -text -modulus -in warmup -in pubkey.pem
結果如下:
我們可以得到如下參數:
e=65537 (0x10001)
Modulus即為N=C2636AE5C3D8E43FFB97AB09028F1AAC6C0BF6CD3D70EBCA281BFFE97FBE30DD
然后我們可以使用yafu對n進行因數分解,得到p、q
p=275127860351348928173285174381581152299
q=319576316814478949870590164193048041239
解碼網站在這里:https://factordb.com/
至此,各個參數已經求得如下,可以編寫代碼獲得私鑰,再用私鑰解密密文,得到明文信息~
p = 275127860351348928173285174381581152299
q = 319576316814478949870590164193048041239
N = 87924348264132406875276140514499937145050893665602592992418171647042491658461
e = 65537
我們可以開始用python寫腳本了~
#!/usr/bin/env python # -*- coding: utf-8 -*- import gmpy2 import rsa p = 275127860351348928173285174381581152299 q = 319576316814478949870590164193048041239 N = 87924348264132406875276140514499937145050893665602592992418171647042491658461 e = 65537 d = int(gmpy2.invert((e,p - 1) * (q - 1))) privatekey = rsa.PrivateKey(N,e,d,p,q) s = open("flag.enc","rb") print rsa.decrypt(s.read().privatekey).decode()
結果如下:
當然了,我們也可以用之前的公鑰對一段信息進行加密操作,具體實現過程如下:
#!/usr/bin/env python # -*- coding: utf-8 -*- import rsa import base64 message = 'Angel_Kitty' key = ('C2636AE5C3D8E43FFB97AB09028F1AAC6C0BF6CD3D70EBCA281BFFE97FBE30DD', '010001') modulus = int(key[0], 16) exponent = int(key[1], 16) rsa_pubkey = rsa.PublicKey(modulus, exponent) crypto = rsa.encrypt(message, rsa_pubkey) b64str = base64.b64encode(crypto) print b64str
加密結果如下:
這樣子我們就得到一個rsa加密,base64編碼過的字符串了,我們這個過程主要就是在一串字符串中,對照一個偏移表,提取需要的位置上的數字~~
本文用到的文件我已經上傳到本地,點擊下載即可:https://files.cnblogs.com/files/ECJTUACM-873284962/RSA公鑰文件解密密文的原理分析實例.rar