-
2021-12-28 20:05:57
利用Python实现RSA数字签名的产生和验证过程。
任务1:准备一个私钥文件,一个公钥文件,一个数据文件;
任务2:定义一个函数,能够使用指定的私钥对数据文件进行签 名,并将签名结果输出到文件返回;
任务3:定义一个函数,能够使用指定的公钥对任务2中的签名 文件进行验证,返回验证结果;
任务4:利用任务1中的文件对任务2和3中的函数进行测试。标准库Hashlib
实现了SHA1,SHA224以及MD5等多个安全哈希算法,
pycryptodome的使用
- Python扩展库pycryptodome和cryptography,提供了SHA系列算法和其他哈希算法,以及DES,AES,RSA等多个加密算法和签名算法的实现
- pycryptodome是加密库
- pycryptodome模块不是Python的内置模块,pycryptodome模块实现了各种算法和协议的加密模块的结合,结合了各种加密方式对应的多种加密算法的实现,包括单向加密、对称加密以及公钥加密和随机数操作。
区别:
crypto是GPG加解密库,该库已于2016年停更,且pythongnupg库才是最主流的GPG加解密库。
PyCrypto是Python前主流加解密库,但已停更。
PyCryptodome是当前最主流的Python加解密库,如果遇到代码中import Crypto等字样,就需要安装这个库。
安装pycryptodome: pip install pycryptodome
1、公钥加密
Crypto.PubicKey.RSA生成私公密钥对
- 在该模块下的RSA.py源代码中提供了直接生成原始密钥的函数,所以要使用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)
输出:
Private RSA key at 0x1A81094DF70
用generate函数生成的密钥是一个私钥对象,通过export_key()函数返回这个密钥:
2、RSA.import_key获得公私密钥
- 上文已经可以输出一对公私密钥,还要用import_key函数
- 因为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)
输出
b'"9\x8fW+b\x83\xbf\xc7y\xfc3\xb5R@`\xf4\xad}\x9a\x11\x81\xf2\x0f\xf1\xc6_\xf0K\xb7\xf7t\xcb\xaevK\x08\x8cg\xa1\x8ai\x94\xdf8\xc6\\\xb5\xb8\x98\xfd}A\xb3\\\xf7\x91J\x88\x84/\xdc\xd8\xe7<\xe4\xfa[\n`X\xf5\xf6K\xd9`s\x17\x11F\x80~\xcdt$>$R\x86b\x11*m\xeb\xe0\x87,):&g\x98\'\x90\xbf\x8cK\xef\xbb-\xfc\xecF\x93G!\xf7\xff&\x91\xdc\xdcY\xff\xf76\x91\xcb\n\x1a\xb4\xf3\xcep6\xde5\xf0^\xe1\'\xf7\t\xc5\xdbU6\x83\xc7\xf5\xe2\xeb\xf7\xe3;J\xd1\x9b\xd0\x925!\x98s\x189\xdd\xa8=\xbfw^\xe8R\xdc\xce\xb8\xdb`\x96 f\x85\xd7\x10>\xea\x97\x05p\x8c\x00\xd5\xf0\xae\xea\x0c\xf9\x03\xd98N\xbc\xd8RD]\x97Y\x8a/\n\xec\xb5\xe5\xe9\x8ea\x87\xaeE\x9fM\xc7\\\x0c\xefE*}\xea\xcd*\x1f\xacR\xd7X\x85\xea\xbfl\xcc\xa5\xed\x91\x90\x07\x13\xdd\x97\x8c\xfcl\xf2y'
加密完成
4、RSA解密
# 解密 privateKey = RSA.import_key(private_key) cipher = PKCS1_OAEP.new(privateKey) data = cipher.decrypt(encrypted_data) print(data)
输出
b'123456'
三、数字签名与验签
- 数字签名与验签,简单来说步骤为:A使用自己的私钥对消息进行签名,将签名后的信息和公钥发送给B,B使用公钥验证签名是否属于A。
- 使用Crypto.Publickey,Crypto.Hash,Crypto.Signature三个库,即公钥加密、摘要算法、数字签名三个库
-
1、Crypto.Hash获取消息的HASH值
- 这里会用到摘要算法,常用的摘要算法有:MD2,MD4,MD5,SHA-1,SHA-256,RIPEMD128,RIPEMD160等等,用什么摘要算法不重要,只要在验证时有相同的摘要算法即可。这里选择MD5.
-
2、Crypho.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模式对消息进行签名
-
3、签名验证
- 签名验证部分需要传入三个信息:消息原文(data)、摘要算法(MD5)、HASH值签名结果(signature)
实验总代码
from Crypto.PublicKey import RSA key = RSA.generate(2048) # 任务1:准备一个私钥文件,一个公钥文件,一个数据文件 private_key = key.export_key() public_key = key.publickey().export_key() data = "I love you" with open("private_key.pem", "wb") as prifile,\ open("public_key.pem", "wb") as pubfile,\ open("data.txt","a") as datafile: prifile.write(private_key) pubfile.write(public_key) datafile.write(data) from Crypto.Signature import pkcs1_15 from Crypto.Hash import MD5 from Crypto.PublicKey import RSA # 签名 with open("data.txt", "r") as datafile: data = datafile.read() # print(data) # 任务2:定义签名函数,能够使用指定的私钥对数据文件进行签名,并将签名结果输出到文件返回 def signaturer(private_key, data): # 获取消息的HASH值,摘要算法MD5,验证时也必须用MD5 digest = MD5.new(data.encode('utf-8')) # 使用私钥对HASH值进行签名 signature = pkcs1_15.new(private_key).sign(digest) # 将签名结果写入文件 sig_results = open("sig_results.txt", "wb") sig_results.write(signature) sig_results.close() return sig_results # 任务3:定义签名验证函数,能够使用指定的公钥对任务2中的签名文件进行验证,返回验证结果 def verifier(public_key, data, signature): digest = MD5.new(data.encode('utf-8')) try: pkcs1_15.new(public_key).verify(digest, signature) print("验证成功!!!") except: print("签名无效!!!") # 任务4:利用任务1中的文件对任务2和3中的函数进行测试。 with open('private_key.pem') as prifile, \ open('data.txt') as datafile: private_key = RSA.import_key(prifile.read()) data = datafile.read() signaturer(private_key, data) with open('public_key.pem') as pubfile, \ open('data.txt') as datafile, \ open('sig_results.txt', 'rb') as sigfile: public_key = RSA.import_key(pubfile.read()) data = datafile.read() signature = sigfile.read() verifier(public_key, data, signature)
更多相关内容 -
RSA数字签名算法的具体实现.zip
2021-07-09 22:11:37RSA数字签名算法的具体实现 -
RSA数字签名算法的具体实现
2018-07-12 11:58:18本代码主要用于实现RSA数字签名算法,用java进行编程,能够完整的在eclipse上运行,具体可用于密码学的课程设计等。 -
C++编写的rsa数字签名程序源代码
2018-07-23 10:11:28C++编写的rsa数字签名程序源代码C++编写的rsa数字签名程序源代码C++编写的rsa数字签名程序源代码 -
rsa数字签名
2017-09-19 19:07:39RSA数字签名,对明文进行数字化,签名和验证,C语言,可直接运行。有界面,在文本框输入需签名的明文,再通过按钮进行操作。 -
RSA数字签名
2022-05-04 22:17:11利用RSA算法生成数字签名 2.自己选定一个可用的整数e。 3.点击Calc.D生成d。 4.至此创建了一对公钥和私钥。 5.将公钥(N,e)发送给小伙伴,小伙伴利用该公钥进行消息加密并发回密文。 6.利用私钥对小伙伴发来...利用RSA-Tool加密消息
1.运行RSA-Tool,点击Start按钮,滑动鼠标生成一个随机数。点击Generate生成一对大质数p、q及N=p×q。
2.自己选定一个可用的整数e。
3.点击Calc.D生成d。
4.至此创建了一对公钥和私钥。
5.将公钥(N,e)发送给小伙伴,小伙伴利用该公钥进行消息加密并发回密文。
6.利用私钥对小伙伴发来的密文进行解密。
注:加密时仅需要e和N,解密时仅需要d和N。
利用RSA算法实现对称密钥的安全分配
1.小A同学准备一些文字(信件),选择一个密钥利用DES-Tool对文字进行加密得到密文1。
密文1:AB99FE565BFB9BF2
2.小B同学运行RSA-Tool,生成公钥和私钥,将公钥(10001)发送给小A同学,私钥自己留存。
3.小A同学利用小B同学的公钥对加密信件时使用的对称密钥进行加密,得到密文2。将密文1和密文2一同发送给小B同学。
密文2:73E851322D601169A5B9A52B4D36DC9552EEA812121E372FA38B8981933C6312
4.小B同学首先用自己的私钥解密密文2,接着利用解密密文2得到的对称密钥(小白)在DES-Tool中解密密文1,得到原始文字内容。
利用RSA算法生成数字签名
1.小A同学运行Hash-Tool,生成某文件的MD5值。
MD5:1B55F4C13BF4736C0799ACD5AAAB3EF0
2.小A同学利用RSA Tool对生成的MD5值进行私钥加密(反向使用RSA算法,Generate生成密钥后将D和E交换位置,再用test进行加密)。
3.小A同学将公钥(10001)、文件和加密后的MD5(1B55F4C13BF4736C0799ACD5AAAB3EF0)一起发送给小B同学,由小B同学验证数字签名的正确性(软件中先激活test按钮,再填写公钥进行解密)。
-
Qt利用OpenSSl实现RSA数字签名
2017-07-05 16:07:41Qt利用OpenSSl实现RSA数字签名 http://blog.csdn.net/usister/article/details/74390949资源描述 欢迎评论 -
RSA数字签名java实现
2014-05-12 17:32:48根据上面的过程,我们可以得到RSA数字签名的框图如图2-1: 图 2-1 RSA数字签名框图 2、 假设Alice想和Bob通信,以本地两个文件夹Alice和Bob模拟两个用户,实现消息M和签名的模拟分发 (1)、Alice通过RSA算法生成... -
C++编写的 rsa数字签名 源代码
2018-08-31 22:44:09C++编写的CRC32校验程序源代码 ; C++编写的DES加密程序源代码 ; C++编写的MD5算法程序源代码 ;...C++编写的rsa数字签名程序源代码 ; C++编写的RSA演示程序源代码 ; C++编写的简单移位程序源代码 -
RSA数字签名Java实现
2014-11-05 14:05:48该源码分为两个包,一个rsa包,一个...SignatureData.java 实现数字签名 VerifySignature.java 实现数字签名验证,并含有主程序(main函数) cn.chd.david.utils BitByte.java 工具类,实现二进制流和十六进制流转换 -
python实现RSA数字签名(纯算法实现)
2022-01-14 19:22:56利用python实现RSA数字签名(纯算法实现),用到的hash256得到消息摘要,欧几里得,扩展欧几里得算法python实现RSA数字签名(纯算法实现)
一:什么是数字签名
数字签名是只有信息的发送者才能产生的别人无法伪造的一段数字串,这段数字串同时也是对信息的发送者发送信息真实性的一个有效证明。它是一种类似写在纸上的普通的物理签名,但是在使用了公钥加密领域的技术来实现的,用于鉴别数字信息的方法。一套数字签名通常定义两种互补的运算,一个用于签名,另一个用于验证。数字签名是非对称密钥加密技术与数字摘要技术的应用。
二:数字签名的原理
发送方将先生成一对公私钥,将公钥放到网络上,发送方利用私钥将文件或者消息进行签名。接收方得到发送方的文件或者消息、公钥以及生成的签名;首先利用公钥将得到签名生成消息摘要,在对比文件或者消息的消息摘要,如果匹配,则签名认证成功。
三:数字签名的作用
四:实现数字签名的算法
分为三种:RSA、DSA、ECDSA
五:具备前提知识RSA算法
RSA加密过程:
步骤 说明 描述 1 选择一对不相等且足够大的质数 p,q 2 计算p,q的乘积 n=p*q 3 计算n的欧拉函数 φ(n)=(p-1)*(q-1) 4 选一个与φ(n)互质的整数e 1<e<φ(n) 5 计算出e对于φ(n)的模反元素d de mod φ(n)=1 6 公钥 KU=(e,n) 7 私钥 KR=(d,n) 相关概念:
质数:质数又称素数。一个大于1的自然数,除了1和它自身外,不能被其他自然数整除的数叫做质数;否则称为合数(规定1既不是质数也不是合数)。
欧拉函数:在数论,对正整数n,欧拉函数是小于n的正整数中与n互质的数的数目
例如:
- 如果n可以分解成2个质数的整数之积,那么n的欧拉函数等于这两个因子的欧拉函数之积。
- φ(n)= φ(pxq)=(p-1)*(q-1)
互质:公约数只有1的两个整数,叫做互质整数
六:消息摘要的前提知识
消息摘要算法的特点:
消息摘要是把任意长度的输入揉和而产生长度固定的伪随机输出的算法。消息摘要的主要特点有:
①无论输入的消息有多长,计算出来的消息摘要的长度总是固定的。例如应用MD5算法摘要的消息有128个比特位,用SHA-1算法摘要的消息最终有160比特位的输出,SHA-1的变体可以产生192比特位和256比特位的消息摘要。一般认为,摘要的最终输出越长,该摘要算法就越安全。
②消息摘要看起来是“随机的”。这些比特看上去是胡乱的杂凑在一起的。可以用大量的输入来检验其输出是否相同,一般,不同的输入会有不同的输出,而且输出的摘要消息可以通过随机性检验。但是,一个摘要并不是真正随机的,因为用相同的算法对相同的消息求两次摘要,其结果必然相同;而若是真正随机的,则无论如何都是无法重现的。因此消息摘要是“伪随机的”。
③一般地,只要输入的消息不同,对其进行摘要以后产生的摘要消息也必不相同;但相同的输入必会产生相同的输出。这正是好的消息摘要算法所具有的性质:输入改变了,输出也就改变了;两条相似的消息的摘要确不相近,甚至会大相径庭。
④消息摘要函数是无陷门的单向函数,即只能进行正向的信息摘要,而无法从摘要中恢复出任何的消息,甚至根本就找不到任何与原信息相关的信息。当然,可以采用强力攻击的方法,即尝试每一个可能的信息,计算其摘要,看看是否与已有的摘要相同,如果这样做,最终肯定会恢复出摘要的消息。但实际上,要得到的信息可能是无穷个消息之一,所以这种强力攻击几乎是无效的。
⑤好的摘要算法,没有人能从中找到“碰撞”,虽然“碰撞”是肯定存在的。即对于给定的一个摘要,不可能找到一条信息使其摘要正好是给定的。或者说,无法找到两条消息,使它们的摘要相同。
七:python实现消息摘要
该处我采用的是hash256: SHA256算法使用的哈希值长度是256位
python代码:
def Sha256sum(message: bytes) -> bytes: # 定义常量 # 前8个素数2..19的平方根的小数部分的前32位 h0 = 0x6a09e667 h1 = 0xbb67ae85 h2 = 0x3c6ef372 h3 = 0xa54ff53a h4 = 0x510e527f h5 = 0x9b05688c h6 = 0x1f83d9ab h7 = 0x5be0cd19 # 定义常数K 64 # 前64个素数2..311的立方根的小数部分的前32位 K = (0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2) # R为循环右移, # 右移之后可能会超过32位,所以要和0xffffffff做与运算,确保结果为32位。 R = lambda x, n: ((x >> n) | (x << (32 - n))) & 0xffffffff # 大端 0x12,0x34,0x56,0x78 -> 0x12345678 W = lambda i1, i2, i3, i4: (i1 << 24) | (i2 << 16) | (i3 << 8) | i4 # 对每一个输入先添加一个'0x80',即'10000000', 即128 ascii_list = list(map(lambda x: x, message)) msg_length = len(ascii_list) * 8 ascii_list.append(128) # 补充0 while (len(ascii_list) * 8 + 64) % 512 != 0: ascii_list.append(0) # 最后64为存放消息长度,以大端数存放。 # 例如,消息为'a',则长度为'0x0000000000000008' for i in range(8): ascii_list.append(msg_length >> (8 * (7 - i)) & 0xff) # print(ascii_list) # print(len(ascii_list)//64) for i in range(len(ascii_list) // 64): # 64*8=512bits # print(ascii_list[i*64:(i+1)*64]) # 每个512bits的块进行循环 w = [] # 将512bits扩展到64*32bits=2048bits存入32位无符号数数组 for j in range(16): s = i * 64 + j * 4 w.append(W(ascii_list[s], ascii_list[s + 1], ascii_list[s + 2], ascii_list[s + 3])) for j in range(16, 64): s0 = (R(w[j - 15], 7)) ^ (R(w[j - 15], 18)) ^ (w[j - 15] >> 3) s1 = (R(w[j - 2], 17)) ^ (R(w[j - 2], 19)) ^ (w[j - 2] >> 10) w.append((w[j - 16] + s0 + w[j - 7] + s1) & 0xffffffff) # print(hex(s0)+':'+hex(s1)+':' + hex(R(w[j - 2], 17))) # 初始化 a, b, c, d, e, f, g, h = h0, h1, h2, h3, h4, h5, h6, h7 # for j in w: # print(hex(j)[2:]) for j in range(64): s0 = R(a, 2) ^ R(a, 13) ^ R(a, 22) maj = (a & b) ^ (a & c) ^ (b & c) t2 = s0 + maj s1 = R(e, 6) ^ R(e, 11) ^ R(e, 25) ch = (e & f) ^ ((~e) & g) t1 = h + s1 + ch + K[j] + w[j] h = g & 0xffffffff g = f & 0xffffffff f = e & 0xffffffff e = (d + t1) & 0xffffffff d = c & 0xffffffff c = b & 0xffffffff b = a & 0xffffffff a = (t1 + t2) & 0xffffffff h0 = (h0 + a) & 0xffffffff h1 = (h1 + b) & 0xffffffff h2 = (h2 + c) & 0xffffffff h3 = (h3 + d) & 0xffffffff h4 = (h4 + e) & 0xffffffff h5 = (h5 + f) & 0xffffffff h6 = (h6 + g) & 0xffffffff h7 = (h7 + h) & 0xffffffff digest = (h0 << 224) | (h1 << 192) | (h2 << 160) | (h3 << 128) digest |= (h4 << 96) | (h5 << 64) | (h6 << 32) | h7 # print(hex(digest)[2:]) # .rjust(32, '0')) return hex(digest)[2:] # .rjust(32, '0') if __name__=="__main__": aa='你好,中国'.encode('utf-8') print(Sha256sum(aa)) print(len(Sha256sum(aa)))
消息摘要运行效果:
八:RSA公私钥生成
生成公钥与私钥:此步骤按照第五步
明文 M 加密 Me mod n= C
密文 C 解密 Cd mod n=M#D、E和N的密钥生成 def generatePublicAndSecretKeys(size = 5): p, q = randPrime(size), randPrime(size) #生成一对不相等且足够大的质数 N = p * q #计算p、q的乘积 f = (p - 1) * (q - 1) #计算n的欧拉函数 e = randGcd1(f) #选出一个与f互质的整数e d = liyuan(e, f)#计算出e对于f的模反元素d de mod f =1 keys = {'d' : d, 'e' : e, 'n' : N} #得出公钥与私钥 return keys
1、选择一对不相等且足够大的质数 p,q
#确定素数 def isPrime(num): if (num < 2): return False else: i = 2 flag=True while i < num: # 如果num能被i整除,说明num不是质数 if num % i == 0: # 只要num不是质数,将flag的值修改为 False flag = False i += 1 return flag #大质数生成 def randPrime(n): rangeStart = 10 ** (n-1) #10**4 rangeEnd = (10 ** n) - 1 #10**5-1 while True: num = random.randint(rangeStart, rangeEnd) #返回rangestart到rangeend任意一个数 if isPrime(num): #判断是否是质数,如果是则生成 return num
2、寻找与f互质的整数e,利用欧几里算法,如果值等于1·,那么这两个数互质
#寻找与f互质整数e def randGcd1(b): rangeStart = 2 rangeEnd = b - 1 while True: num = random.randint(rangeStart, rangeEnd) if oujilide(num, b) == 1: #利用欧几里算法,如果值等于1,那么这个两个数互质 return num #欧几里得算法 def oujilide(a,b): if a > b: x = a y = b else: x = b y = a while True: if y == 0: return x else: r = x % y x = y y = r
3、使用扩展欧几里得算法,计算出e对于φ(n)的模反元素d。
#扩展欧几里得算法,求逆元 def liyuan(a, n): x1, x2, x3 = 1, 0, n y1, y2, y3 = 0, 1, a while y3 != 1 and y3 != 0 and y3 > 0: Q = math.floor(x3 / y3) t1, t2, t3 = x1 - Q * y1, x2 - Q * y2, x3 - Q * y3 x1, x2, x3 = y1, y2, y3 y1, y2, y3 = t1, t2, t3 if y3 == 0: return 0 if y3 == 1: if y2 >0: return y2 else: return n+y2
4、SHA256算法得到消息摘要,并哈希值转为整型
将消息摘要进行数字签名与验证#SHA256算法得到消息摘要 def hashing(M, size = 5): aa=zy.Sha256sum(M) #得到哈希值 cc=int(aa, 16) % 10 ** (size * 2 - 2)#将哈希值转化为整型 return cc #将消息摘要进行签名 def signMessage(M, d, N): s = power(M, d, N) #使用私钥签名 hashM**d mod N 得到签名内容 return s #将得到 def verifySign(s, e,n): w = power(s, e, n) return w
九:实现数字签名的整体实现代码
摘要:zaiyao.py
def Sha256sum(message: bytes) -> bytes: # 定义常量 # 前8个素数2..19的平方根的小数部分的前32位 h0 = 0x6a09e667 h1 = 0xbb67ae85 h2 = 0x3c6ef372 h3 = 0xa54ff53a h4 = 0x510e527f h5 = 0x9b05688c h6 = 0x1f83d9ab h7 = 0x5be0cd19 # 定义常数K 64 # 前64个素数2..311的立方根的小数部分的前32位 K = (0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2) # R为循环右移, # 右移之后可能会超过32位,所以要和0xffffffff做与运算,确保结果为32位。 R = lambda x, n: ((x >> n) | (x << (32 - n))) & 0xffffffff # 大端 0x12,0x34,0x56,0x78 -> 0x12345678 W = lambda i1, i2, i3, i4: (i1 << 24) | (i2 << 16) | (i3 << 8) | i4 # 对每一个输入先添加一个'0x80',即'10000000', 即128 ascii_list = list(map(lambda x: x, message)) msg_length = len(ascii_list) * 8 ascii_list.append(128) # 补充0 while (len(ascii_list) * 8 + 64) % 512 != 0: ascii_list.append(0) # 最后64为存放消息长度,以大端数存放。 # 例如,消息为'a',则长度为'0x0000000000000008' for i in range(8): ascii_list.append(msg_length >> (8 * (7 - i)) & 0xff) # print(ascii_list) # print(len(ascii_list)//64) for i in range(len(ascii_list) // 64): # 64*8=512bits # print(ascii_list[i*64:(i+1)*64]) # 每个512bits的块进行循环 w = [] # 将512bits扩展到64*32bits=2048bits存入32位无符号数数组 for j in range(16): s = i * 64 + j * 4 w.append(W(ascii_list[s], ascii_list[s + 1], ascii_list[s + 2], ascii_list[s + 3])) for j in range(16, 64): s0 = (R(w[j - 15], 7)) ^ (R(w[j - 15], 18)) ^ (w[j - 15] >> 3) s1 = (R(w[j - 2], 17)) ^ (R(w[j - 2], 19)) ^ (w[j - 2] >> 10) w.append((w[j - 16] + s0 + w[j - 7] + s1) & 0xffffffff) # print(hex(s0)+':'+hex(s1)+':' + hex(R(w[j - 2], 17))) # 初始化 a, b, c, d, e, f, g, h = h0, h1, h2, h3, h4, h5, h6, h7 # for j in w: # print(hex(j)[2:]) for j in range(64): s0 = R(a, 2) ^ R(a, 13) ^ R(a, 22) maj = (a & b) ^ (a & c) ^ (b & c) t2 = s0 + maj s1 = R(e, 6) ^ R(e, 11) ^ R(e, 25) ch = (e & f) ^ ((~e) & g) t1 = h + s1 + ch + K[j] + w[j] h = g & 0xffffffff g = f & 0xffffffff f = e & 0xffffffff e = (d + t1) & 0xffffffff d = c & 0xffffffff c = b & 0xffffffff b = a & 0xffffffff a = (t1 + t2) & 0xffffffff h0 = (h0 + a) & 0xffffffff h1 = (h1 + b) & 0xffffffff h2 = (h2 + c) & 0xffffffff h3 = (h3 + d) & 0xffffffff h4 = (h4 + e) & 0xffffffff h5 = (h5 + f) & 0xffffffff h6 = (h6 + g) & 0xffffffff h7 = (h7 + h) & 0xffffffff digest = (h0 << 224) | (h1 << 192) | (h2 << 160) | (h3 << 128) digest |= (h4 << 96) | (h5 << 64) | (h6 << 32) | h7 # print(hex(digest)[2:]) # .rjust(32, '0')) return hex(digest)[2:] # .rjust(32, '0') if __name__=="__main__": aa='你好,中国'.encode('utf-8') print(Sha256sum(aa)) print(len(Sha256sum(aa)))
RSA公私钥生成:shuziqianming.py
import random import math import zhaiyao as zy #确定素数 def isPrime(num): if (num < 2): return False else: i = 2 flag=True while i < num: # 如果num能被i整除,说明num不是质数 if num % i == 0: # 只要num不是质数,将flag的值修改为 False flag = False i += 1 return flag #大质数生成 def randPrime(n): rangeStart = 10 ** (n-1) #10**4 rangeEnd = (10 ** n) - 1 #10**5-1 while True: num = random.randint(rangeStart, rangeEnd) #返回rangestart到rangeend任意一个数 if isPrime(num): #判断是否是质数,如果是则生成 return num #扩展欧几里得算法,求逆元 def liyuan(a, n): x1, x2, x3 = 1, 0, n y1, y2, y3 = 0, 1, a while y3 != 1 and y3 != 0 and y3 > 0: Q = math.floor(x3 / y3) t1, t2, t3 = x1 - Q * y1, x2 - Q * y2, x3 - Q * y3 x1, x2, x3 = y1, y2, y3 y1, y2, y3 = t1, t2, t3 if y3 == 0: return 0 if y3 == 1: if y2 >0: return y2 else: return n+y2 #寻找与f互质整数e def randGcd1(b): rangeStart = 2 rangeEnd = b - 1 while True: num = random.randint(rangeStart, rangeEnd) if oujilide(num, b) == 1: #利用欧几里算法,如果值等于1,那么这个两个数互质 return num #欧几里得算法 def oujilide(a,b): if a > b: x = a y = b else: x = b y = a while True: if y == 0: return x else: r = x % y x = y y = r #从数字幂快速搜索模块 def power(x, n, mod): #x**n mod mod if n == 0: return 1 elif n % 2 == 0: p = power(x, n / 2, mod) return (p * p) % mod else: return (x * power(x, n - 1, mod)) % mod #D、E和N的密钥生成 def generatePublicAndSecretKeys(size = 5): p, q = randPrime(size), randPrime(size) #生成一对不相等且足够大的质数 N = p * q #计算p、q的乘积 f = (p - 1) * (q - 1) #计算n的欧拉函数 e = randGcd1(f) #选出一个与f互质的整数e d = liyuan(e, f)#计算出e对于f的模反元素d de mod f =1 keys = {'d' : d, 'e' : e, 'n' : N} #得出公钥与私钥 return keys #SHA256算法得到消息摘要 def hashing(M, size = 5): aa=zy.Sha256sum(M) #得到哈希值 cc=int(aa, 16) % 10 ** (size * 2 - 2)#将哈希值转化为整型 return cc #将消息摘要进行签名 def signMessage(M, d, N): s = power(M, d, N) #使用私钥签名 hashM**d mod N 得到签名内容 return s #将得到 def verifySign(s, e,n): w = power(s, e, n) return w
十:运行截图
1、对汉字的数字签名运行结果
2、对英文hello world 进行数字签名的运行结果
3、对后缀为.png图片生成数字签名的运行结果
4、对后缀为.doc的文档进行数字签名的运行结果
十一:整体代码
此处没有写出主函数,如要参考,请参考github
如要参加完整代码、ppt讲解、文档:请参考(纯算法,没有调用库)python实现RSA数字签名代码、ppt、文档.rar
最后:如有任何问题,可以私信博主
看到博主编写文章不容易,不点赞,关注,收藏在走吗???
-
Go语言实现RSA数字签名
2021-01-07 18:40:51package main import ( os encoding/pem crypto/x509 crypto/rsa crypto/sha256 crypto/rand crypto fmt ...//生成RSA私钥和公钥,保存到文件中 ... privateKey, err := rsa.GenerateKey(rand.Reader -
基于RSA的数字签名算法的实现
2021-10-25 23:58:38基于RSA的数字签名算法的实现,能够用在VC6.0 平台运行。RSA加密算法中,消息发送方是用公钥对数据进行加密,消息接收方用私钥对密文进行解密获得消息;在RSA签名算法中,消息发布者用私钥对消息进行签名,消息接收... -
基于rsa数字签名c++实现
2011-05-17 10:20:36rsa数字签名c++图形化界面的实现方式,帮助密码学方面的同学用 -
RSA 数字签名—— Java 实现
2019-05-10 18:28:25RSA 数字签名—— Java 实现依赖代码运行结果 依赖 <dependency> <groupId>commons-net</groupId> <artifactId>commons-net</artifactId> <version>3...依赖
<dependency> <groupId>commons-net</groupId> <artifactId>commons-net</artifactId> <version>3.6</version> </dependency> <dependency> <groupId>commons-codec</groupId> <artifactId>commons-codec</artifactId> <version>1.9</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.25</version> </dependency>
代码
package awesome.data.structure.algorithm.encrypt.rsa; import awesome.data.structure.algorithm.encrypt.md5.Md5Util; import org.apache.tomcat.util.codec.binary.Base64; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.security.*; import java.security.spec.InvalidKeySpecException; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import java.util.HashMap; import java.util.Map; import java.util.TreeMap; /** * RSA 工具类 * * @author: Andy * @time: 2019/5/10 16:50 * @since */ public class RSAUtil { private static final Logger LOGGER = LoggerFactory.getLogger(RSAUtil.class); private static final int RSA_SIZE_1024 = 1024; private static final String ALGORITHM = "SHA1WithRSA"; /** * 生成 RSA 密钥对 * * @param keySize * @return: {@link Map<String,Object> } * @author: Andy * @time: 2019/5/10 16:59 */ public static Map<String, Object> createKeyPair(int keySize) { KeyPairGenerator keyGen = null; try { keyGen = KeyPairGenerator.getInstance("RSA"); } catch (NoSuchAlgorithmException e) { LOGGER.error("初始化密钥工具异常", e); return null; } keyGen.initialize(keySize, new SecureRandom()); KeyPair key = keyGen.generateKeyPair(); PublicKey publicKey = key.getPublic(); PrivateKey privateKey = key.getPrivate(); Map map = new HashMap(); map.put("publicKey", publicKey); map.put("privateKey", privateKey); map.put("publicKeyBase64", Base64.encodeBase64String(publicKey.getEncoded())); map.put("privateKeyBase64", Base64.encodeBase64String(privateKey.getEncoded())); return map; } /** * 获得公钥的 Base64 字符串 * * @param publicKey 公钥 * @return: {@link String } * @author: Andy * @time: 2019/5/10 17:11 */ public static String getBase64PublicKeyString(PublicKey publicKey) { return Base64.encodeBase64URLSafeString(publicKey.getEncoded()).trim(); } /** * 获得私钥的 Base64 字符串 * * @param privateKey 公钥 * @return: {@link String } * @author: Andy * @time: 2019/5/10 17:11 */ public static String getBase64PrivateKeyString(PrivateKey privateKey) { return Base64.encodeBase64URLSafeString(privateKey.getEncoded()).trim(); } /** * 获取公钥 * * * @param publicKeyBase64 公钥的 Base64 字符串 * @return: {@link PublicKey } * @author: Andy * @time: 2019/5/10 18:05 */ public static PublicKey getPublicKey(String publicKeyBase64) throws NoSuchAlgorithmException, InvalidKeySpecException { X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(org.apache.commons.net.util.Base64.decodeBase64(publicKeyBase64)); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); PublicKey publicKey = keyFactory.generatePublic(pubKeySpec); return publicKey; } /** * 获取私钥 * * * @param privateKeyBase64 私钥的 Base64 字符串 * @return: {@link PrivateKey } * @author: Andy * @time: 2019/5/10 18:05 */ public static PrivateKey getPrivateKey(String privateKeyBase64) throws NoSuchAlgorithmException, InvalidKeySpecException { PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec(org.apache.commons.net.util.Base64.decodeBase64(privateKeyBase64)); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); PrivateKey priKey = keyFactory.generatePrivate(priKeySpec); return priKey; } /** * 使用私钥对数据进行数字签名 * * @param data 需要签名的数据 * @param privateKey 私钥 * @return: {@link byte[] } * @author: Andy * @time: 2019/5/10 17:15 */ public static byte[] sign(byte[] data, PrivateKey privateKey) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException { Signature signature = Signature.getInstance(ALGORITHM); signature.initSign(privateKey); signature.update(data); return signature.sign(); } /** * 使用私钥对数据进行数字签名 * * @param data 需要签名的字符串 * @param privateKey 私钥 * @return: {@link String } * @author: Andy * @time: 2019/5/10 17:15 */ public static String sign(String data, PrivateKey privateKey) throws InvalidKeyException, NoSuchAlgorithmException, SignatureException { return Base64.encodeBase64URLSafeString(sign(data.getBytes(), privateKey)).trim(); } /** * 签名校验 * * @param data 参与签名的数据 * @param sign 数字签名 * @param publicKey 公钥 * @return: {@link boolean } * @author: Andy * @time: 2019/5/10 17:22 */ public static boolean verify(byte[] data, byte[] sign, PublicKey publicKey) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException { Signature signature = Signature.getInstance(ALGORITHM); signature.initVerify(publicKey); signature.update(data); return signature.verify(sign); } /** * 签名校验 * * @param data 参与签名的数据 * @param sign 数字签名 * @param publicKey 公钥 * @return: {@link boolean } * @author: Andy * @time: 2019/5/10 17:22 */ public static boolean verify(String data, String sign, PublicKey publicKey) throws InvalidKeyException, NoSuchAlgorithmException, SignatureException { return verify(data.getBytes(), Base64.decodeBase64(sign), publicKey); } /** * 获取参与签名的参数的字符串。参数拼接的顺序由 TreeMap 决定。 * * @param paramsMap 参与签名的参数名和参数值的映射 * @return: {@link String } * @author: Andy * @time: 2019/5/10 17:43 */ public static String getSourceSignData(TreeMap<String, String> paramsMap) { StringBuilder paramsBuilder = new StringBuilder(); boolean first = true; for (Map.Entry<String, String> paramEntry : paramsMap.entrySet()) { if(!first){ paramsBuilder.append("&"); }else { first = false; } paramsBuilder.append(paramEntry.getKey()).append("=").append(paramEntry.getValue()); } return paramsBuilder.toString(); } /** * 设计流程: * <p> * 1、创建密钥对 * 2、获取参与签名的数据 * 3、获取参与签名的数据的摘要(MD5值) * 4、使用私钥对摘要进行数字签名 * 5、使用公钥验证签名 * * @author: Andy * @time: 2019/5/10 17:32 */ public static void main(String[] args) throws InvalidKeySpecException, NoSuchAlgorithmException, SignatureException, InvalidKeyException { //1、创建密钥对 Map<String, Object> keyPairMap = createKeyPair(RSA_SIZE_1024); String publicKeyBase64 = keyPairMap.get("publicKeyBase64").toString(); String privateKeyBase64 = keyPairMap.get("privateKeyBase64").toString(); System.out.println(String.format("publicKeyBase64: %s", publicKeyBase64)); System.out.println(String.format("privateKeyBase64: %s", privateKeyBase64)); //2、获取参与签名的数据 //创建 TreeMap, 排序方式为字符串的自然顺序 TreeMap<String, String> paramsMap = new TreeMap<>(); paramsMap.put("token", "token"); paramsMap.put("batchNo", "批次号"); paramsMap.put("totalBillCount", "1"); paramsMap.put("sumMoney", "1"); paramsMap.put("idCard", "452626199212070014"); paramsMap.put("name", "张三"); paramsMap.put("afterTaxMoney", "1"); paramsMap.put("remark", "备注"); String sourceSignData = getSourceSignData(paramsMap); System.out.println(String.format("参与签名的数据: %s", sourceSignData)); //3、获取参与签名的数据的摘要(MD5值) String md5Str = Md5Util.encrypt(sourceSignData); System.out.println(String.format("参与签名的数据的摘要(MD5值): %s", md5Str)); //4、使用私钥对摘要进行数字签名 String signature = sign(md5Str, getPrivateKey(privateKeyBase64)); System.out.println(String.format("数字签名: %s", signature)); //5、使用公钥验证签名 boolean success = verify(md5Str, signature, getPublicKey(publicKeyBase64)); System.out.println(String.format("签名验证结果:%s", success)); } } package awesome.data.structure.algorithm.encrypt.md5; import org.apache.commons.codec.digest.DigestUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Md5 工具类 * * @author: Andy * @time: 2019/5/10 17:27 * @since */ public class Md5Util { private static final Logger LOGGER = LoggerFactory.getLogger(Md5Util.class); /** * 简单 MD5 加密 * * @param str * @return: {@link String } * @author: Andy * @time: 2019/4/29 15:28 * @since */ public static String encrypt(String str) { try { return DigestUtils.md5Hex(str).toUpperCase(); } catch (Exception e) { LOGGER.error("MD5加密失败!", e); } return null; } }
运行结果
publicKeyBase64: MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCMcizy+1sAprsTLKyk8DLU8yR29ZMuol7T50LeyG4JMQxewXm05g56UlVg1cx8FAJCrMUg6ZU8KyjJycP+au9mkGsRUZv2k5Pwahhmt9Y2yviuIDUuGJ3/4ojgvaqsxSE+yQi+rLconS5DxwOOTJ0Dp5nG7eo5auVCkk8+uy7JlwIDAQAB privateKeyBase64: MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAIxyLPL7WwCmuxMsrKTwMtTzJHb1ky6iXtPnQt7IbgkxDF7BebTmDnpSVWDVzHwUAkKsxSDplTwrKMnJw/5q72aQaxFRm/aTk/BqGGa31jbK+K4gNS4Ynf/iiOC9qqzFIT7JCL6styidLkPHA45MnQOnmcbt6jlq5UKSTz67LsmXAgMBAAECgYB+KbKnM5S0KRK0TtVn9T40fZasJj5pDgMRaBVx+6qdJyptlG+4SVGIIJ4Btw1SCMdfDcSnpC0jN8IUQuOFkJosu7N6iB4IxEIe7cDOWppO5fOAR51c9tU+Z6544RdEcL9+X4S2GfdT9IObriMrcg0q0PSnj73MpkKJ7jV0ybWNQQJBAL3AnHjgxFMYFInoagQ0yX1KMSQlv+OrbQbQoZYGsvaacRcVKa0wngeeF3lzFN2XxoMqUR1e5gbMiHJMTdjPKw0CQQC9erxjde5NYJtGtPYTx6bXL3zDKI/T82uqlCt3lMjTe+s73q9oUPFvBU0Zj/IWlqD0kgB1NETMJid1WPT+KI4zAkAdmKNPP0+f3kulzvhqO4mJ3z6W8sRhUGWrAHOToOvdBu3IueZMOx8K9R+YM9j3TysJXlpUiG68dL57hWdG/9kpAkBVXLcEg/uw5mXt69a0wIx8g0tMzLhHP3Hw7kHK5L+47ynh1gfmEhlC7/t1GbFx1bh7lk8YfkzEQCgkqMfuvKybAkAnkLilyXl60wLfeinuynte1IQGk5kNuH0/DaP89UkWnXIEfH4FBIXETIhSRXHYnDMEGfojuE3J25QZw2eKY8rq 参与签名的数据: afterTaxMoney=1&batchNo=批次号&idCard=452626199212070014&name=张三&remark=备注&sumMoney=1&token=token&totalBillCount=1 参与签名的数据的摘要(MD5值): 553218F911324C5F45282142C036778F 数字签名: inrW4yFyEZrq1RNMVVaca5ImPiudcRsoCtlJCu8YADZ6mBLI5pHd9MkCElxNJCxFMbraEbXA8blhMbvdt3fqcgnJADIcy0xPVLLNXubCDes-brgmMBcmRLoEAFR_KZrDxj_5QzGZUekkiQxNh8_2emBxqvXjhUCJr-uwAzuwP9A 签名验证结果:true
-
Python RSA数字签名实践
2021-01-17 13:45:01之前讲到RSA可以用来加密和数字签名,这里是RSA用作数字签名。Python的pycrypto库实现的数字签名有一个限制,必须对哈希(hash)值进行签名,而不能直接对原文进行数字签名。好像大部分实现都有此限制。from Crypto.... -
RSA算法和RSA数字签名算法的实现
2011-05-29 14:01:52RSA算法和RSA数字签名算法的实现,RSA算法和RSA数字签名算法的实现,RSA算法和RSA数字签名算法的实现 -
RSA数字签名?原来这么好理解!!!
2020-11-23 11:48:26前言 数字签名就是附加在数据单元上的一些数据。而这些数据可以用来确认数据单元的来源(即确认是谁发给你的数据),并且可保护数据单元的... 本文将通过讲解RSA数字签名的实现方式,向各位读者说明数字签名在现 -
RSA 数字签名 c
2010-05-25 22:44:15RSA 数字签名 c语言实现~可运行成功 -
【密码学】Python实现RSA数字签名算法
2021-11-21 20:00:48程序要求清单: 基本流程: 运行结果: INPUT: ... -
(纯算法,没有调用库)python实现RSA数字签名代码、ppt、文档.rar
2022-01-14 19:14:15(纯算法,没有调用库)python实现RSA数字签名代码、ppt、文档 -
RSA-Digital-Signature-master_加密_RSA数字签名_
2021-10-02 00:19:16RSA的,数字签名,网上下的,只是加密,试一试 -
Java实现的数字签名算法RSA完整示例
2020-08-25 16:08:49主要介绍了Java实现的数字签名算法RSA,结合完整实例形式详细分析了RSA算法的相关概念、原理、实现方法及操作技巧,需要的朋友可以参考下