**
生成非对称密钥对
**
generateKey.py
from Crypto import Random
from Crypto.PublicKey import RSA
# 伪随机数生成器
random_generator = Random.new().read
# rsa算法生成实例
rsa = RSA.generate(1024, random_generator)
# 私钥的生成
private_pem = rsa.exportKey()
with open("private.pem", "wb") as f:
f.write(private_pem)
# 公钥的生成
public_pem = rsa.publickey().exportKey()
with open("public.pem", "wb") as f:
f.write(public_pem)
**
加密(公钥)
**
import base64
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5
# 加密
message = "Hello,This is RSA加密"
data = open("public.pem").read()
rsakey = RSA.importKey(data)
# 创建用于执行pkcs1_v1_5加密或者解密的密码
cipher = PKCS1_v1_5.new(rsakey)
cipher_text = base64.b64encode(cipher.encrypt(message.encode()))
print(cipher_text.decode())
结果
BoNOpo+YEcYoI/vOqmf0AtqfZn49MxiWbYXE+qY7Coz3TjmkGKxkooQ6Mwa2lCRjc2CoPee8YTcuGUA6ncLB+C1JlRTSzbHqfbch22SivsriPMUNoWWZUMY6nNDTE95aZrcNZs32MP7IGrLP/Yev/548Z9iIPzPg/+UHPyLgtPo=
这里每次使用公钥加密后的结果都不一致,跟对数据的padding即填充有关。
加密时支持的最大字节数与证书有一定关系。加密时支持的最大字节数:证书位数/8 -11(比如:2048位的证书,支持的最大加密字节数:2048/8 - 11 = 245)
1024位的证书,加密时最大支持117个字节,解密时为128;
2048位的证书,加密时最大支持245个字节,解密时为256。
如果需要加密的字节数超出证书能加密的最大字节数,此时就需要进行分段加密。
**
解密(私钥)
**
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5
import base64
cipher_text ="BoNOpo+YEcYoI/vOqmf0AtqfZn49MxiWbYXE+qY7Coz3TjmkGKxkooQ6Mwa2lCRjc2CoPee8YTcuGUA6ncLB+C1JlRTSzbHqfbch22SivsriPMUNoWWZUMY6nNDTE95aZrcNZs32MP7IGrLP/Yev/548Z9iIPzPg/+UHPyLgtPo="
encrypt_text = cipher_text.encode()
rsakey = RSA.importKey(open("private.pem").read())
# 创建用于执行pkcs1_v1_5加密或者解密的密码
cipher = PKCS1_v1_5.new(rsakey)
text = cipher.decrypt(base64.b64decode(encrypt_text), False)
print(text.decode('utf-8'))
结果
Hello,This is RSA加密
**
签名(私钥)
使用私钥加签,每次签名是一致的。
**
from Crypto.PublicKey import RSA
from Crypto.Signature import PKCS1_v1_5
from Crypto.Hash import SHA
import base64
#加签
message = "This is a request message..."
rsakey = RSA.importKey(open("private.pem").read())
signer = PKCS1_v1_5.new(rsakey)
digest = SHA.new()
digest.update(message.encode("utf-8"))
sign = signer.sign(digest)
signature = base64.b64encode(sign)
print(signature.decode('utf-8'))
结果
g4jS1+6Y7EMjTXZo5TYEXxBbAmzo1W3LgED43STOh6oZ8DqN5CvaNLG5W7f3d0PX/v+39dD4iMHzoIyfHo5CBMoAdnUA5YGbJdUqbY0Gad/9aIGn2AKhCOXqXnvKAfrVZXfM44hzFGwba7OcYFO+TMvi9uqmst3ImL0g/gbWf4c=
**
验签(公钥)
**
from Crypto.PublicKey import RSA
from Crypto.Signature import PKCS1_v1_5
from Crypto.Hash import SHA
import base64
#验签
message_verify = "This is a request message..."
signature = "g4jS1+6Y7EMjTXZo5TYEXxBbAmzo1W3LgED43STOh6oZ8DqN5CvaNLG5W7f3d0PX/v+39dD4iMHzoIyfHo5CBMoAdnUA5YGbJdUqbY0Gad/9aIGn2AKhCOXqXnvKAfrVZXfM44hzFGwba7OcYFO+TMvi9uqmst3ImL0g/gbWf4c="
rsakey = RSA.importKey(open("public.pem").read())
verifier = PKCS1_v1_5.new(rsakey)
hsmsg = SHA.new()
hsmsg.update(message_verify.encode("utf-8"))
is_verify = verifier.verify(hsmsg, base64.b64decode(signature))
print(is_verify)
结果
True
问题:对长字符串如何进行加密报错
File “E:\venv\practice_env\lib\site-packages\Crypto\Cipher\PKCS1_v1_5.py”, line 107, in encrypt
raise ValueError(“Plaintext is too long.”)
ValueError: Plaintext is too long.
import base64
import json
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签名和加解密
# 公钥私钥在线生成网站:http://web.chacuo.net/netrsakeypair
class RsaUtil(object):
# PUBLIC_KEY_PATH = r'E:\code\actionultra\practice\RSA(python)\public.pem' # 公钥
public_key = """-----BEGIN PUBLIC KEY-----
-----END PUBLIC KEY-----"""
# PRIVATE_KEY_PATH = r'E:\code\actionultra\practice\RSA(python)\private.pem' # 私钥
private_key = """-----BEGIN RSA PRIVATE KEY-----
-----END RSA PRIVATE KEY-----"""
def __init__(self,
public_key=public_key ,
private_key=private_key):
if public_key:
self.company_public_key = RSA.importKey(public_key)
if private_key:
self.company_private_key = RSA.importKey(private_key)
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).decode()
return encrypt_result
# 加密 支付方私钥
def encrypt_by_private_key(self, encrypt_message):
"""使用私钥加密.
:param encrypt_message: 需要加密的内容.
加密之后需要对接过进行base64转码
"""
encrypt_result = ""
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())
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 += out_data.decode(encoding='utf-8').encode(encoding='utf-8').strip() # 此处不能使用 str(out_data) 直接转换bytes
return decrypt_result.decode(encoding='utf-8')
# 签名 商户私钥 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)
if __name__ == '__main__':
message = {
"machine_code": "TOUG:OH2S:QIBB:ZFWD:VDVJ:DBDV:T6Q4:Z5LH:XNYA:2OKR:OIZB:3P5N",
"max_people_count": 70,
"expire_time": "2022-08-31"
}
message = json.dumps(message)
# message = ['HY2S:QKUL:J3Y5:IAJT:CID4:PV3N:NALY:BKXC:SCQF:NBN5:D7XA:ZTUN',"20","2022-05-12"]
# message = json.dumps(message)
print("明文内容:>>> ")
print(message)
rsaUtil = RsaUtil()
encrypy_result = rsaUtil.encrypt_by_public_key(message)
print("加密结果:>>> ")
print(type(encrypy_result),encrypy_result)
with open("./licence.key", "w", encoding='utf-8') as f:
f.write(encrypy_result)
print("licence.key---------写入成功")
decrypt_result = rsaUtil.decrypt_by_private_key(encrypy_result)
print("解密结果:>>> ")
print(decrypt_result)
运行安装模块
pip install pycryptodome==3.14.1
按照报错信息,缺少依赖信息
解决办法:
python -m pip install --upgrade --force pip
pip install pycryptodome==3.14.1