參考博客地址: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文件不會有這個問題的。
公鑰:
私鑰:
以上