【Python】Crypto模块 _ RSA加解密、加签验签
一、 RSA 和 AES 介绍
RSA加密算法是一种非对称加密算法。
RSA 是1977年由罗纳德·李维斯特(Ron Rivest)、阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)一起提出的。他们三人姓氏开头字母拼在一起组成的。
非对称加密算法:加密和解密用不同的密钥,一对秘钥: 使用公钥来加密信息,然后使用私钥来解密。
AES是高级加密标准, 是最常见的对称加密算法。
一种分组加密标准,每个加密块大小为128位,允许的密钥长度为128、192和256位
对称加密算法:加密和解密用相同的密钥,同一个秘钥即用来加密,也用来解密。
二、安装Crypto
crypto,pycrypto,pycryptodome的功能是一样的。
crypto与pycrypto已经没有维护了,后面可以使用pycryptodome。
在 Windows 中,不管是 Python2 和 Python3 ,都不能用 crypto 和 pycrypto ,可以用 pycryptodome 。
在 Linux 中,不管是 Python2 和 Python3 ,都不能用 crypto ,可以用 pycrypto 和 pycryptodome 。
安装命令
pip install pycryptodome
pip install Crypto
三、RSA加解密
1、生成RSA公钥 私钥
# -*- coding:utf-8 -*- # import rsa # 方法一引用 from x.logger import * # 方法二引用 from Crypto import Random from Crypto.PublicKey import RSA class encryPa: # 方法一:rsa 模块生成RSA公钥私钥 # def rsa_puiv(self): # # 生成RSA公钥 私钥 # (pubkey, privkey) = rsa.newkeys(1024) # rsa_key = pubkey.save_pkcs1() # logs.debug(rsa_key.decode()) # rsa_iv = privkey.save_pkcs1() # logs.debug(rsa_iv.decode()) # self.sava_Loc("./key_iv/rsa_pubkey.pem", rsa_key) # self.sava_Loc("./key_iv/rsa_prikey.pem", rsa_iv) # # return rsa_key, rsa_iv # 方法二:crypto 模块生成RSA公钥私钥 def crypto_rsa_puiv(self): random_g = Random.new().read rsa = RSA.generate(1024, random_g) # 生成RSA公钥 crypto_key = rsa.public_key().exportKey() logs.debug(crypto_key.decode()) # 生成RSA私钥 crypto_iv = rsa.exportKey() logs.debug(crypto_iv.decode()) self.sava_Loc("./key_iv/crypto_pubkey.pem", crypto_key) self.sava_Loc("./key_iv/crypto_privkey.pem", crypto_iv) return crypto_key, crypto_iv # 保存数据到文件 def sava_Loc(self, fileName, fileData): with open(fileName, "wb+") as f: f.write(fileData) if __name__ == "__main__": # encryPa().rsa_puiv() encryPa().crypto_rsa_puiv()
-----BEGIN RSA PUBLIC KEY----- MIGJAoGBALIhbVPwic/U1YhX3Xr4BECzOlcK26V++LUbM+WVuOCKmgO1xGJlod0N fdkPLMQw7tiW1gaGRqtaKQct5zNJoAN6/dftOxey6xfMooGvH1qpruUTcqeXvkAA niVuVlVO9mYrxlmmg8IP7cFISc5VWFtxdGGelh1oAyd1x5zcamMnAgMBAAE= -----END RSA PUBLIC KEY----- -----BEGIN RSA PRIVATE KEY----- MIICXwIBAAKBgQCyIW1T8InP1NWIV916+ARAszpXCtulfvi1GzPllbjgipoDtcRi ZaHdDX3ZDyzEMO7YltYGhkarWikHLeczSaADev3X7TsXsusXzKKBrx9aqa7lE3Kn l75AAJ4lblZVTvZmK8ZZpoPCD+3BSEnOVVhbcXRhnpYdaAMndcec3GpjJwIDAQAB AoGAQ4B9UJjPcI2j2YYKbSX9XpNMoV2A/McP8nl7gh3psFV1pcBEylDfNMh/Dzk7 6qDscfE+67wInbiN4aWYN1/csFZFCOaUBOBGSCPp6Nblg2563/vhIx3lvch8XkdY HqH8mwKWJs/0zTtCMbQEZl1F/3m6LABJSCsPhUtmfonuE2kCRQC70RJrn3fGgaLl 4bPnLVi2ShJ3MlYWQE3qfQmGs7taupbAa8ULeaYH6KNTLEF/xaMdOAKpWJ0/3IlX LipuOCniWnKS0wI9APLMKq1oknw0Dd8l/os9hnia2bHUn+UabWxAbsLXhivPA51Q zLEfJsjuY49ExdqhDBRLZFRFowyiH/Px3QJEZrvN36Cy25o9iJEU3vcm9089GoYm ILW76O/MLipR6Sb3HvnUJpq7/sd5zxz+Fu38cxcYHZmjKjNvzIgsHW4LOw1ObpEC PAiGTJVMD6CWv0nvbpF69oazgSMyQO7tT5w2Yu0qXgaZvRm/5X/uhREW9Z3pHz0+ 3Eq2Hu6qh0ABTTfmbQJEej0n4Qnh62de+uc9mGs7C+4oB5lTPkhEnDtdIwjCF6iI ttTLpJOLb+bi+xFkffV+MgF8yCUhVem50kS7IiHs+WnF1YU= -----END RSA PRIVATE KEY----- -----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCxhCGE+ALdMd1eQKPOvbYq+kNi GI43TJwSnLZu0SYxmUOWvOw6VAMRawuIraZEiUR5hUMeLhRPB/bybd9b//N27hr5 qk8GQylL1whCHklmadxWY09HjUCngHb8JcF/hFYKB36ut5MT4HbBeUfe2ubcfPXu /nfz5CHADpJd9yaU6wIDAQAB -----END PUBLIC KEY----- -----BEGIN RSA PRIVATE KEY----- MIICXAIBAAKBgQCxhCGE+ALdMd1eQKPOvbYq+kNiGI43TJwSnLZu0SYxmUOWvOw6 VAMRawuIraZEiUR5hUMeLhRPB/bybd9b//N27hr5qk8GQylL1whCHklmadxWY09H jUCngHb8JcF/hFYKB36ut5MT4HbBeUfe2ubcfPXu/nfz5CHADpJd9yaU6wIDAQAB AoGARkFeiMMlUwjErWRU0GJZ4hmJKJ5CTtWFoYIfW61v+cpIKzTbI1yTmEWu22mq d86B6Lxaq2ueQwcKb7kXYNBkOOFKmR0BUE7Douff1U0OeblsvaVwMOnsWujd2pz7 Qyxiq8Aeo27hXBKtzYqDep9qS9062ot/iuC7YVcADaoN76ECQQDQFaY4ipFARDJI P6kDzJONZwk4TsL16bo5FJEEahpGB+FEeE1WZSKOEdlMDXxcEmigsOfQXDZXEKeK 3ZpumI7LAkEA2mSBz+Rpo/PBQv7Pw5IZsX62L8kcIdYDWcO2BQLZO5UvvKjyV+EP y3MQKAvSfrPPZLf0hINreG0i+QkNCxAuYQJABhfMMTWlgSs+Ca2Lhmf0HhzZQUPV I5w/brJyeJ2evVQ3vWiEYzY858oQAdEXRh7n32SutQQuNyhur3tDrV9cNwJAYGex rhXEVG2LyIk3Kbvav7GRtvJuCrmwbPWp6fhh8J1gn0VtBUICeOroHOVrHCc/y9Qw ijaBQH3czFYkfde8wQJBAKo8ijH1/4Ts94xAtM3tqLL/lzlPJeweavvVlHTK+3U3 Dp6HGIKEv+MtUVjPTNCSphBMOQJAsC/xbOg9R0CvezQ= -----END RSA PRIVATE KEY----- 进程已结束,退出代码为 0
2、RSA 加解密
RSA 模块
# 导入模块 import rsa
# rsa 公钥加密 def use_rsa_keyencry(self): # 读取生成的公钥 with open("./key_iv/rsa_pubkey.pem", "rb") as f: file_pub = f.read() logs.debug(file_pub) # 秘钥解析 rsa_key = rsa.PublicKey.load_pkcs1(file_pub) # logs.debug(rsa_key) # 需要加密的信息 txt = "zhangsanlisiwangwanma/123456".encode("utf-8") # rsa加密 enc_txt = rsa.encrypt(txt, rsa_key) logs.debug(enc_txt) return enc_txt # rsa 私钥解密 def use_rsa_ivencry(self): # 读取与公钥匹配的私钥 with open("./key_iv/rsa_prikey.pem", "rb") as f: file_pri = f.read() logs.debug(file_pri) # 秘钥解析 rsa_iv = rsa.PrivateKey.load_pkcs1(file_pri) # 需要解密的信息 en_txt = self.use_rsa_keyencry() # 解密 den_txt = rsa.decrypt(en_txt, rsa_iv).decode() logs.debug(den_txt)
运行结果
b'dl\xe2*\x85\x00n\xbc\x9e\xc6\xd4@\x84\x05\xac\xc4F:\x16 \x98\xcf\x0fv\xab\x11\xd5|\xcd\xc2ssx\x1c\xef\x0es\x0c<\x1df\x83\xfd8\xca\xcf\x82\xac\xed\xd8O\x97\x95\xbb\xf9_\xae\xba`\xa6Py\xa7\xfd\xd3\xae\xa8_T\x16\xc1\x99\x10\x05B\x8fO8=\x9a\xb0\xe1\xda\xb4+\x91>O%\xb2q\x18\x7f\xe0&\xa6\x8fH;\x00\xcd?X\xaa\xaa\x1d+x\xa1!T\xc9\xb7\xb7\x12#\xe9\xaeY\xa5.\xda\xef\x9d\xa3#]\x95' zhangsanlisiwangwanma/123456
Crypto模块
from Crypto import Random from Crypto.PublicKey import RSA from Crypto.Cipher import PKCS1_v1_5 as PKCS1_cipher
# crypto 模块公钥加密 def use_crypto_keyencry(self): msg = "需要加密的信息" # 读取公钥 with open("./key_iv/crypto_pubkey.pem", "rb") as f: file_key = f.read() # RSA 的 importKey() 方法将读取到的公钥字符串 处理成可用的加密公钥 crypt_pub = RSA.importKey(file_key) # 实例化一个加密对象 cipher 传入公钥对信息进行加密。 cipher = PKCS1_cipher.new(crypt_pub) # 将结果转换成 base64 字符串 encrypto_txt = base64.b64encode(cipher.encrypt(bytes(msg.encode("utf-8")))) logs.debug("crypto 加密数据:%s" % encrypto_txt.decode()) return encrypto_txt # crypto 模块私钥解密 def use_crypto_ivencry(self): msg = self.use_crypto_keyencry() with open("./key_iv/crypto_privkey.pem", "rb") as f: file_iv = f.read() # 使用 RSA 的 importKey()方法将 读取的私钥字符串 处理成可用的解密私钥 crypt_pri = RSA.importKey(file_iv) # 实例化一个解密对象 cipher 传私钥对信息进行解密 解密结果与加密之前保持一致 cipher = PKCS1_cipher.new(crypt_pri) # 将结果转换成 base64 字符串 dencrypto_txt = cipher.decrypt(base64.b64decode(msg), 0) logs.debug("crypto解密数据:%s" % dencrypto_txt.decode()) return dencrypto_txt
运行结果
crypto加密:wD28WBZN7Q7JfzBk3opIqb5Foj4NFuZeDIdnD4fnyJtB5EKtMeNImgJALh15vJ5xY5KO/39d0RMb+JMuhnuMwyBAPweY/WVmPVf5fTTcq3ZpyRBewoD0sQh86bifCaeP6ztlD9DYB0D+naqnEFUzIE7aBN4y6T1+7KhI+tQB3lM=
crypto解密:需要加密的信息
四、Sign 签名验证
私钥生成签名和公钥验证签名
# 导入模块 from Crypto.Hash import SHA from Crypto.Signature import PKCS1_v1_5 as PKCS1_signature
# sign 私钥生成签名和公钥验证签名 def use_sign(self, message): # message = "需要加密的信息alal" # 使用私钥生成签名 with open('./key_iv/crypto_privkey.pem') as f: key = f.read() # RSA 的 importKey() 方法将读取的私钥字符串 处理成可用的私钥用于生成签名 pri_key = RSA.importKey(key) # 实例化一个签名对象 signer 传入处理后的私钥 signer = PKCS1_signature.new(pri_key) # 信息需要先转换成 sha 字符串 digest = SHA.new() digest.update(message.encode("utf8")) # 对信息生成签名 sign = signer.sign(digest) # 。生成的签名是字节串 将结果转换成 base64 字符串 signature = base64.b64encode(sign) # logs.debug(signature.decode('utf-8')) # 使用公钥验证签名 with open('./key_iv/crypto_pubkey.pem') as f: key = f.read() # RSA 的 importKey() 方法将读取的公钥字符串 处理成可用的公钥用于验证签名 pub_key = RSA.importKey(key) # 实例化一个验证对象 verifier ,传入处理的公钥, verifier = PKCS1_signature.new(pub_key) digest = SHA.new() digest.update(message.encode("utf8")) # 对签名进行验证。验证结果是一个布尔值,验证成功返回 True , 不成功返回 False 。 sign_result = verifier.verify(digest, base64.b64decode(signature)) # logs.debug(sign_result) return signature, sign_result
运行结果
NRGzy07A81TZfqTLBblV0aOOHJdXQG4Ddr9m7sHL5pSkvjfCvm4+5FXPiQpN9O80Kjc/mC2LevHkk/z1XLPYd+s+b9hRPuFJKCq555A5tahzMSWhv80vvhdgVeIej1FIlE+bOGNgRIBadKi3N6Anyii9/RvzfErLHYcO3SYHNog=
True
进程已结束,退出代码为 0
五、完整实现
RSA加解密、加签、验签
# -*- coding:utf-8 -*- import os import base64 from Crypto import Random from Crypto.Hash import SHA256 from Crypto.PublicKey import RSA # Crypto模块中的pkcs1_v1_5对应pkcs8格式 from Crypto.Cipher import PKCS1_v1_5 as Cipher_pkcs1_v1_5 from Crypto.Signature import PKCS1_v1_5 as Signature_pkcs1_v1_5 class rsa_tools: """RSA PKCS8 SHA256 加解密工具""" def __init__(self, msg, pub_file): """ RSA 加解密,加签 验签 :param msg: 需要加密的信息 :param pub_file: 公钥/私钥文件 路径 """ self.pubFile = pub_file self.message = msg def getEncrypt(self): """加载公钥用来加密""" with open(self.pubFile, 'rb') as public_file: public_key = public_file.read() rsakey = RSA.importKey(public_key) cipher = Cipher_pkcs1_v1_5.new(rsakey) cipher_text = base64.b64encode(cipher.encrypt(self.message)) return cipher_text.decode('utf8') def getdecryp(self): """加载私钥用于解密""" with open(self.pubFile, 'rb') as private_file: private_key = private_file.read() rsakey = RSA.importKey(private_key) cipher = Cipher_pkcs1_v1_5.new(rsakey) text = cipher.decrypt(base64.b64decode(self.message), '') return text.decode("utf-8") def rsa_sign(self): """读取私钥信息用于加签""" with open(self.pubFile, 'rb') as private_file: private_key = private_file.read() prikey = RSA.importKey(private_key) signer = Signature_pkcs1_v1_5.new(prikey) digest = SHA256.new() digest.update(self.message) signature = signer.sign(digest) auth_signature = base64.b64encode(signature) signature = auth_signature.decode() return signature def rsa_verify(self, signature): """读取公钥用于验签""" with open(self.pubFile, 'rb') as public_file: public_key = public_file.read() pubkey = RSA.importKey(public_key) verifier = Signature_pkcs1_v1_5.new(pubkey) digest = SHA256.new() digest.update(self.message) is_verify = verifier.verify(digest, base64.b64decode(signature.encode("utf-8"))) return is_verify @staticmethod def rsa_to_key_iv(name='rsa'): """ crypto 模块生成RSA公钥私钥 :param name: 公私钥文件拼接名; 如 公钥:name+'_public_key.pem' 私钥:name+'_private_key.pem' :return: """ random_g = Random.new().read rsa = RSA.generate(1024, random_g) # 生成RSA公钥 crypto_key = rsa.public_key().exportKey() print(crypto_key.decode()) # 生成RSA私钥 crypto_iv = rsa.exportKey() print(crypto_iv.decode()) # 公私钥保存地址 cur_path = os.path.abspath(os.path.dirname(__file__)) # 获取当前文件的目录 proj_path = cur_path[:cur_path.find('projectName')] + 'projectName\\key_iv' # 获取根目录 public_key_path = os.path.join(proj_path, "{}_public_key.pem".format(name)) private_key_path = os.path.join(proj_path, "{}_private_key.pem".format(name)) # 保存数据 rsa_tools.sava_Loc(public_key_path, crypto_key) rsa_tools.sava_Loc(private_key_path, crypto_iv) return crypto_key, crypto_iv @staticmethod def sava_Loc(fileName, fileData): """保存数据到文件""" try: with open(fileName, "wb+") as f: f.write(fileData) except FileNotFoundError: os.makedirs(os.path.split(fileName)[0]) with open(fileName, "wb+") as f: f.write(fileData) if __name__ == '__main__': code = '{"name": "zhangsan", "age": "112"}' cur_path = os.path.abspath(os.path.dirname(__file__)) # 获取当前文件的目录 proj_path = cur_path[:cur_path.find('base')] + 'data\\key_iv' # 获取根目录 public_key_path = os.path.join(proj_path, "{}_public_key.pem".format("rsa")) private_key_path = os.path.join(proj_path, "{}_private_key.pem".format("rsa")) # print(public_key_path) r = rsa_tools.rsa_key_iv_to_file() # 生成公私钥 # rsaObj_en = rsa_tools(code.encode("UTF-8"), public_key_path) # rsa_en = rsaObj_en.rsa_get_encrypt() # 加密 # print(rsa_en) # # rsaObj_de = rsa_tools(rsa_en, private_key_path) # rsa_de = rsaObj_de.rsa_get_decrypt() # 解密 # print(rsa_de) s = rsa_tools(code.encode("utf-8")).rsa_sign() ds = rsa_tools(code.encode("utf-8")).rsa_verify(s) print(s) print(ds)
执行结果
2023-4-23 优化版:支持超长文本加密 及使用加密后的公私钥对文本进行加密
# -*- coding:utf-8 -*- import json import os import base64 import sys from urllib.parse import * from Crypto import Random from Crypto.Hash import SHA1 from Crypto.Hash import SHA256 from Crypto.Hash import SHA512 from Crypto.PublicKey import RSA # Crypto模块中的pkcs1_v1_5对应pkcs8格式 from Crypto.Cipher import PKCS1_v1_5 as Cipher_pkcs1_v1_5 from Crypto.Signature import PKCS1_v1_5 as Signature_pkcs1_v1_5 from aa_demo.base.jiajiemi.aes_ecb_tools import * from aa_demo.base.logger import * class rsa_tools: """RSA PKCS8 SHA1/SHA256 加解密工具""" def __init__(self, msg, pub_fname="", pri_fname=""): """ RSA 加解密,加签 验签 :param msg: 需要加密的信息 传参时需要对msg进行encode 示例,rsa_tools(msg.encode("UTF-8")) :param pub_fname: 公钥文件名 路径:./data/key_iv/ + pub_fname :param pri_fname: 私钥文件名 路径:./data/key_iv/ + pri_fname """ self.message = msg # logs.debug(self.message) cur_path = os.path.abspath(os.path.dirname(__file__)) # 获取当前文件的目录 proj_path = cur_path[:cur_path.find('base')] + 'data\\key_iv' # 获取根目录 # :param pub_file: 公钥/私钥文件 路径 self.pubFile = os.path.join(proj_path, "{}".format(pub_fname)) self.priFile = os.path.join(proj_path, "{}".format(pri_fname)) # logs.debug(self.pubFile) # logs.debug(self.priFile) def rsa_get_encrypt(self, passphrase=''): """ 加载公钥用来加密 :param passphrase: 秘钥加密码,默认不加密 :return: """ # 读取公钥 with open(self.pubFile, 'rb') as public_file: public_key = public_file.read() try: # RSA 的 importKey() 方法将读取到的公钥字符串 处理成可用的加密公钥 rsakey = RSA.importKey(extern_key=public_key) if passphrase == '' else RSA.importKey(extern_key=public_key, passphrase=passphrase) # pem加密短语 except ValueError as ve: logs.error("秘钥处理异常, 请确保秘钥加密码正确:异常原因:{}".format(ve)) except Exception as e: logs.error("出现其他异常:原因:{}".format(e)) else: # 实例化一个加密对象 cipher 传入公钥对信息进行加密。 cipher = Cipher_pkcs1_v1_5.new(rsakey) # 将结果转换成 base64 字符串 cipher_text = base64.b64encode(cipher.encrypt(self.message)) return cipher_text.decode('utf8') def rsa_get_decrypt(self, passphrase=''): """ 加载私钥用于解密 :param passphrase: 秘钥加密码 ,默认不加密 :return: """ # 读取私钥 with open(self.priFile, 'rb') as private_file: private_key = private_file.read() try: # 使用 RSA 的 importKey()方法将 读取的私钥字符串 处理成可用的解密私钥 rsakey = RSA.importKey(extern_key=private_key) if passphrase == '' else RSA.importKey(extern_key=private_key, passphrase=passphrase) except ValueError as ve: logs.error("秘钥处理异常, 请确保秘钥加密码正确:异常原因:{}".format(ve)) except Exception as e: logs.error("出现其他异常:原因:{}".format(e)) else: # 实例化一个解密对象 cipher 传私钥对信息进行解密 解密结果与加密之前保持一致 cipher = Cipher_pkcs1_v1_5.new(rsakey) # 将结果转换成 base64 字符串 text = cipher.decrypt(base64.b64decode(self.message), '') return text.decode("utf-8") def rsa_long_encrypt(self, passphrase='', length=100): """ 超长文本加密 :param passphrase: 秘钥加密码,默认不加密 :param length: 1024bit的证书用100, 2048bit的证书用 200 :return: """ # 读取公钥 with open(self.pubFile, 'rb') as public_file: public_key = public_file.read() try: rsakey = RSA.importKey(public_key) if passphrase == '' else RSA.importKey(extern_key=public_key, passphrase=passphrase) # pem秘钥加密 except ValueError as ve: logs.error("秘钥处理异常, 请确保秘钥加密码正确:异常原因:{}".format(ve)) except Exception as e: logs.error("出现其他异常:原因:{}".format(e)) else: cipher = Cipher_pkcs1_v1_5.new(rsakey) # 处理:Plaintext is too long. 分段加密 if len(self.message) <= length: # 对编码的数据进行加密,并通过base64进行编码 result = base64.b64encode(cipher.encrypt(self.message)) else: rsa_text = [] # 对编码后的数据进行切片,原因:加密长度不能过长 for i in range(0, len(self.message), length): cont = self.message[i:i + length] # 对切片后的数据进行加密,并新增到text后面 rsa_text.append(cipher.encrypt(cont)) # 加密完进行拼接 cipher_text = b''.join(rsa_text) # base64进行编码 result = base64.b64encode(cipher_text) return result def rsa_long_decrypt(self, passphrase='', length=128): """ 超长文本解密,默认不加密 :param passphrase: 秘钥加密码 :param length: 1024bit的证书用128,2048bit证书用256位 :return: """ # 读取私钥 with open(self.priFile, 'rb') as private_file: private_key = private_file.read() try: # 使用 RSA 的 importKey()方法将 读取的私钥字符串 处理成可用的解密私钥 rsakey = RSA.importKey(extern_key=private_key) if passphrase == '' else RSA.importKey(extern_key=private_key, passphrase=passphrase) # pem秘钥解密 except ValueError as ve: logs.error("秘钥处理异常, 请确保秘钥加密码正确:异常原因:{}".format(ve)) except Exception as e: logs.error("出现其他异常:原因:{}".format(e)) else: # 实例化一个解密对象 cipher 传私钥对信息进行解密 解密结果与加密之前保持一致 cipher = Cipher_pkcs1_v1_5.new(rsakey) # base64 解密字符串 base64_de = base64.b64decode(self.message) # 对解码后的数据进行切片,原因:长度不正确的密文(不是128字节) res = [] for i in range(0, len(base64_de), length): res.append(cipher.decrypt(base64_de[i:i + length], 'xyz')) return b"".join(res) def rsa_sign(self, passphrase='', sha_mode='SHA1'): """ 读取私钥信息用于加签 :param passphrase: 秘钥加密码, 默认不加密 :param sha_mode: 算法模式:仅支持SHA1/SHA256 <SHA1的输出大小为160位。 SHA256的输出大小为256位> :return: """ # 读取私钥 with open(self.priFile, 'rb') as private_file: private_key = private_file.read() try: # RSA 的 importKey() 方法将读取的私钥字符串 处理成可用的私钥用于生成签名 prikey = RSA.importKey(extern_key=private_key) if passphrase == '' else RSA.importKey(extern_key=private_key, passphrase=passphrase) # pem秘钥加密 except ValueError as ve: logs.error("秘钥处理异常, 请确保秘钥加密码正确:异常原因:{}".format(ve)) except Exception as e: logs.error("出现其他异常:原因:{}".format(e)) else: # 实例化一个签名对象 signer 传入处理后的私钥 signer = Signature_pkcs1_v1_5.new(prikey) # 信息需要先转换成 sha 字符串 digest = SHA1.new() if sha_mode in ['SHA1', 'SHA256', 'SHA512'] else sys.exit("请检查参数 sha_mode={}, Tips:仅支持SHA1/SHA256/SHA512, 如需其他方式请完善代码".format(sha_mode)) digest = SHA256.new() if sha_mode == 'SHA256' else digest digest = SHA512.new() if sha_mode == 'SHA512' else digest digest.update(self.message) # 对信息生成签名 signature = signer.sign(digest) # logs.debug(signature) # 生成的签名是字节串 将结果转换成 base64 字符串 auth_signature = base64.b64encode(signature) # logs.debug(auth_signature # 签名结果转换成字符串 signature = auth_signature.decode() # logs.debug(signature) return signature def rsa_verify(self, signature, passphrase='', sha_mode='SHA1'): """ 读取公钥用于验签 :param signature: 对验签内容签名的值 resp.sign :param passphrase: 秘钥加密码, 默认不加密 :param sha_mode: 算法模式:仅支持SHA1/SHA256 <SHA1的输出大小为160位。 SHA256的输出大小为256位> :return: """ # 读取公钥 with open(self.pubFile, 'rb') as public_file: public_key = public_file.read() try: # RSA 的 importKey() 方法将读取的公钥字符串 处理成可用的公钥用于验证签名 pubkey = RSA.importKey(extern_key=public_key) if passphrase == '' else RSA.importKey(extern_key=public_key, passphrase=passphrase) # pem秘钥加密 except ValueError as ve: logs.error("秘钥处理异常, 请确保秘钥加密码正确:异常原因:{}".format(ve)) except Exception as e: logs.error("出现其他异常:原因:{}".format(e)) else: # 实例化一个验证对象 verifier ,传入处理的公钥, verifier = Signature_pkcs1_v1_5.new(pubkey) digest = SHA1.new() if sha_mode in ['SHA1', 'SHA256', 'SHA512'] else sys.exit("请检查参数 sha_mode={}, Tips:仅支持SHA1/SHA256/SHA512, 如需其他方式请完善代码".format(sha_mode)) digest = SHA256.new() if sha_mode == 'SHA256' else digest digest = SHA512.new() if sha_mode == 'SHA512' else digest digest.update(self.message) # logs.debug(digest) # 对签名进行验证。 验证结果是一个布尔值,验证成功返回 True , 不成功返回 False 。 re = verifier.verify(digest, base64.b64decode(signature)) return re @staticmethod def rsa_key_iv_to_file(name='rsa', passphrase='', key_length=1024): """ crypto 模块生成RSA公钥私钥 :param name: 公私钥文件拼接名; 如 公钥:name+'_public_key.pem' 私钥:name+'_private_key.pem' :param passphrase: 秘钥加密密码 :param key_length: 秘钥长度 1024/ 2048 :return: """ random_g = Random.new().read rsa = RSA.generate(key_length, random_g) # 生成RSA公钥 crypto_key = rsa.public_key().exportKey() if passphrase == '' else rsa.public_key().exportKey(passphrase=passphrase) # passphrase 将秘钥加密 # print(crypto_key.decode()) # 生成RSA私钥 crypto_iv = rsa.exportKey() if passphrase == '' else rsa.exportKey(passphrase=passphrase) # passphrase 将秘钥加密 # print(crypto_iv.decode()) # 公私钥保存地址 cur_path = os.path.abspath(os.path.dirname(__file__)) # 获取当前文件的目录 proj_path = cur_path[:cur_path.find('base')] + 'data\\key_iv' # 获取根目录 public_key_path = os.path.join(proj_path, "{}_public_key.pem".format(name)) private_key_path = os.path.join(proj_path, "{}_private_key.pem".format(name)) # 保存数据 rsa_tools.sava_Loc(public_key_path, crypto_key) rsa_tools.sava_Loc(private_key_path, crypto_iv) return crypto_key, crypto_iv @staticmethod def sava_Loc(fileName, fileData): """保存数据到文件""" try: with open(fileName, "wb+") as f: f.write(fileData) except FileNotFoundError: os.makedirs(os.path.split(fileName)[0]) with open(fileName, "wb+") as f: f.write(fileData) if __name__ == '__main__': # code = '{"name": "zhangsan", "age": "112"}' code = '{"user_1":{"name":"zhangsan","age":"112","addr1":"zhangsan","tel1":"112","addr2":"zhangsan","tel2":"112","addr3":"zhangsan","tel3":"112","addr4":"zhangsan","tel4":"112","addr5":"zhangsan","tel5":"112","addr6":"zhangsan","tel6":"112","addr7":"zhangsan","tel7":"112","addr8":"zhangsan","tel8":"112","addr9":"zhangsan","tel9":"112"},"user_2":{"name":"zhangsan","age":"112","addr1":"zhangsan","tel1":"112","addr2":"zhangsan","tel2":"112","addr3":"zhangsan","tel3":"112","addr4":"zhangsan","tel4":"112","addr5":"zhangsan","tel5":"112","addr6":"zhangsan","tel6":"112","addr7":"zhangsan","tel7":"112","addr8":"zhangsan","tel8":"112","addr9":"zhangsan","tel9":"112"},"user_3":{"name":"zhangsan","age":"112","addr1":"zhangsan","tel1":"112","addr2":"zhangsan","tel2":"112","addr3":"zhangsan","tel3":"112","addr4":"zhangsan","tel4":"112","addr5":"zhangsan","tel5":"112","addr6":"zhangsan","tel6":"112","addr7":"zhangsan","tel7":"112","addr8":"zhangsan","tel8":"112","addr9":"zhangsan","tel9":"112"},"user_4":{"name":"zhangsan","age":"112","addr1":"zhangsan","tel1":"112","addr2":"zhangsan","tel2":"112","addr3":"zhangsan","tel3":"112","addr4":"zhangsan","tel4":"112","addr5":"zhangsan","tel5":"112","addr6":"zhangsan","tel6":"112","addr7":"zhangsan","tel7":"112","addr8":"zhangsan","tel8":"112","addr9":"zhangsan","tel9":"112"},"user_5":{"name":"zhangsan","age":"112","addr1":"zhangsan","tel1":"112","addr2":"zhangsan","tel2":"112","addr3":"zhangsan","tel3":"112","addr4":"zhangsan","tel4":"112","addr5":"zhangsan","tel5":"112","addr6":"zhangsan","tel6":"112","addr7":"zhangsan","tel7":"112","addr8":"zhangsan","tel8":"112","addr9":"zhangsan","tel9":"112"},"user_6":{"name":"zhangsan","age":"112","addr1":"zhangsan","tel1":"112","addr2":"zhangsan","tel2":"112","addr3":"zhangsan","tel3":"112","addr4":"zhangsan","tel4":"112","addr5":"zhangsan","tel5":"112","addr6":"zhangsan","tel6":"112","addr7":"zhangsan","tel7":"112","addr8":"zhangsan","tel8":"112","addr9":"zhangsan","tel9":"112"},"user_7":{"name":"zhangsan","age":"112","addr1":"zhangsan","tel1":"112","addr2":"zhangsan","tel2":"112","addr3":"zhangsan","tel3":"112","addr4":"zhangsan","tel4":"112","addr5":"zhangsan","tel5":"112","addr6":"zhangsan","tel6":"112","addr7":"zhangsan","tel7":"112","addr8":"zhangsan","tel8":"112","addr9":"zhangsan","tel9":"112"},"user_8":{"name":"zhangsan","age":"112","addr1":"zhangsan","tel1":"112","addr2":"zhangsan","tel2":"112","addr3":"zhangsan","tel3":"112","addr4":"zhangsan","tel4":"112","addr5":"zhangsan","tel5":"112","addr6":"zhangsan","tel6":"112","addr7":"zhangsan","tel7":"112","addr8":"zhangsan","tel8":"112","addr9":"zhangsan","tel9":"112"}}' # rsaObj_en = "ZI35e/yQjS9zDfU0B6Iz8gEEp/NqvdIGw4GoDA02SRcF4PKAIsJm4mfIsA5tNyEd1Pe5nTnYmm17Kl3EymkTbMN4N/Hg+4+azFPdckIEY1znpfJc3aHm9rYe41GgsduasImyraG39AVVvnmfWvxM6SgwHkdS5mqWg8C5lx+Y89c=" # enrsaen = 'j3wvfGbEn6YKlc79+eamDBSkTCftQ45mHyHw3OQwDL3TDQ/GxdrtBJRPwmOfDvdMAu8VnUNRnQrc2yDwud1/z+3z6IY7dLj/a3IJ7anv5+12lCcXUtEiB7BG2gOYL2u9mCG1jhKIBI+MZu7JtGNXJJHdyQCkeRedbkjw7GK9Wys=' """默认""" # # rsa_tools.rsa_key_iv_to_file() # 生成公私钥 public_key_path = os.path.join("{}_public_key.pem".format("rsa")) private_key_path = os.path.join("{}_private_key.pem".format("rsa")) try: rsaObj_en = rsa_tools(msg=code.encode("UTF-8"), pub_fname=public_key_path).rsa_get_encrypt() # 加密 rsaObj_de = rsa_tools(msg=rsaObj_en, pri_fname=private_key_path).rsa_get_decrypt() # 解密 logs.debug("数据加密:{}".format(rsaObj_en)) logs.debug("数据解密:{}".format(rsaObj_de)) except Exception as e: logs.error("异常原因:{}".format(e)) rsa_en = rsa_tools(msg=code.encode("UTF-8"), pub_fname=public_key_path).rsa_long_encrypt() # 加密 rsa_de = rsa_tools(msg=rsa_en, pri_fname=private_key_path).rsa_long_decrypt() # 解密 logs.debug("兼容超长数据加密:{}".format(rsa_en)) logs.debug("兼容超长数据解密:{}".format(rsa_de)) s = rsa_tools(msg=code.encode("utf-8"), pri_fname=private_key_path).rsa_sign(sha_mode='SHA512') a = rsa_tools(msg=code.encode("utf-8"), pub_fname=public_key_path).rsa_verify(signature=s, sha_mode='SHA512') logs.debug("签名:{}".format(s)) logs.debug("验签结果:{}".format(a)) """秘钥加密""" # # rsa_tools.rsa_key_iv_to_file(name='enrsa', passphrase='pem123') # 生成加密的公私钥 # public_key_path = os.path.join("{}_public_key.pem".format("enrsa")) # private_key_path = os.path.join("{}_private_key.pem".format("enrsa")) # # try: # rsaObj_en = rsa_tools(msg=code.encode("UTF-8"), pub_fname=public_key_path).rsa_get_encrypt(passphrase='pem123') # 加密 # rsaObj_de = rsa_tools(msg=rsaObj_en, pri_fname=private_key_path).rsa_get_decrypt('pem123') # 解密 # logs.debug("数据加密(加密的rsa公钥):{}".format(rsaObj_en)) # logs.debug("数据解密(加密的rsa私钥):{}".format(rsaObj_de)) # except Exception as e: # logs.error("异常原因:{}".format(e)) # # rsa_en = rsa_tools(msg=code.encode("UTF-8"), pub_fname=public_key_path).rsa_long_encrypt(passphrase='pem123') # 秘钥加密 # rsa_de = rsa_tools(msg=rsa_en, pri_fname=private_key_path).rsa_long_decrypt(passphrase='pem123') # 秘钥加密 # logs.debug("兼容超长数据加密(加密的rsa公钥):{}".format(rsa_en)) # logs.debug("兼容超长数据解密(加密的rsa私钥):{}".format(rsa_de)) # # s = rsa_tools(msg=code.encode("utf-8"), pri_fname=private_key_path).rsa_sign(passphrase='pem123') # a = rsa_tools(msg=code.encode("utf-8"), pub_fname=public_key_path).rsa_verify(signature=s, passphrase='pem123') # logs.debug("签名(加密的rsa私钥):{}".format(s)) # logs.debug("验签结果(加密的rsa公钥):{}".format(a))
执行结果
拓展
问题1:引用crypto时提示:ModuleNotFoundError: No module named 'Crypto'
解决方法:将site-package下的crypto文件夹该问Crypto
问题2:运行提示:TypeError: a bytes-like object is required, not 'str'
检查 bytes和str两种类型转换使用正确;转为bytes:encode()、转为str:decode()
问题3:ValueError: Plaintext is too long.
加密的plaintext最大长度是证书key位数/8 - 11,例如1024 bit的证书,被加密的串最长1024/8 - 11 = 117,
解决办法是分块加密,然后分块解密证书key固定,加密的串长度也固定
-
- 代码实现
-
# -*- coding:utf-8 -*- import json import os import base64 import sys from urllib.parse import * from Crypto import Random from Crypto.Hash import SHA1 from Crypto.PublicKey import RSA # Crypto模块中的pkcs1_v1_5对应pkcs8格式 from Crypto.Cipher import PKCS1_v1_5 as Cipher_pkcs1_v1_5 from Crypto.Signature import PKCS1_v1_5 as Signature_pkcs1_v1_5 from aa_demo.base.logger import * class rsa_tools: """RSA PKCS8 SHA1 加解密工具""" def __init__(self, msg, pub_fname="", pri_fname=""): """ RSA 加解密,加签 验签 :param msg: 需要加密的信息 传参时需要对msg进行encode 示例,rsa_tools(msg.encode("UTF-8")) :param pub_fname: 公钥文件名 路径:./data/key_iv/ + pub_fname :param pri_fname: 私钥文件名 路径:./data/key_iv/ + pri_fname """ self.message = msg # logs.debug(self.message) cur_path = os.path.abspath(os.path.dirname(__file__)) # 获取当前文件的目录 proj_path = cur_path[:cur_path.find('base')] + 'data\\key_iv' # 获取根目录 # :param pub_file: 公钥/私钥文件 路径 self.pubFile = os.path.join(proj_path, "{}".format(pub_fname)) self.priFile = os.path.join(proj_path, "{}".format(pri_fname)) # logs.debug(self.pubFile) # logs.debug(self.priFile) def rsa_long_encrypt(self, passphrase='', length=100): """ 超长文本加密 :param passphrase: 秘钥加密码,默认不加密 :param length: 1024bit的证书用100, 2048bit的证书用 200 :return: """ # 读取公钥 with open(self.pubFile, 'rb') as public_file: public_key = public_file.read() try: rsakey = RSA.importKey(public_key) if passphrase == '' else RSA.importKey(extern_key=public_key, passphrase=passphrase) # pem秘钥加密 except ValueError as ve: logs.error("秘钥处理异常, 请确保秘钥加密码正确:异常原因:{}".format(ve)) except Exception as e: logs.error("出现其他异常:原因:{}".format(e)) else: cipher = Cipher_pkcs1_v1_5.new(rsakey) # 处理:Plaintext is too long. 分段加密 if len(self.message) <= length: # 对编码的数据进行加密,并通过base64进行编码 result = base64.b64encode(cipher.encrypt(self.message)) else: rsa_text = [] # 对编码后的数据进行切片,原因:加密长度不能过长 for i in range(0, len(self.message), length): cont = self.message[i:i + length] # 对切片后的数据进行加密,并新增到text后面 rsa_text.append(cipher.encrypt(cont)) # 加密完进行拼接 cipher_text = b''.join(rsa_text) # base64进行编码 result = base64.b64encode(cipher_text) return result def rsa_long_decrypt(self, passphrase='', length=128): """ 超长文本解密,默认不加密 :param passphrase: 秘钥加密码 :param length: 1024bit的证书用128,2048bit证书用256位 :return: """ # 读取私钥 with open(self.priFile, 'rb') as private_file: private_key = private_file.read() try: # 使用 RSA 的 importKey()方法将 读取的私钥字符串 处理成可用的解密私钥 rsakey = RSA.importKey(extern_key=private_key) if passphrase == '' else RSA.importKey(extern_key=private_key, passphrase=passphrase) # pem秘钥解密 except ValueError as ve: logs.error("秘钥处理异常, 请确保秘钥加密码正确:异常原因:{}".format(ve)) except Exception as e: logs.error("出现其他异常:原因:{}".format(e)) else: # 实例化一个解密对象 cipher 传私钥对信息进行解密 解密结果与加密之前保持一致 cipher = Cipher_pkcs1_v1_5.new(rsakey) # base64 解密字符串 base64_de = base64.b64decode(self.message) # 对解码后的数据进行切片,原因:长度不正确的密文(不是128字节) res = [] for i in range(0, len(base64_de), length): res.append(cipher.decrypt(base64_de[i:i + length], 'xyz')) return b"".join(res) if __name__ == '__main__': # code = '{"name": "zhangsan", "age": "112"}' code = '{"user_1":{"name":"zhangsan","age":"112","addr1":"zhangsan","tel1":"112","addr2":"zhangsan","tel2":"112","addr3":"zhangsan","tel3":"112","addr4":"zhangsan","tel4":"112","addr5":"zhangsan","tel5":"112","addr6":"zhangsan","tel6":"112","addr7":"zhangsan","tel7":"112","addr8":"zhangsan","tel8":"112","addr9":"zhangsan","tel9":"112"},"user_2":{"name":"zhangsan","age":"112","addr1":"zhangsan","tel1":"112","addr2":"zhangsan","tel2":"112","addr3":"zhangsan","tel3":"112","addr4":"zhangsan","tel4":"112","addr5":"zhangsan","tel5":"112","addr6":"zhangsan","tel6":"112","addr7":"zhangsan","tel7":"112","addr8":"zhangsan","tel8":"112","addr9":"zhangsan","tel9":"112"},"user_3":{"name":"zhangsan","age":"112","addr1":"zhangsan","tel1":"112","addr2":"zhangsan","tel2":"112","addr3":"zhangsan","tel3":"112","addr4":"zhangsan","tel4":"112","addr5":"zhangsan","tel5":"112","addr6":"zhangsan","tel6":"112","addr7":"zhangsan","tel7":"112","addr8":"zhangsan","tel8":"112","addr9":"zhangsan","tel9":"112"},"user_4":{"name":"zhangsan","age":"112","addr1":"zhangsan","tel1":"112","addr2":"zhangsan","tel2":"112","addr3":"zhangsan","tel3":"112","addr4":"zhangsan","tel4":"112","addr5":"zhangsan","tel5":"112","addr6":"zhangsan","tel6":"112","addr7":"zhangsan","tel7":"112","addr8":"zhangsan","tel8":"112","addr9":"zhangsan","tel9":"112"},"user_5":{"name":"zhangsan","age":"112","addr1":"zhangsan","tel1":"112","addr2":"zhangsan","tel2":"112","addr3":"zhangsan","tel3":"112","addr4":"zhangsan","tel4":"112","addr5":"zhangsan","tel5":"112","addr6":"zhangsan","tel6":"112","addr7":"zhangsan","tel7":"112","addr8":"zhangsan","tel8":"112","addr9":"zhangsan","tel9":"112"},"user_6":{"name":"zhangsan","age":"112","addr1":"zhangsan","tel1":"112","addr2":"zhangsan","tel2":"112","addr3":"zhangsan","tel3":"112","addr4":"zhangsan","tel4":"112","addr5":"zhangsan","tel5":"112","addr6":"zhangsan","tel6":"112","addr7":"zhangsan","tel7":"112","addr8":"zhangsan","tel8":"112","addr9":"zhangsan","tel9":"112"},"user_7":{"name":"zhangsan","age":"112","addr1":"zhangsan","tel1":"112","addr2":"zhangsan","tel2":"112","addr3":"zhangsan","tel3":"112","addr4":"zhangsan","tel4":"112","addr5":"zhangsan","tel5":"112","addr6":"zhangsan","tel6":"112","addr7":"zhangsan","tel7":"112","addr8":"zhangsan","tel8":"112","addr9":"zhangsan","tel9":"112"},"user_8":{"name":"zhangsan","age":"112","addr1":"zhangsan","tel1":"112","addr2":"zhangsan","tel2":"112","addr3":"zhangsan","tel3":"112","addr4":"zhangsan","tel4":"112","addr5":"zhangsan","tel5":"112","addr6":"zhangsan","tel6":"112","addr7":"zhangsan","tel7":"112","addr8":"zhangsan","tel8":"112","addr9":"zhangsan","tel9":"112"}}' # rsaObj_en = "ZI35e/yQjS9zDfU0B6Iz8gEEp/NqvdIGw4GoDA02SRcF4PKAIsJm4mfIsA5tNyEd1Pe5nTnYmm17Kl3EymkTbMN4N/Hg+4+azFPdckIEY1znpfJc3aHm9rYe41GgsduasImyraG39AVVvnmfWvxM6SgwHkdS5mqWg8C5lx+Y89c=" # enrsaen = 'j3wvfGbEn6YKlc79+eamDBSkTCftQ45mHyHw3OQwDL3TDQ/GxdrtBJRPwmOfDvdMAu8VnUNRnQrc2yDwud1/z+3z6IY7dLj/a3IJ7anv5+12lCcXUtEiB7BG2gOYL2u9mCG1jhKIBI+MZu7JtGNXJJHdyQCkeRedbkjw7GK9Wys=' """默认""" # # rsa_tools.rsa_key_iv_to_file() # 生成公私钥 public_key_path = os.path.join("{}_public_key.pem".format("rsa")) private_key_path = os.path.join("{}_private_key.pem".format("rsa")) rsa_en = rsa_tools(msg=code.encode("UTF-8"), pub_fname=public_key_path).rsa_long_encrypt() # 加密 rsa_de = rsa_tools(msg=rsa_en, pri_fname=private_key_path).rsa_long_decrypt() # 解密 logs.debug("兼容超长数据加密:{}".format(rsa_en)) logs.debug("兼容超长数据解密:{}".format(rsa_de))
- 执行结果
-
注意:
从 Crypto.Cipher 中导入 PKCS1_v1_5 ,导入时记得重命名一下,如 PKCS1_cipher
因为在 Crypto 的另一个模块 Crypto.Signature 中也有同名的类 PKCS1_v1_5
同时使用时不重命名会造成冲突
如果万事开头难 那请结局一定圆满 @ Phoenixy
-------------------------------------------------------------------------------------