1. 程式人生 > >rsa字符串格式公鑰轉換python rsa庫可識別的公鑰形式

rsa字符串格式公鑰轉換python rsa庫可識別的公鑰形式

進制 __name__ 結束 with mod 之前 簡單 使用 文件格式

在爬蟲分析的時候,經常在網頁上看到如下格式的rsa公鑰:

MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDC7kw8r6tq43pwApYvkJ5laljaN9BZb21TAIfT/vexbobzH7Q8SUdP5uDPXEBKzOjx2L28y7Xs1d9v3tdPfKI2LR7PAzWBmDMn8riHrDDNpUpJnlAGUqJG9ooPn8j7YNpcxCa1iybOlc2kEhmJn5uwoanQq+CA6agNkqly2H4j6wIDAQAB

對於rsa算法的公鑰,我們了解到,主要有兩個信息:模數(modulus)和指數(exponent)

只有有這兩個信息,我們便可以用以下代碼段生成公鑰,然後使用rsa庫對數據進行加密

import rsa

key = rsa.PublicKey(modulus, exponent)
print key

現在我們需要做的就是從這段字符串中提出模數和指數.

在研究的過程中,除了這種字符串的形式,我們看得最多的應該屬於public.pem、private.pem這種文件格式的公鑰私鑰了.

那麽PEM這又是個什麽格式呢,搜索下來,基本上都說包含什麽信息然後是數據什麽的,我怎麽知道那些是信息,那些是數據呢?

對比一些資料,覺得看下圖基本明了(本來是有一篇很好的文章,貌似找不到鏈接了,只保存了一張圖片)

技術分享

我們打開pem格式的文件看一下,發現

-----BEGIN RSA PUBLIC KEY-----
MIGJAoGBAPVZR7eov
/GFh77lx2sp1FDkP63mygPAUkomwV9fPFUuajviO5038P3k Jhl5o14+LN8NxLuyiTzgYKSunUkvqxwkWSKHOw8EL3m6YKytk5UR+FEg8LBqPNox lcT9a9VH2PngbnR9WWm2ycMQBppQRC3Ci7yLIcjwgDUOrgoz6PmpAgMBAAE= -----END RSA PUBLIC KEY-----

這個BEGIN和這個END中間這一段很像我們找到的這個字符串,我們把開頭的字符串復制到public.pem文件的中間,然後使用以下代碼加密試試:

import rsa

with open(
public.pem,r) as f: pubkey = rsa.PublicKey.load_pkcs1(f.read().encode()) message = cnblogs crypto = rsa.encrypt(message.encode(), pubkey) print crypto

這段似乎根本就會報錯,而且,這個復制過去的格式也不對,原先的是有換行的,

查詢一下似乎換行也是一種信息,而我們的字符串從哪裏換行根本無從得知

那麽,這個字符串和pem就沒有別的聯系了嗎?答案是有的.

之前就有猜測這個字符串可能是base64加密過的,那麽我就解密看看:

import base64

pubkey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDC7kw8r6tq43pwApYvkJ5laljaN9BZb21TAIfT/vexbobzH7Q8SUdP5uDPXEBKzOjx2L28y7Xs1d9v3tdPfKI2LR7PAzWBmDMn8riHrDDNpUpJnlAGUqJG9ooPn8j7YNpcxCa1iybOlc2kEhmJn5uwoanQq+CA6agNkqly2H4j6wIDAQAB"

b64_str = base64.b64decode(pubkey)

print b64_str
print len(b64_str)

得到一串亂碼,我們把這串亂碼轉換成16進制

發現結尾是"\x01\x00\x01",10001,看多了rsa的公鑰,就知道這個數,多半是exponent了.

再看看解碼後的長度,162,我們找到偏移表,發現模數的偏移位置是159,長度是3,加起來正好162

那麽說明這段字符串就是指數和模數加密過後的結果,甚至比一般的pem文件中的信息還要簡單

按照這個思路,對照偏移表我們找出指數和模數:

# /usr/bin/python
# encoding: 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 = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDC7kw8r6tq43pwApYvkJ5laljaN9BZb21TAIfT/vexbobzH7Q8SUdP5uDPXEBKzOjx2L28y7Xs1d9v3tdPfKI2LR7PAzWBmDMn8riHrDDNpUpJnlAGUqJG9ooPn8j7YNpcxCa1iybOlc2kEhmJn5uwoanQq+CA6agNkqly2H4j6wIDAQAB"
    key = str2key(pubkey)
    print key

得到結果如下:

(c2ee4c3cafab6ae37a7002962f909e656a58da37d0596f6d530087d3fef7b16e86f31fb43c49474fe6e0cf5c404acce8f1d8bdbccbb5ecd5df6fded74f7ca2362d1ecf033581983327f2b887ac30cda54a499e500652a246f68a0f9fc8fb60da5cc426b58b26ce95cda41219899f9bb0a1a9d0abe080e9a80d92a972d87e23eb, 010001)

現在我們用剛才得到的key來加密字符串:

    import rsa

    message = cnblogs
    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編碼過的字符串了.

總結一下:主要就是在一串字符串中,對照一個偏移表,提取需要的位置上的數字.

rsa字符串格式公鑰轉換python rsa庫可識別的公鑰形式