一、 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
同時使用時不重命名會造成沖突