解決從python2.7升級到python3 RSA加解密錯誤
解決一下兩個錯誤
1.em = b'\x00\x02' + ps + b'\x00' + _copy_bytes(None, None, message)
2.TypeError: Object type <class 'str'> cannot be passed to C code
運行環境
pip install python 3.7.7
pip install pycryptodome-3.9.4
代碼
公鑰私鑰在線生成網站:http://web.chacuo.net/netrsakeypair
# -*- coding: UTF-8 -*- # ! /usr/bin/env python import base64 from Crypto.Cipher import PKCS1_v1_5 as PKCS1_v1_5_cipper from Crypto.Signature import PKCS1_v1_5 from Crypto.PublicKey import RSA from Crypto.Hash import SHA import Crypto # -*- coding: UTF-8 -*- # ! /usr/bin/env python import base64 from Crypto.Cipher import PKCS1_v1_5 as PKCS1_v1_5_cipper from Crypto.Signature import PKCS1_v1_5 from Crypto.PublicKey import RSA from Crypto.Hash import SHA import Crypto # 使用 rsa庫進行RSA簽名和加解密 class RsaUtil(object): PUBLIC_KEY_PATH = 'D:\cloudpayDjango\conf\company_rsa_public_key.pem' # 公鑰 PRIVATE_KEY_PATH = 'D:\cloudpayDjango\conf\company_rsa_private_key.pem' # 私鑰 # 初始化key def __init__(self, company_pub_file=PUBLIC_KEY_PATH, company_pri_file=PRIVATE_KEY_PATH): if company_pub_file: self.company_public_key = RSA.importKey(open(company_pub_file).read()) if company_pri_file: self.company_private_key = RSA.importKey(open(company_pri_file).read()) def get_max_length(self, rsa_key, encrypt=True): """加密內容過長時 需要分段加密 換算每一段的長度. :param rsa_key: 鑰匙. :param encrypt: 是否是加密. """ blocksize = Crypto.Util.number.size(rsa_key.n) / 8 reserve_size = 11 # 預留位為11 if not encrypt: # 解密時不需要考慮預留位 reserve_size = 0 maxlength = blocksize - reserve_size return maxlength # 加密 支付方公鑰 def encrypt_by_public_key(self, encrypt_message): """使用公鑰加密. :param encrypt_message: 需要加密的內容. 加密之后需要對接過進行base64轉碼 """ encrypt_result = b'' max_length = int(self.get_max_length(self.company_public_key)) cipher = PKCS1_v1_5_cipper.new(self.company_public_key) while encrypt_message: input_data = encrypt_message[:max_length] encrypt_message = encrypt_message[max_length:] out_data = cipher.encrypt(input_data.encode(encoding='utf-8')) encrypt_result += out_data encrypt_result = base64.b64encode(encrypt_result) return encrypt_result # 加密 支付方私鑰 def encrypt_by_private_key(self, encrypt_message): """使用私鑰加密. :param encrypt_message: 需要加密的內容. 加密之后需要對接過進行base64轉碼 """ encrypt_result = b"" max_length = int(self.get_max_length(self.company_private_key)) cipher = PKCS1_v1_5_cipper.new(self.company_public_key) while encrypt_message: input_data = encrypt_message[:max_length] encrypt_message = encrypt_message[max_length:] out_data = cipher.encrypt(input_data.encode(encoding='utf-8').strip() + b"\n") encrypt_result += out_data encrypt_result = base64.b64encode(encrypt_result) return encrypt_result def decrypt_by_public_key(self, decrypt_message): """使用公鑰解密. :param decrypt_message: 需要解密的內容. 解密之后的內容直接是字符串,不需要在進行轉義 """ decrypt_result = b"" max_length = self.get_max_length(self.company_public_key, False) decrypt_message = base64.b64decode(decrypt_message) cipher = PKCS1_v1_5_cipper.new(self.company_public_key) while decrypt_message: input_data = decrypt_message[:max_length] decrypt_message = decrypt_message[max_length:] out_data = cipher.decrypt(input_data.encode(encoding='utf-8'), '') decrypt_result += out_data return decrypt_result def decrypt_by_private_key(self, decrypt_message): """使用私鑰解密. :param decrypt_message: 需要解密的內容. 解密之后的內容直接是字符串,不需要在進行轉義 """ decrypt_result = b"" max_length = int(self.get_max_length(self.company_private_key, False)) decrypt_message = base64.b64decode(decrypt_message) cipher = PKCS1_v1_5_cipper.new(self.company_private_key) while decrypt_message: input_data = decrypt_message[:max_length] decrypt_message = decrypt_message[max_length:] out_data = cipher.decrypt(input_data, '') decrypt_result += str(out_data).encode(encoding='utf-8').strip() + b"\n" return decrypt_result # 簽名 商戶私鑰 base64轉碼 def sign_by_private_key(self, message): """私鑰簽名. :param message: 需要簽名的內容. 簽名之后,需要轉義后輸出 """ cipher = PKCS1_v1_5.new(self.company_private_key) # 用公鑰簽名,會報錯 raise TypeError("No private key") 如下 # if not self.has_private(): # raise TypeError("No private key") hs = SHA.new(message) signature = cipher.sign(hs) return base64.b64encode(signature) def verify_by_public_key(self, message, signature): """公鑰驗簽. :param message: 驗簽的內容. :param signature: 對驗簽內容簽名的值(簽名之后,會進行b64encode轉碼,所以驗簽前也需轉碼). """ signature = base64.b64decode(signature) cipher = PKCS1_v1_5.new(self.company_public_key) hs = SHA.new(message) # digest = hashlib.sha1(message).digest() # 內容摘要的生成方法有很多種,只要簽名和解簽用的是一樣的就可以 return cipher.verify(hs, signature) message = 'hellworldhellworldhellworldhell' print("明文內容:>>> ") print(message) rsaUtil = RsaUtil() encrypy_result = rsaUtil.encrypt_by_public_key(message) print("加密結果:>>> ") print(encrypy_result) decrypt_result = rsaUtil.decrypt_by_private_key(encrypy_result) print("解密結果:>>> ") print(decrypt_result) sign = rsaUtil.sign_by_private_key(bytearray(message.encode(encoding='utf-8'))) print("簽名結果:>>> ") print(sign) print("驗簽結果:>>> ") print(rsaUtil.verify_by_public_key(bytearray(message.encode(encoding='utf-8')), sign))
運行結果
明文內容:>>> hellworldhellworldhellworldhell 加密結果:>>> b'Mn/H3hA1JAJlcINFqWL4yooxcvKyWXI8hQZE1dta3bDdzy0cJr6jxxrS5GFCZB6TDMvRSbttRwk/iGDee8Pwk0YRevMx6t6PfQnn46WqbhchE+n1nDXcZh+ay8yCU82Sec9BgLqLY1tupNTuyjkLfx39VAIZPKJimwIH3FNN3sA=' 解密結果:>>> b'hellworldhellworldhellworldhell' 簽名結果:>>> b'MrieH+FX8U73jyPssxcpI3qrP3WOAPIqDuVbHsUOHA8Fv47UZR8qfNVn2s1uapNxuDGfzdTnYaxOnsfLDRnD3HC1JWoEXYLnkW4w/GokDJ+5JM9DGRCv2Rsr9rNM9S3JGipQD9oIJydwNvymAT9U4cYeatwEICD+4RjvaYqo1kU=' 驗簽結果:>>> True