在某次安全研究中。需要手工验证下某重要文件MD5withRSA的数字签名是否正确。于是写了个脚本。现记录下来,供大家学习讨论。

1. 数字签名基础知识

数字签名:

一旦选择足够安全的散列算法, 那么就能够使用其实现数字签名系统。数字签名基础结构具有两个明显的目标:

1.数字化的签名消息可以向接收方保证: 消息确实来自己声明的发送者, 并且实施了不可否认性(也就是说, 排除了发送者之后声称消息是伪造的情况)。

2.数字化的签名消息可以向接收方保证: 消息在发送方和接收方之间进行传输的过程中不会被改变。这种方法确保消息不会受到恶意的修改(第三方想要修改消息的含义)以及无意识的修改(由通信过程中的故障造成,如电磁干扰) 。

数字签名算法的基础是我的一篇博客中讲到的两个重要概念: 公钥密码学和散列函数。

CISSP考试要求里的“应用密码学”内容辅助记忆趣味串讲_晓翔仔的博客-CSDN博客_cissp密码学

(公钥密码学=非对称密码学)

如果Alice 想要数字化签名一条发送给Bob 的消息,那么她会执行下列动作:

(1) Alice 使用一种足够安全的散列算法(如SHA-512)生成原始明文消息的消息摘要。

(2) 然后, A1ice 使用她的私钥只对消息摘要进行加密。加密的消息摘要便是数字签名。

(3) Alice 将签名的消息摘要添加到明文消息中。

(4) Alice 将完成添加的消息传送给Bob。

当Bob 接收到数字化签名的消息时,他会逆向完成如下过程:(这就是签名验证需要做的!)

(1) Bob 使用Alice 的公钥解密数字签名。

(2) Bob 使用相同的散列函数, 生成从Alice 那里接收到的完整明文消息的消息摘要。

(3) 然后, Bob 将从Alice那里接收到的已解密的消息摘要与自己计算得到的消息摘要进行比较

如果两个消息摘要匹配, 那么Bob 就能够确认接收到的消息是由Alice 发送的。如果这两个消息摘要不匹配, 那么这条消息有可能不是Alice 发送的, 也有可能在传输过程中被修改了。

需要注意的是,数字签名过程本身并不提供任何隐私保护。数字签名只是确保满足加密目标中的完整性和不可否认性。然而,如果Alice 想保证发送给Bob 的消息的隐私性,那么她就要在消息生成的过程中增加额外的步骤。在将己签名的消息摘要添加到明文消息中以后,Alice可以用Bob的公钥加密整条消息。当Bob接收到消息时,他会用自己的私钥在上述所列的步骤之前对消息进行解密。

数字签名不仅仅用于消息,软件供应商经常使用数字签名技术对从互联网上下载的编码分发(例如,applet和软件补丁)进行身份认证。

2. 签名文件的产生

2.1 生成一对公私钥

RSA密钥对的生成方式很多,这里为了方便,利用在线工具生成了一对公私钥。

公钥:

-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCr0erlUoNR/7WNp3RxIBM3UQVE/e7kbS8rKeybytjxPyNKta9/nlMWm3Yt9t8DQ0Tc5D18Uj1pmBGpplYCVKSxHF5VEzCK7+gMCJnieeZ/WLjGHqZJjIOwg3y5H52012jvQ5EcE7JIXRTOzIj7+2+J50JmDBmSUB4Vq+vAtdeA+wIDAQAB
-----END PUBLIC KEY-----

私钥:

-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQCr0erlUoNR/7WNp3RxIBM3UQVE/e7kbS8rKeybytjxPyNKta9/
nlMWm3Yt9t8DQ0Tc5D18Uj1pmBGpplYCVKSxHF5VEzCK7+gMCJnieeZ/WLjGHqZJ
jIOwg3y5H52012jvQ5EcE7JIXRTOzIj7+2+J50JmDBmSUB4Vq+vAtdeA+wIDAQAB
AoGAAzjbi9NhTQ9biz2BrIFqetYVIDcW3MfDY67UlhNWwCdr9QG1OdJxQnJF5BTG
F9ySFQZetM8iAbHtWt4YrNCDihrNNN8jhAK3l/QmqUjDmJuf34KRMWm1v0v3LE6C
5NOTreq5RDw2xEvPu9SDprhues9fVz0FCNagasI4l3UMM3ECQQDuCSjJOsjg9d8V
YUwNKlB7renL4laeO+qCwgkmuApX5nw3cPZAr6XlJDuy6oV0x16gdZfISU0BghL4
IdmArf1ZAkEAuMl43wWOxKphfqdP7lJ/besrzU6uNlGP56KtHy61cJ1s7Dexs46B
b89SRG2sCq1TgledPUynsepAOdxM7tQCcwJBAKZivKG8d4HYG7GkKzbgpxVswYoE
kitVEl2IKEFqT8CVmapfSaJ5pOqA40Hy8IpqediLmickJbGyLHRJpPFvrTECQEMR
xVBVaRNSsB5TRfy/bscLo5NaKntGsU+myOVXg72DNiSqtlHwuGRHwJlboSUi8fuO
J2E3cGpwFq2pmzbYNqcCQQCp6HwOLqsZ3GKPgX45txlESpHqeb4bNKm4G7M/b3nw
C0wdkZ3UHtbnc04m++atZB7re3eiQ/sYdMcN0RXXDBqv
-----END RSA PRIVATE KEY-----

2.2 用私钥对重要文件的哈希做加密

新建文件,写了重要内容。计算文件的MD5是

2da853603413c8823df8454ed579cd64

用上一步生成的私钥对MD5信息进行加密,加密结果用BASE64编码显示,是:

PXhWLNkyGRwBiuONnaeDXFv4HD6kvCIFO61jpjC9gX61qGfplMPrbcBn+co2eImNO10gAaXMXB1rxWnkxTETU9otaUO0I/SorqWbqiE4eOu1vlmuUZ0rXlxHGkLzfzJov25iFc8Lgt/qGbwuDL2p+yvjPNljhK2K3idOzO2v4I8=

用一个单独文件存放密文。这个就是该重要文件的数字签名。

3. 签名验证

3.1 利用RSA公钥对signature做解密。

熟悉RSA算法的你一定知道:RSA解密计算的时候,需要密文,模和指数。这密文就是数字签名signature,模(m)和指数(e)都存在与RSA公钥文件里面。

RSA公钥文件的主体部分是:

MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCr0erlUoNR/7WNp3RxIBM3UQVE/e7kbS8rKeybytjxPyNKta9/nlMWm3Yt9t8DQ0Tc5D18Uj1pmBGpplYCVKSxHF5VEzCK7+gMCJnieeZ/WLjGHqZJjIOwg3y5H52012jvQ5EcE7JIXRTOzIj7+2+J50JmDBmSUB4Vq+vAtdeA+wIDAQAB

RSA公钥文件的主体部分做BASE64解码后是:

30819f300d06092a864886f70d010101050003818d0030818902818100abd1eae5528351ffb58da77471201337510544fdeee46d2f2b29ec9bcad8f13f234ab5af7f9e53169b762df6df034344dce43d7c523d699811a9a6560254a4b11c5e5513308aefe80c0899e279e67f58b8c61ea6498c83b0837cb91f9db4d768ef43911c13b2485d14cecc88fbfb6f89e742660c1992501e15abebc0b5d780fb0203010001

褐色部分是模(m),紫色部分是指数(e)。

