pycryptodome简介——python实现RSA数字签名的产生和验证(一)

依旧在做实验之前,对实验中会应用到的一些知识做一个总结~~~~

  关于pycryptodome的安装,直接pip install pycryptodome,不行的话请参考:pip install pycryptodome失败的解决办法

文章目录

  • pycryptodome的前身
  • pycryptodome的使用
    • 一、对称加密(以AES为例)
      • 1.Crypto.Random
      • 2.Crypto.Cipher
      • 3.Crypto.Util
    • 二、公钥加密(以RSA为例)
      • 1.Crypto.PublicKey.RSA生成私公密钥对
      • 2.RSA.import_key获得公私密钥
      • 3.RSA加密
      • 4.RSA解密
    • 三、数字签名与验签
      • 1.Crypto.Hash获取消息的HASH值
      • 2.Crypto.Signature对HASH值使用私钥进行签名
      • 3.签名验证

pycryptodome的前身

crypto、pycrypto和pycryptodome均是加密库,具体说明如下:

  Crypto为UNIX和Linux平台上的一个或多个文件提供了到对称GPG(GNU隐私保护Gnu Privacy Guard)加密和解密的简单接口。它运行在GPG之上,需要在系统上安装GPG。使用AES256密码算法进行加密。

  pycrypto(Python Cryptography Toolkit)是安全哈希函数(如sha256和ripemd160)和各种加密算法(aes、des、rsa、elgamal等)的集合。它是一个第三方库,但是已经停止更新三年了,所以不建议安装这个库。

  pycryptodome是一个独立的包含低级密码原语的python包。它是pycrypto的延伸版本,用法和pycrypto 是一模一样的;建议开发者使用 PyCryptodome 或者 cryptography。

pycryptodome的使用

pycrytodome模块不是Python的内置模块,pycryptodome模块是一个实现了各种算法和协议的加密模块的结合,提供了各种加密方式对应的多种加密算法的实现,包括 单向加密、对称加密以及公钥加密和随机数操作。hashlib和hmac虽然是Python的内置模块,但是它们只提供了单向加密相关算法的实现,如果要使用对称加密算法(如, DES,AES等)或者公钥加密算法我们通常都是使用pycrytodome这个第三方模块来实现。存在以下几个子包:

一、对称加密(以AES为例)

1.Crypto.Random

  一般用于产生随机密钥,当然也可以使用Python内置的random模块产生,random模块的介绍前面的文章已经提过:python暴力破解加密的压缩文件(一)
  这里测试一下Crypto.Random的用法:
pycryptodome简介——python实现RSA数字签名的产生和验证(一)_第1张图片
可以看到,输出了一串字节串,所以该模块即可用于初始密钥的生成

2.Crypto.Cipher

支持对称加密,如AES、DES等;

pycryptodome简介——python实现RSA数字签名的产生和验证(一)_第2张图片
关于这里的密钥为什么是16位,因为"AES key must be either 16, 24, or 32 bytes long",至于明文为什么是16的倍数,请自行学习对称加密的相关内容。

3.Crypto.Util

上面涉及到明文的长度问题,该模块即可对不符合规定长度的明文进行填充

测试用例:

from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
from Crypto.Random import get_random_bytes

data = b"123456"
key = get_random_bytes(16)
cipher = AES.new(key, AES.MODE_CBC)
encrypted_data = cipher.encrypt(pad(data, AES.block_size))
print(encrypted_data)

#输出:b'4\x98,\x12\x17\xc7Q\xdf\xe5\x0b\x8a\x1d\xc28 \xc0'

这里的block_size以及key_size我也找到了源代码
pycryptodome简介——python实现RSA数字签名的产生和验证(一)_第3张图片

二、公钥加密(以RSA为例)

1.Crypto.PublicKey.RSA生成私公密钥对

  在该模块下的RSA.py源代码中提供了直接生成原始密钥的函数,而AES并没有这样的函数,所以要使用Crypto.Random模块生成:
  为什么是私公不是公私呢?继续走:
在这里插入图片描述
测试样例:

from Crypto.PublicKey import RSA

key = RSA.generate(2048)
private_key = key.export_key()
public_key = key.publickey().export_key()

