本文链接: https://blog.csdn.net/xietansheng/article/details/115559295
1. pycryptodome/Crypto 模块
pycryptodome
模块文档: https://pycryptodome.readthedocs.io/en/latest/
使用第三方模块pycryptodome
中的Crypto.PublicKey.RSA
实现 RSA 秘钥对生成、加密/解密、签名/验签。
安装pycryptodome
模块:
pip3 install pycryptodome
1.1 生成 RSA 秘钥对
生成一对 RSA 密钥(公钥、私钥),并保持到文件:
from Crypto.PublicKey import RSA
# 生成一对长度为 2048 位的 RSA 秘钥对, 使用默认的随机数生成函数,
# 也可以手动指定一个随机数生成函数: randfunc=Crypto.Random.new().read
rsa_key = RSA.generate(2048)
print(rsa_key) # Private RSA key at 0x7FB241173748
print(type(rsa_key)) # <class 'Crypto.PublicKey.RSA.RsaKey'>
# 导出公钥, "PEM" 表示使用文本编码输出, 返回的是 bytes 类型, 格式如下:
# b'-----BEGIN PUBLIC KEY-----\n{Base64Text}\n-----END PUBLIC KEY-----'
# 输出格式可选: "PEM", "DER", "OpenSSH"
pub_key = rsa_key.publickey().export_key("PEM")
# 导出私钥, "PEM" 表示使用文本编码输出, 返回的是 bytes 类型, 格式如下:
# b'-----BEGIN RSA PRIVATE KEY-----\n{Base64Text}\n-----END RSA PRIVATE KEY-----'
pri_key = rsa_key.export_key("PEM")
# 转换为文本打印输出公钥和私钥
print(pub_key.decode())
print(pri_key.decode())
# 把公钥和私钥保存到文件
with open("pub.pem", "wb") as pub_fp:
pub_fp.write(pub_key)
with open("pri.pem", "wb") as pri_fp:
pri_fp.write(pri_key)
1.2 RSA 非对称加密/解密(公钥加密、私钥解密)
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5
""" 1. 生成秘钥对, 创建 公钥/私钥 对象 """
# 生成一对长度为 2048 位的 RSA 秘钥对
rsa_key = RSA.generate(2048)
# 从秘钥对中获取 公钥 对象, 返回类型为: <class 'Crypto.PublicKey.RSA.RsaKey'>
pub_key = rsa_key.publickey()
# 秘钥对本身就是 私钥 对象, 类型为: <class 'Crypto.PublicKey.RSA.RsaKey'>
pri_key = rsa_key
""" 2. 创建密码器, 加密/解密 """
# 创建 公钥 密码器, 返回类型为: <class 'Crypto.Cipher.PKCS1_v1_5.PKCS115_Cipher'>
pub_cipher = PKCS1_v1_5.new(pub_key)
# 加密内容(bytes), 返回加密后的密文(bytes类型)
ciphertext = pub_cipher.encrypt("Hello World".encode())
# 创建 私钥 密码器, 返回类型为: <class 'Crypto.Cipher.PKCS1_v1_5.PKCS115_Cipher'>
pri_cipher = PKCS1_v1_5.new(pri_key)
# 解密密文(bytes), 返回解密后的明文(bytes类型)
plaintext = pri_cipher.decrypt(ciphertext, sentinel=None)
""" 3. 查看结果 """
# 输出解密后的明文, 结果为: "Hello World"
print(plaintext.decode())
1.3 读取 RAS 秘钥对并进行非对称加密/解密
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5
""" 1. 读取 秘钥对, 创建 公钥/私钥 对象 """
# 从 PEM 格式的 公钥 文件中读取数据
with open("pub.pem", "rb") as f:
pub_bytes = f.read()
# 导入读取到的公钥数据, 生成 公钥对象, 返回类型为: <class 'Crypto.PublicKey.RSA.RsaKey'>
pub_key = RSA.import_key(pub_bytes)
# 从 PEM 格式的 私钥 文件中读取数据
with open("pri.pem", "rb") as f:
pri_bytes = f.read()
# 导入读取到的私钥数据, 生成 私钥对象, 返回类型为: <class 'Crypto.PublicKey.RSA.RsaKey'>
pri_key = RSA.import_key(pri_bytes)
# 私钥中包含了公钥, 公钥也可以从私钥中获取(PS: 公钥中不包含私钥)
# pub_key = pri_key.publickey()
""" 2. 创建密码器, 加密/解密 """
# 创建 公钥 密码器, 返回类型为: <class 'Crypto.Cipher.PKCS1_v1_5.PKCS115_Cipher'>
pub_cipher = PKCS1_v1_5.new(pub_key)
# 加密内容(bytes), 返回加密后的密文(bytes类型)
ciphertext = pub_cipher.encrypt("Hello World".encode())
# 创建 私钥 密码器, 返回类型为: <class 'Crypto.Cipher.PKCS1_v1_5.PKCS115_Cipher'>
pri_cipher = PKCS1_v1_5.new(pri_key)
# 解密密文(bytes), 返回解密后的明文(bytes类型)
plaintext = pri_cipher.decrypt(ciphertext, sentinel=None)
""" 3. 查看结果 """
# 输出解密后的明文, 结果为: "Hello World"
print(plaintext.decode())
1.4 RSA 秘钥对的签名/验签(私钥签名、公钥验签)
import Crypto.PublicKey.RSA
import Crypto.Signature.PKCS1_v1_5
import Crypto.Hash.SHA256
""" 1. 生成秘钥对, 创建 公钥/私钥 对象 """
# 生成一对长度为 2048 位的 RSA 秘钥对
rsa_key = Crypto.PublicKey.RSA.generate(2048)
# 从秘钥对中获取 公钥 对象, 返回类型为: <class 'Crypto.PublicKey.RSA.RsaKey'>
pub_key = rsa_key.publickey()
# 秘钥对本身就是 私钥 对象, 类型为: <class 'Crypto.PublicKey.RSA.RsaKey'>
pri_key = rsa_key
""" 2. 数据内容 """
# 要签名的数据内容(bytes类型)
data_content = "Hello World".encode()
""" 3. 创建 私钥 签名工具: 签名 """
# 创建 私钥 签名工具, 返回类型为: <class 'Crypto.Signature.pkcs1_15.PKCS115_SigScheme'>
pri_signer = Crypto.Signature.PKCS1_v1_5.new(pri_key)
# 创建 Hash 对象(使用 SHA256 算法), 返回类型为: <class 'Crypto.Hash.SHA256.SHA256Hash'>
msg_hash = Crypto.Hash.SHA256.new()
# 对 数据内容 进行 Hash
msg_hash.update(data_content)
# 使用 私钥 签名工具 对 数据 进行签名, 返回签名结果(bytes类型)
signature_result = pri_signer.sign(msg_hash)
""" 4. 创建 公钥 验签工具: 验签 """
# 创建 公钥 验签工具, 返回类型为: <class 'Crypto.Signature.pkcs1_15.PKCS115_SigScheme'>
pub_signer = Crypto.Signature.PKCS1_v1_5.new(pub_key)
# 创建 Hash 对象(使用 SHA256 算法), 返回类型为: <class 'Crypto.Hash.SHA256.SHA256Hash'>
msg_hash = Crypto.Hash.SHA256.new()
# 对 数据内容 进行 Hash
msg_hash.update(data_content)
# 使用公钥 验签工具 对 数据和签名 进行验签, 返回 True/False
verify = pub_signer.verify(msg_hash, signature_result)
# 校验结果为 True 表示通过验签
print(verify)
# 验签:
# 验证「数据」、「签名」、「公钥」 三个可公开的数据是否匹配。
# 如果匹配,说明该「签名」是该「公钥」对应的「私钥」对该「数据」进行的正确签名;
# 如果不匹配,说明可能该「数据」被篡改。
# 如此可以用来验证公开发布的「数据」是否是官方(即「私钥」)发布的。
2. rsa 模块
第三方模块rsa
以工具方法的形式实现 RSA 秘钥对生成、加密/解密、签名/验签。
安装rsa
模块:
pip3 install rsa
ras模块中的主要函数:
# 生成秘钥对, 返回元祖: (公钥, 私钥)
pub_key, pri_key = rsa.newkeys(2048, ...)
# 保存密钥
pub_key.save_pkcs1(...)
pri_key.save_pkcs1(...)
# 读取密钥
rsa.PublicKey.load_pkcs1(...)
rsa.PrivateKey.load_pkcs1(...)
# 加密/解密
rsa.encrypt(...)
rsa.decrypt(...)
# 签名/验签
rsa.sign(...)
rsa.verify(...)
2.1 生成 RSA 秘钥对
生成一对 RSA 密钥(公钥、私钥),并保持到文件:
import rsa
# 生成长度为 2048 位的 RSA 秘钥对, 返回一个元祖: (公钥, 私钥)
pub_key, pri_key = rsa.newkeys(2048)
# 公钥对象类型为: <class 'rsa.key.PublicKey'>
print(type(pub_key))
# 私钥对象类型为: <class 'rsa.key.PrivateKey'>
print(type(pri_key))
# 把公钥和私钥保存到文件
with open("pub.pem", "wb") as pub_fp:
# 保存为 PEM 格式, format = "PEM" 或 "DER"
key_content = pub_key.save_pkcs1(format="PEM")
pub_fp.write(key_content)
with open("pri.pem", "wb") as pri_fp:
key_content = pri_key.save_pkcs1(format="PEM")
pri_fp.write(key_content)
2.2 RSA 非对称加密/解密(公钥加密、私钥解密)
import rsa
# 生成长度为 2048 位的 RSA 秘钥对, 返回一个元祖: (公钥, 私钥)
pub_key, pri_key = rsa.newkeys(2048)
# 加密: 第一个参数为加密内容(bytes), 第二个参数为公钥, 返回加密后的密文(bytes)
ciphertext = rsa.encrypt(message="Hello World".encode(), pub_key=pub_key)
# 解密: 第一个参数是密文(bytes), 第二个参数为私钥, 返回解密后的明文(bytes)
plaintext = rsa.decrypt(crypto=ciphertext, priv_key=pri_key)
# 解密后的明文为原文: "Hello World"
print(plaintext.decode())
2.3 读取 RAS 秘钥对并进行非对称加密/解密
import rsa
# 从 PEM 格式公钥文件中读取公钥
with open("pub.pem", "rb") as f:
pub_key = rsa.PublicKey.load_pkcs1(f.read(), format="PEM")
# 从 PEM 格式私钥文件中读取私钥
with open("pri.pem", "rb") as f:
pri_key = rsa.PrivateKey.load_pkcs1(f.read(), format="PEM")
# 公钥对象类型为: <class 'rsa.key.PublicKey'>
print(type(pub_key))
# 私钥对象类型为: <class 'rsa.key.PrivateKey'>
print(type(pri_key))
# 加密: 第一个参数为加密内容(bytes), 第二个参数为公钥, 返回加密后的密文(bytes)
ciphertext = rsa.encrypt(message="Hello World".encode(), pub_key=pub_key)
# 解密: 第一个参数是密文(bytes), 第二个参数为私钥, 返回解密后的明文(bytes)
plaintext = rsa.decrypt(crypto=ciphertext, priv_key=pri_key)
# 解密后的明文为原文: "Hello World"
print(plaintext.decode())
2.4 RSA 秘钥对的签名/验签(私钥签名、公钥验签)
import rsa
# 生成长度为 2048 位的 RSA 秘钥对, 返回一个元祖: (公钥, 私钥)
pub_key, pri_key = rsa.newkeys(2048)
# 需要签名/验签的内容
content = "Hello World".encode()
# 签名:
# 第一个参数为签名的内容(bytes), 第二个参数为私钥, 第三个参数为使用的HASH算法。
# 返回签名结果(bytes)
sign = rsa.sign(message=content, priv_key=pri_key, hash_method="SHA-256")
# 验签:
# 第一个参数为验签的内容(bytes), 第二个参数为签名(bytes), 第三个参数为公钥。
# 验签通过, 返回签名算法名称(str); 验签失败, 抛出异常。
verify = rsa.verify(message=content, signature=sign, pub_key=pub_key)
# 结果为: "SHA-256"
print(verify)