RSA 非对称加密 – 秘钥对生成,加密/解密,签名/验签

本文链接: https://blog.csdn.net/xietansheng/article/details/115559295

加密是指利用某个值(密钥)对明文的数据通过一定的算法变换加密(密文)数据的过程,它的逆向过程叫解密。

业务场景:一般情况下,互联网上流动的数据不会被加密,无法避免这些数据泄露窃取,实际数据上传过程中,为了保证数据不被泄露、实现安全数据传输,出现了各种加密技术,本次主要分享如何通过python来实现非对称加密算法RSA加解密。

一、pycryptodome/Crypto 模块

pycryptodome模块文档: https://pycryptodome.readthedocs.io/en/latest/

使用第三方模块pycryptodome中的Crypto.PublicKey.RSA实现 RSA 秘钥对生成、加密/解密、签名/验签。

1.1 安装pycryptodome模块:

pip3 install pycryptodome

1.2 生成 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.3 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.4 读取 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.5 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)


# 验签: 
#    验证「数据」、「签名」、「公钥」 三个可公开的数据是否匹配。
#    如果匹配,说明该「签名」是该「公钥」对应的「私钥」对该「数据」进行的正确签名;
#    如果不匹配,说明可能该「数据」被篡改。
#    如此可以用来验证公开发布的「数据」是否是官方(即「私钥」)发布的。

二、rsa 模块

第三方模块rsa以工具方法的形式实现 RSA 秘钥对生成、加密/解密、签名/验签。

2.1 安装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.2 生成 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.3 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.4 读取 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.5 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)
展开阅读全文
存在即是合理,一切皆有可能。
下一篇

vue3 封装 axios [ 请求拦截、响应拦截 ]

你也可能喜欢

  • 暂无相关文章!

发表评论

您的电子邮件地址不会被公开。 必填项已用 * 标注

提示:点击验证后方可评论!

插入图片
返回顶部

微信扫一扫

微信扫一扫