print(key)
# print(private_key)
# print(public_key)

输出:
在这里插入图片描述
显然,用generate函数生成的密钥是一个私钥对象,通过export_key()函数返回这个密钥:
在这里插入图片描述
那么公钥的生成就需要下面这个函数:
pycryptodome简介——python实现RSA数字签名的产生和验证(一)_第4张图片
这些函数除generate外,都是定义在Crypto.PublicKey.RSA下的主类在这里插入图片描述
里面的,大家可以参考源代码。

2.RSA.import_key获得公私密钥

上文已经可以输出一对公私密钥,为什么还要有一个import_key函数来获得呢?承接上文,如果接着这样写代码的话:

from Crypto.Cipher import PKCS1_OAEP

data = b"123456"

# publicKey = RSA.import_key(public_key)
# 加密
cipher = PKCS1_OAEP.new(public_key)
encrypted_data = cipher.encrypt(data)
print(encrypted_data)

会报出属性错误:
在这里插入图片描述
为什么呢,我们print(public_key):
在这里插入图片描述
接着print(publicKey):
在这里插入图片描述
这里我猜测是因为publicKey是一个公钥的实例化对象,即public_key的实例化对象,在使用PKCS1_OAEP实例化加密套件时传入的参数必须是这个对象,查阅PKCS1_OAEP.py的源代码也发现传入的参数key应该是一个对象:
在这里插入图片描述

3.RSA加密

好了,一个正确的完整的测试用例:

from Crypto.PublicKey import RSA

key = RSA.generate(2048)
private_key = key.export_key()
public_key = key.publickey().export_key()

# print(key)
# print(private_key)
# print(public_key)

from Crypto.Cipher import PKCS1_OAEP

data = b"123456"

publicKey = RSA.import_key(public_key)
# print(publicKey)
# 加密
cipher = PKCS1_OAEP.new(publicKey)
encrypted_data = cipher.encrypt(data)
print(encrypted_data)

输出:
在这里插入图片描述
RSA加密完成!!

4.RSA解密

加密完成,解密就很好说了:

# 解密
privateKey = RSA.import_key(private_key)
cipher = PKCS1_OAEP.new(privateKey)
data = cipher.decrypt(encrypted_data)
print(data)

输出:
在这里插入图片描述
RSA解密完成!!!

三、数字签名与验签

  数字签名与验签,简单来说步骤为:A使用自己的私钥对消息进行签名,将签名后的信息和公钥发送给B,B使用公钥验证签名是否属于A。
  这里我们需要使用到Crypto.PublicKey,Crypto.Hash,Crypto.Signature三个库,即公钥加密、摘要算法和数字签名三个库。

1.Crypto.Hash获取消息的HASH值

  这里会用到摘要算法,常用的摘要算法有:MD2、MD4、MD5、SHA-1、SHA-256、RIPEMD128、RIPEMD160等等,用什么摘要算法不重要,只要在验签时用相同的摘要算法即可。这里我选择MD5,示例:

data = b'123456'
digest = MD5.new(data)

2.Crypto.Signature对HASH值使用私钥进行签名

  本质上是使用私钥对HASH值进行加密,为了方便我把公钥私钥以及消息分别保存在public_key.pem、private_key.pem、data.txt三个文件中,这里有坑了哦!
坑一:别忘了获取公私钥要用import_key函数;
坑二:从data.txt中读取消息后要使用相应的编码格式,于是上步就变成了:digest = MD5.new(data.encode('utf-8'))
  好了,在Crypto.Signature中随便选择一个模式,这里我选择pkcs1_15模式对消息就行签名,示例:

signature = pkcs1_15.new(private_key).sign(digest)

3.签名验证

  签名验证部分需要传入三个信息:消息原文(data)、摘要算法(MD5)、HASH值签名结果(signature)
  像pkcs1_15这些模式源代码内部都包括sign以及verify两个函数,所以验签时就是:

pkcs1_15.new(public_key).verify(digest, signature)

好了,到这里本实验已经能独立完成了!格外提醒大家注意一下编码格式、字符串、字节串等常踩坑~~

你可能感兴趣的:(pycryptodome简介——python实现RSA数字签名的产生和验证(一))