python3 實現RSA算法分段加密解密

參考博客地址:html

https://blog.csdn.net/qq_33414271/article/details/78424951算法

https://www.cnblogs.com/piperck/p/7257043.html安全

最近因爲工做的須要,須要寫mock,寫mock就須要接觸到加密解密簽名驗籤的問題,下面是一些總結(只針對加密解密):app

加密解密概念

關於加解密和加簽驗籤的概念參考上面的第二個博主內容,解釋的很到位,這裏直接摘取過來了:測試

  加密和加簽徹底不是一樣一件事情。加密

  加密使用的是公鑰對數據進行加密,並且當你使用一把1024bit的rsa公鑰的時候,你一次只能加密最多117byte的數據,spa

若是數據量超過這個數,可能會涉及到對數據進行分段加密的問題。並且如今rsa 1024bit長度的鑰匙已經被證實了不夠安全,.net

應該儘可能使用2048bit長度的鑰匙。2048bit長度的鑰匙一次能夠加密245byte長度的數據。這個計算方法是 2048bit/8 =code

256byte - 11byte = 245byte長數據。就是鑰匙長度減去11byte獲得的本身最大能一次加密多長的數據。若是超過了就會報錯,htm

因此不少平臺要求對數據用公鑰進行加密,就可能涉及到分段加密的問題。同時要注意的是,解密的時候不存在這11byte的

減小。就是說一把1024bit的鑰匙能夠解密128byte長的數據而2048bit的能夠解密256byte的數據。

  而加簽是使用本身的私鑰對須要加簽的字符串進行簽名。而對方須要拿着你給的公鑰來驗證這個數據是否是由你發出的,

須要使用公鑰對數據進行驗籤。若是成功驗籤才能說明你是你。

代碼實現

這裏公鑰私鑰是找開發要的,不是本身生成的,由於是作mock,須要和開發的公鑰私鑰一致。 

實現加密代碼:

from Crypto.Cipher import PKCS1_v1_5 as Cipher_pkcs1_v1_5
from Crypto.PublicKey import RSA
import base64


'''
單次加密串的長度最大爲(key_size/8 - 11)
加密的 plaintext 最大長度是 證書key位數/8 - 11, 例如1024 bit的證書,被加密的串最長 1024/8 - 11=117,
解決辦法是 分塊 加密,而後分塊解密就好了,
由於 證書key固定的狀況下,加密出來的串長度是固定的。
'''


def rsa_long_encrypt(pub_key_str, msg):
    msg = msg.encode('utf-8')
    length = len(msg)
    default_length = 117
    #公鑰加密
    pubobj = Cipher_pkcs1_v1_5.new(RSA.importKey(pub_key_str))
    #長度不用分段
    if length < default_length:
        return base64.b64encode(pubobj.encrypt(msg))
    #須要分段
    offset = 0
    res = []
    while length - offset > 0:
        if length - offset > default_length:
            res.append(pubobj.encrypt(msg[offset:offset+default_length]))
        else:
            res.append(pubobj.encrypt(msg[offset:]))
        offset += default_length
    byte_data = b''.join(res)

    return base64.b64encode(byte_data)

這裏有個問題,我怎麼知道證書key的位數呢?開始的時候嘗試過用print(len(key))來查看key的位數,可是輸出的結果不對,

最後是經過監測Crypto模塊中計算key位數的代碼來查看的:

上面的modBits值就是key的位數。

根據須要,可使用base64算法將二進制流轉換成字符串。這裏加密的時候還出現了一個問題,就是分段加密後最後拼接成一

個加密串的時候報錯了:

錯誤大概的意思是不能夠用byte類型進行拼接,其實''.join(res)是將列表中的各個字符串元素拼接成一個字符串,可是這裏加密後

返回的結果類型是byte類型的,不是str,因此才報錯了。解決方法也簡單,就是作bytes拼接,在''.join(res)前加b就能夠了,修改

後的爲b''.join(res)。

實現解密代碼:

def rsa_long_decrypt(priv_key_str, msg):
    msg = base64.b64decode(msg)
    length = len(msg)
    default_length = 128
    #私鑰解密
    priobj = Cipher_pkcs1_v1_5.new(RSA.importKey(priv_key_str))
    #長度不用分段
    if length < default_length:
        return b''.join(priobj.decrypt(msg, b'xyz'))
    #須要分段
    offset = 0
    res = []
    while length - offset > 0:
        if length - offset > default_length:
            res.append(priobj.decrypt(msg[offset:offset+default_length], b'xyz'))
        else:
            res.append(priobj.decrypt(msg[offset:], b'xyz'))
        offset += default_length

    return b''.join(res)

這裏須要注意的是decrypt方法,這個方法有兩個參數,第一個參數是解密的內容,第二個參數是解密錯誤後返回的結果,這個結

果也須要轉換成byte類型。

對加密解密代碼進行測試:

msg = '{"ApplyId":"20180504002","ChannelId":"O00420000001","LoanId":"9996401-5077812265125477811","LoanAmount":"5000.00""LoanPeriod":6,"LoanCardNo":"6225768313133272","BankId":"BANKLIST/ZHAOHANG"}'


with open('rsa-public.pem') as f:
    '''讀取公鑰並加密'''
    key = f.read()
    result = rsa_long_encrypt(key, msg)
    print(result.decode('utf-8'))

with open('rsa-private.pem') as f:
    '''讀取私鑰並解密'''
    key1 = f.read()
    result1 = rsa_long_decrypt(key1, data)
    print(result1.decode('utf-8'))

這裏可能會出現讀取密鑰格式錯誤的問題,這時須要在密鑰的先後加上如下內容,若是是自動生成的.pem文件不會有這個問題的。

公鑰:

私鑰:

 以上

相關文章
相關標籤/搜索