这里需要注意的是RSA公钥文件是由不同格式的。一种是“BEGIN RSA PUBLIC KEY”,另一种是“BEGIN PUBLIC KEY”。两种格式下,模(m)在公钥文件中所处的位置不一样(注意看python代码“# 找到模数和指数的开头结束位置”),指数(e)则永远都在公钥文件的结尾。

如何在两种公钥格式之间进行转换,一种是“BEGIN RSA PUBLIC KEY”,另一种是“BEGIN PUBLIC KEY” - 码客

根据上述分析,编写python3代码,用RSA公钥对signature做解密

import rsa
import base64class DecryptByPublicKey:"""先产生模数因子然后生成rsa公钥再使用rsa公钥去解密传入的加密str"""def __init__(self, encrypt_text, pub_key):missing_padding = 4 - len(encrypt_text) % 4if missing_padding:encrypt_text += '=' * missing_paddingself._encrypt_text = encrypt_text.replace(" ", "+")self._pub_string_key = pub_key# 使用公钥字符串求出模数和因子self._modulus = None  # 模数self._exponent = None  # 因子# 使用PublicKey(模数,因子)算出公钥self._pub_rsa_key = Nonedef _gen_modulus_exponent(self, s):# 对字符串解码, 解码成功返回 模数和指数b_str = base64.b64decode(s)# print("len(b_str):", len(b_str))# if len(b_str) < 162:#     print("_gen_modulus_exponent return false")#     # return Falsehex_str = b_str.hex()# print("hex_str is: ", hex_str)# 找到模数和指数的开头结束位置 BEGIN PUBLIC KEY格式的开头位置if pub_key_type == 'BEGIN PUBLIC KEY':m_start = 29 * 2e_start = 159 * 2m_len = 128 * 2e_len = 3 * 2elif pub_key_type == 'BEGIN RSA PUBLIC KEY':m_start = 7 * 2e_start = 137 * 2m_len = 128 * 2e_len = 3 * 2else:print("pubkey type not recognized")self._modulus = int(hex_str[m_start:m_start + m_len], 16)self._exponent = int(hex_str[e_start:e_start + e_len], 16)# print("exponent is:", hex(self._exponent))# print("modulus is:", hex(self._modulus))def _gen_rsa_pubkey(self):# 将pub key string 转换为 pub rsa keytry:rsa_pubkey = rsa.PublicKey(self._modulus, self._exponent)# 赋值到_pub_rsa_keyself._pub_rsa_key = rsa_pubkey.save_pkcs1()except Exception as e:raise edef decode(self):"""decrypt msg by public key"""public_key = rsa.PublicKey.load_pkcs1(self._pub_rsa_key)b64decoded_encrypt_text = base64.b64decode(self._encrypt_text)length = len(b64decoded_encrypt_text)# print("b64decoded_encrypt_text is: ", b64decoded_encrypt_text)# print("length of b64decoded_encrypt_text is: ", length)length_max = 128decryptDataText = []data = b''if length >= 128:for i in range(0, length, length_max):encrypted = rsa.transform.bytes2int(b64decoded_encrypt_text[i:i + length_max])print("encrypted data(signature):", hex(encrypted))print("public_key.e:", public_key.e)print("public_key.n:", public_key.n)decrypted = rsa.core.decrypt_int(encrypted, public_key.e, public_key.n)decrypted_bytes = rsa.transform.int2bytes(decrypted)# print("decrypted_bytes: ",decrypted_bytes)print("decrypted data(hex):", hex(decrypted))else:encrypted = rsa.transform.bytes2int(b64decoded_encrypt_text)decrypted = rsa.core.decrypt_int(encrypted, public_key.e, public_key.n)decrypted_bytes = rsa.transform.int2bytes(decrypted)try:raw_info = decrypted_bytes[decrypted_bytes.find(b'\x00') + 1:]except Exception as e:p.error(e)raise eprint("decrypt sign by public key is: ", raw_info.decode("utf-8"))return 'TRUE'def decrypt(self):"""先产生模数因子然后生成rsa公钥再使用rsa公钥去解密"""self._gen_modulus_exponent(self._pub_string_key)self._gen_rsa_pubkey()ret = self.decode()print("ret is:", ret)return retif __name__ == "__main__":# 在线生成pub_key_type = 'BEGIN PUBLIC KEY'pub_key = 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCr0erlUoNR/7WNp3RxIBM3UQVE/e7kbS8rKeybytjxPyNKta9/nlMWm3Yt9t8DQ0Tc5D18Uj1pmBGpplYCVKSxHF5VEzCK7+gMCJnieeZ/WLjGHqZJjIOwg3y5H52012jvQ5EcE7JIXRTOzIj7+2+J50JmDBmSUB4Vq+vAtdeA+wIDAQAB'encrypt_text = 'PXhWLNkyGRwBiuONnaeDXFv4HD6kvCIFO61jpjC9gX61qGfplMPrbcBn+co2eImNO10gAaXMXB1rxWnkxTETU9otaUO0I/SorqWbqiE4eOu1vlmuUZ0rXlxHGkLzfzJov25iFc8Lgt/qGbwuDL2p+yvjPNljhK2K3idOzO2v4I8='  # encrypt_text 是被私钥加密后的密文result = DecryptByPublicKey(encrypt_text, pub_key).decrypt()print(result)

备注:借鉴了这篇博客,特感谢

【Python3】RSA公钥解密_Parkour1990的博客-CSDN博客_python rsa 公钥解密

计算输出是:

decrypt sign by public key is:  2da853603413c8823df8454ed579cd64

3.2 哈希对比

对重要文件计算MD5,并与上一步python3解密计算的输出对比,发现是一致的,因此我们可以说本次数字证书验证通过。

4.总结

使用python进行RSA公钥加密私钥解密,网上方法很多。但是当你需要验证某数字签名的时候,发现很多博客的代码都无法直接拿过来用,我的python3签名验证代码亲测通过,希望我的这篇博客能够帮助到你。

用python3实现MD5withRSA数字签名的验证相关推荐

  1. python基于rsa的数字签名实现_OpenSSL和Python实现RSA Key数字签名和验证

    OpenSSL和Python实现RSA Key数字签名和验证,基于非对称算法的RSA Key主要有两个用途,数字签名和验证(私钥签名,公钥验证),以及非对称加解密(公钥加密,私钥解密).本文提供一个基 ...

  2. 数字签名(代码签名)流程和数字签名的验证

    数字签名(代码签名)流程 数字签名(代码签名)流程 Authenticode : 这里翻译为数字认证代码.  code sign : 字面的翻译为代码签名,但是通常的我们称为数字签名,以下的文中均称为 ...

  3. python生成数字签名及验证签名

    公私钥生成方法,请见前文 实例:python生成数字签名及验证 import base64from Crypto.Hash import SHA256 from Crypto.PublicKey im ...

  4. java api接口签名验证失败_cryptapi结合java进行数字签名与验证签名的困惑

    最近的一个项目需要用到数字签名,参考以下网友文章后,http://hi.baidu.com/luckydogs888/blog/item/50103cf0b587a8aea40f52ee.html,客 ...

  5. CryptoAPI与openssl数字签名与验证交互

    http://blog.csdn.net/zhouyuqwert/article/details/7467296 昨天写过了RSA非对称加密解密的交互方式, 其实数字签名也是RSA非对称加密,只不过用 ...

  6. PDF数字签名与验证

    工具:Acrobat Reader DC 前提:数字证书(包含私钥) 一.签名 1.在"工具栏"中选择"证书",将会展示"数字签名"菜单: ...

  7. 【密码学五】数字签名、RSA实现数字签名和验证

    消息认证码&数字签名 消息认证码(message authentication code)是一种确认完整性并进行认证的技术,取三个单词的首字母,简称为MAC. 消息认证码的输入包括任意长度的消 ...

  8. java jar 签名_JAR包数字签名与验证

    经签名的Jar包内包含了以下内容: 原Jar包内的class文件和资源文件 签名文件 META-INF/*.SF:这是一个文本文件,包含原Jar包内的class文件和资源文件的Hash 签名block ...

  9. python3正则表达式判断ipv4_Python 正则表达式验证IPv4地址

    1. Simple regex to check for an IP address ^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$ 2. Accurate regex to chec ...

最新文章

  1. Java方法详细介绍
  2. [译] JWT 与 Spring Cloud 微服务
  3. 使用自动化插件release来管理maven项目的版本发布
  4. 三维渲染引擎设计与实践(四)
  5. linux密码修改实验
  6. make mrproper 删除编译产生的相关文件
  7. browse下载插件DownThemAll!
  8. 巧用Linux命令完成统计排序功能yes2
  9. html生成1-32位随机数,如何生成一个32位的随机数 | 求索阁
  10. java查询未提交事务的数据_Jfinal同一事务中已插入的数据记录在事务未提前前查询不到?...
  11. Android项目同步,如何通过gradle任务同步Android项目?
  12. UIImageView 与 UIImage 区别
  13. 10条买房错误思维,你中招了几条?
  14. CSDN《老友记》简记
  15. uva 10308 Roads in the North
  16. 怎么高速旋转_洗衣机怎么选比较好,滚筒洗衣机和波轮洗衣机哪种更好?
  17. Julia: Array元素过滤、元素替代、元素删除等酸爽操作
  18. python中的__file__、os.path.realpath(__file__)、os.path.dirname(os.path.realpath(__file__))
  19. plsql 备份还原 教程_PLSQL导出还原数据库
  20. Part2 Movielens介绍

热门文章

  1. 前端学习日记2-html表单元素
  2. 工业图像处理实战--九点标定法
  3. maven手工安装依赖包
  4. java实验5_java实验5
  5. “1024”讲话两个月后,深交所正式发布区块链50指数,板块再迎利好
  6. R语言笔记7:functions——编写函数所需的基础知识
  7. ecshop支持mysql_ecshop安装不支持MySQL
  8. VB控件实现IObjectSafety安全接口(zt)
  9. 本科科研经历(技术干货篇-论文发表流程)
  10. 【基础】(C语言)高精度算法