RSA公鑰文件解密密文的原理分析


前言

  最近在學習RSA加解密過程中遇到一個這樣的難題:假設已知publickey公鑰文件和加密后的密文flag,如何對其密文進行解密,轉換成明文~~

分析

  對於rsa算法的公鑰與私鑰的產生,我們可以了解到以下產生原理:

公鑰與私鑰的產生

  1. 隨機選擇兩個不同大質數 $p$ 和 $q$,計算 $N = p \times q$
  2. 根據歐拉函數,求得 $r=\varphi (N)=\varphi (p)\varphi (q)=(p-1)(q-1)$
  3. 選擇一個小於 $r$ 的整數 $e$,使 $e$ 和 $r$ 互質。並求得 $e$ 關於 $r$ 的模反元素,命名為 $d$,有 $ed\equiv 1 \pmod r$
  4. 將 $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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM