简介
最近工作需要对接接口,我记录了实现RSA加解密的3种不同方式,希望给有需要的人带来帮助
使用的Python版本为3.10.13
第一种:RSA包
需要安装RSA包
pip install rsa
具体代码如下
# rsa==4.9
import json
import base64
import rsa
# `RsaRsaUtil` 类提供使用 RSA 加密来加密、解密、签名和验证数据的方法。
class RsaRsaUtil:
def __init__(self, rsa_publicKey: str = None, rsa_privateKey: str = None):
"""
公钥私钥为不带开头的文本
这里公钥与私钥是对方给的,不是同一对秘钥(也可以是同一对)
:param rsa_publicKey: rsa_publicKey
:param rsa_privateKey: rsa_privateKey
"""
self.public_key = rsa.PublicKey.load_pkcs1(rsa_publicKey)
self.private_key = rsa.PrivateKey.load_pkcs1(rsa_privateKey)
def decrypt(self, data: str) -> str:
"""
“解密”函数接收字符串“data”,使用公钥对其进行解密,并将解密后的数据作为字符串返回。
:param data: “data”参数是一个字符串,表示要解密的数据。
:type data: str
:return: “解密”函数返回一个解密的字符串。
"""
if isinstance(data, str):
data = data.encode('utf-8')
data = base64.b64decode(data)
# default_length = 128
default_length = 256 #1024bit的证书用128,2048bit证书用256位
length = len(data)
# print(length)
if len(data) < default_length:
res_data = rsa.decrypt(data, self.private_key)
return str(res_data, encoding='utf8')
else:
# 文本太长,需要分段解密
offset = 0
res = []
while length - offset > 0:
if length - offset > default_length:
res.append(rsa.decrypt(data[offset:offset + default_length], self.private_key))
else:
res.append(rsa.decrypt(data[offset:], self.private_key))
offset += default_length
res_data = b''.join(res)
return str(res_data, encoding='utf8')
def encrypt(self, data: str) -> str:
"""
“加密”函数接收字符串“data”,使用私钥对其进行解密,并将解密后的数据作为字符串返回。
:param data: “data”参数是一个字符串,表示要加密的数据。
:type data: str
:return: “加密”函数返回一个解密的字符串。
"""
if isinstance(data, str):
data = data.encode('utf-8')
length = len(data)
default_length = 117
if length < default_length:
res_data = rsa.encrypt(data, self.public_key)
return str(base64.b64encode(res_data), encoding='utf8')
# 需要分段加密
offset = 0
res = []
while length - offset > 0:
if length - offset > default_length:
res.append(rsa.encrypt(data[offset:offset + default_length], self.public_key))
else:
res.append(rsa.encrypt(data[offset:], self.public_key))
offset += default_length
res_data = b''.join(res)
return str(base64.b64encode(res_data), encoding='utf8')
def sign(self, data: str) -> str:
"""
“签名”函数接收字符串“data”,使用私钥对其进行签名,并将签名后的数据作为字符串返回。
:param data: “data”参数是一个字符串,表示要签名的数据。
:type data: str
:return: “签名”函数返回一个签名的字符串。
"""
data = data.encode('utf-8')
signature = rsa.sign(data, self.private_key, 'SHA-256')
return str(base64.b64encode(signature), encoding='utf8')
def verify(self, data: str, sign: str) -> bool:
"""
验签
"""
if isinstance(data, str):
data = data.encode('utf-8')
# data = base64.b64decode(data)
if isinstance(sign, str):
sign = sign.encode('utf-8')
sign = base64.b64decode(sign)
try:
rsa.verify(data, sign, self.public_key)
print('The signature is valid.')
return True
except (ValueError,TypeError):
print('The signature is invalid.')
return False
if __name__ == '__main__':
# 生成新的rsa秘钥对
# (public_key, private_key) = rsa.newkeys(1024)
# public_key = public_key.save_pkcs1().decode('utf-8')
# private_key = private_key.save_pkcs1().decode('utf-8')
# 使用现有秘钥对
with open('public_key.pem', 'r') as f:
public_key = f.read()
with open('private_key.pem', 'r') as f:
private_key = f.read()
rsaUtil = RsaRsaUtil(rsa_publicKey=public_key, rsa_privateKey=private_key)
msg = {
"key1": "This is a random string that contains random characters and numbers.",
"key2": "Another random string with more random characters and numbers.",
"key3": "Here is another random string that may contain special characters and spaces.",
"key4": "This string is longer and contains more random characters and numbers.",
"key5": "A random string with some special characters and spaces.",
"key6": "This is a random string that may contain special characters and spaces.",
"key7": "Here is another random string that may contain more special characters and spaces.",
"key8": "This string is longer and contains more random characters and numbers.",
"key9": "A random string with some special characters and spaces.",
"key10": "This is a very long random string that may contain more special characters and spaces."
}
data = json.dumps(msg)
data = "xxxxxxxxeerererre"
# 加密
data_encrypt = rsaUtil.encrypt(data)
print(data_encrypt)
# # 解密
data_decrypt = rsaUtil.decrypt(data_encrypt)
print(data_decrypt)
# 加签名
signature = rsaUtil.sign(data)
print(signature)
# 验签
print(rsaUtil.verify(data, signature))
第二种:pycryptodome
许安装pycryptodome包
pip install pycryptodome==3.19.0
代码如下
# pycryptodome==3.19.0
import json
import base64
from Crypto.Hash import SHA256
from Crypto.PublicKey import RSA
from Crypto.Signature import PKCS1_v1_5
from Crypto.Cipher import PKCS1_v1_5 as Cipher_pkcs1_v1_5
# `CryptoRsaUtil` 类提供使用 RSA 加密来加密、解密、签名和验证数据的方法。
class CryptoRsaUtil:
def __init__(self, rsa_publicKey: str = None, rsa_privateKey: str = None):
"""
公钥私钥为不带开头的文本
这里公钥与私钥是对方给的,不是同一对秘钥(也可以是同一对)
:param rsa_publicKey: rsa_publicKey
:param rsa_privateKey: rsa_privateKey
"""
self.public_key = RSA.importKey(rsa_publicKey)
self.private_key = RSA.importKey(rsa_privateKey)
def decrypt(self, data: str) -> str:
"""
“解密”函数接收字符串“data”,使用公钥对其进行解密,并将解密后的数据作为字符串返回。
:param data: “data”参数是一个字符串,表示要解密的数据。
:type data: str
:return: “解密”函数返回一个解密的字符串。
"""
data = base64.b64decode(data)
length = len(data)
print(length)
# default_length = 128
default_length = 256 #1024bit的证书用128,2048bit证书用256位
# 私钥解密
priobj = Cipher_pkcs1_v1_5.new(self.private_key)
# 长度不用分段
if length < default_length:
return b''.join(priobj.decrypt(data, b' '))
# 需要分段
offset = 0
res = []
while length - offset > 0:
if length - offset > default_length:
res.append(priobj.decrypt(data[offset:offset + default_length], b' '))
else:
res.append(priobj.decrypt(data[offset:], b' '))
offset += default_length
res_data = b''.join(res)
return str(res_data, encoding='utf8')
def encrypt(self, data: str) -> str:
"""
“加密”函数接收字符串“data”,使用私钥对其进行解密,并将解密后的数据作为字符串返回。
:param data: “data”参数是一个字符串,表示要加密的数据。
:type data: str
:return: “加密”函数返回一个解密的字符串。
"""
length = len(data)
#单次加密串的长度最大为 (key_size/8)-11,1024bit的证书用100, 2048bit的证书用 200
default_length = 117
# default_length = 100
# 公钥加密
pubobj = Cipher_pkcs1_v1_5.new(self.public_key)
# 长度不用分段
if length < default_length:
return str(base64.b64encode(pubobj.encrypt(data.encode('utf-8'))), encoding='utf8')
# 需要分段
offset = 0
res = []
while length - offset > 0:
if length - offset > default_length:
res.append(pubobj.encrypt(data[offset:offset + default_length].encode('utf-8')))
else:
res.append(pubobj.encrypt(data[offset:].encode('utf-8')))
offset += default_length
byte_data = b''.join(res)
return str(base64.b64encode(byte_data), encoding='utf8')
def sign(self, data: str) -> str:
"""
“签名”函数接收字符串“data”,使用私钥对其进行签名,并将签名后的数据作为字符串返回。
:param data: “data”参数是一个字符串,表示要签名的数据。
:type data: str
:return: “签名”函数返回一个签名的字符串。
"""
data = data.encode('utf-8')
hash_obj = SHA256.new(data)
signer = PKCS1_v1_5.new(self.private_key)
signature = signer.sign(hash_obj)
return str(base64.b64encode(signature), encoding='utf8')
def verify(self, data: str, sign: str) -> bool:
if isinstance(data, str):
data = data.encode('utf-8')
if isinstance(sign, str):
sign = sign.encode('utf-8')
#data做“哈希”处理,RSA签名这么要求的
hash_obj = SHA256.new(data)
try:
#因为签名被base64编码,所以这里先解码,再验签
PKCS1_v1_5.new(self.public_key).verify(hash_obj,base64.b64decode(sign))
print('The signature is valid.')
return True
except (ValueError,TypeError):
print('The signature is invalid.')
return False
if __name__ == '__main__':
x = RSA.generate(2048)
private_key = str(x.export_key(), encoding = "utf-8") #私钥
public_key = str(x.publickey().export_key(), encoding = "utf-8") #公钥
rsa = CryptoRsaUtil(rsa_publicKey=public_key, rsa_privateKey=private_key)
msg = {
"key1": "This is a random string that contains random characters and numbers.",
"key2": "Another random string with more random characters and numbers.",
"key3": "Here is another random string that may contain special characters and spaces.",
"key4": "This string is longer and contains more random characters and numbers.",
"key5": "A random string with some special characters and spaces.",
"key6": "This is a random string that may contain special characters and spaces.",
"key7": "Here is another random string that may contain more special characters and spaces.",
"key8": "This string is longer and contains more random characters and numbers.",
"key9": "A random string with some special characters and spaces.",
"key10": "This is a very long random string that may contain more special characters and spaces."
}
data = json.dumps(msg)
# 加密
data_encrypt = rsa.encrypt(data)
print(data_encrypt)
# 解密
data_decrypt = rsa.decrypt(data_encrypt)
print(data_decrypt)
# 加签名
signature = rsa.sign(data)
print(signature)
# 验签
print(rsa.verify(data, signature))
第三种:cryptography
需安装cryptography包
pip install cryptography==41.0.7
代码如下
# cryptography==41.0.7
import json
import base64
from cryptography.hazmat.primitives import serialization, hashes
from cryptography.hazmat.primitives.asymmetric import padding, rsa
# `CryptographyRsaUtil` 类提供使用 RSA 加密来加密、解密、签名和验证数据的方法。
class CryptographyRsaUtil:
def __init__(self, rsa_publicKey: str = None, rsa_privateKey: str = None):
"""
公钥私钥为不带开头的文本
这里公钥与私钥是对方给的,不是同一对秘钥(也可以是同一对)
:param rsa_publicKey: rsa_publicKey
:param rsa_privateKey: rsa_privateKey
"""
self.public_key = serialization.load_pem_public_key(rsa_publicKey.encode())
self.private_key = serialization.load_pem_private_key(rsa_privateKey.encode(), password=None)
def decrypt(self, data: str) -> str:
"""
“解密”函数接收字符串“data”,使用公钥对其进行解密,并将解密后的数据作为字符串返回。
:param data: “data”参数是一个字符串,表示要解密的数据。
:type data: str
:return: “解密”函数返回一个解密的字符串。
"""
if isinstance(data, str):
data = data.encode()
res_data = self.private_key.decrypt(
base64.b64decode(data),
padding=padding.PKCS1v15()
)
return str(res_data, encoding='utf8')
def encrypt(self, data: str) -> str:
"""
“加密”函数接收字符串“data”,使用私钥对其进行解密,并将解密后的数据作为字符串返回。
:param data: “data”参数是一个字符串,表示要加密的数据。
:type data: str
:return: “加密”函数返回一个解密的字符串。
"""
if isinstance(data, str):
data = data.encode()
res_data = self.public_key.encrypt(
data,
padding=padding.PKCS1v15()
)
return str(base64.b64encode(res_data), encoding='utf8')
def sign(self, data: str) -> str:
"""
“签名”函数接收字符串“data”,使用私钥对其进行签名,并将签名后的数据作为字符串返回。
:param data: “data”参数是一个字符串,表示要签名的数据。
:type data: str
:return: “签名”函数返回一个签名的字符串。
"""
signature = self.private_key.sign(
data.encode(),
padding.PKCS1v15(),
hashes.SHA256()
)
return str(base64.b64encode(signature), encoding='utf8')
def verify(self, data: str, sign: str) -> bool:
if isinstance(data, str):
data = data.encode('utf-8')
if isinstance(sign, str):
sign = sign.encode('utf-8')
bysign = base64.b64decode(sign)
try:
#因为签名被base64编码,所以这里先解码,再验签
self.public_key.verify(
bysign,
data,
padding.PKCS1v15(),
hashes.SHA256())
print('The signature is valid.')
return True
except (ValueError,TypeError):
print('The signature is invalid.')
return False
if __name__ == '__main__':
# 生成公钥私钥
# 长的字符串需要长的秘钥才能加密
private_key_obj = rsa.generate_private_key(
public_exponent=65537,
key_size=2048*3
)
public_key_obj = private_key_obj.public_key()
public_key = public_key_obj.public_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PublicFormat.SubjectPublicKeyInfo
)
private_key = private_key_obj.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.PKCS8,
encryption_algorithm=serialization.NoEncryption()
)
# print(public_key)
# print(private_key)
public_key = public_key.decode('utf-8')
private_key = private_key.decode('utf-8')
rsaUtil = CryptographyRsaUtil(rsa_publicKey=public_key, rsa_privateKey=private_key)
msg = {
"key1": "This is a random string that contains random characters and numbers.",
"key2": "Another random string with more random characters and numbers.",
"key3": "Here is another random string that may contain special characters and spaces.",
"key4": "This string is longer and contains more random characters and numbers.",
"key5": "A random string with some special characters and spaces.",
"key6": "This is a random string that may contain special characters and spaces.",
"key7": "Here is another random string that may contain more special characters and spaces.",
"key8": "This string is longer and contains more random characters and numbers.",
"key9": "A random string with some special characters and spaces.",
"key10": "This is a very long random string that may contain more special characters and spaces."
}
data = json.dumps(msg)
# data = "b0989a5c4b93b02957973a9dc41e032e"
# 加密
data_encrypt = rsaUtil.encrypt(data)
print(data_encrypt)
# 解密
data_decrypt = rsaUtil.decrypt(data_encrypt)
print(data_decrypt)
# # 加签名
signature = rsaUtil.sign(data)
print(signature)
# # 验签
print(rsaUtil.verify(data, signature))
📌注意:cryptography包需要更长的秘钥去加密更长的密文。
若用同一套秘钥,且填充方式为PKCS1v15,与第一、第二种加解密可以互通
网友评论