參考博客地址:
https://blog.csdn.net/qq_33414271/article/details/78424951
https://www.cnblogs.com/piperck/p/7257043.html
最近由於工作的需要,需要寫mock,寫mock就需要接觸到加密解密簽名驗簽的問題,下面是一些總結(只針對加密解密):
加密解密概念
關於加解密和加簽驗簽的概念參考上面的第二個博主內容,解釋的很到位,這里直接摘取過來了:
加密和加簽完全不是同樣一件事情。
加密使用的是公鑰對數據進行加密,而且當你使用一把1024bit的rsa公鑰的時候,你一次只能加密最多117byte的數據,
如果數據量超過這個數,可能會涉及到對數據進行分段加密的問題。而且現在rsa 1024bit長度的鑰匙已經被證明了不夠安全,
應該盡量使用2048bit長度的鑰匙。2048bit長度的鑰匙一次可以加密245byte長度的數據。這個計算方法是 2048bit/8 =
256byte - 11byte = 245byte長數據。就是鑰匙長度減去11byte得到的自己最大能一次加密多長的數據。如果超過了就會報錯,
所以很多平台要求對數據用公鑰進行加密,就可能涉及到分段加密的問題。同時要注意的是,解密的時候不存在這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文件不會有這個問題的。
公鑰:

私鑰:

以上
