目录
学习资料
https://www.cnblogs.com/skprimin/p/16172231.html#_label0
预备知识
RSA的基础知识
涉及到的参数有:模数n,公钥指数e,私钥指数d,我们将(e,n)称为公钥,(d,n) 称为私钥
参数计算:
- 选两个保密的大质数 p , q p,q p,q
- 计算 N = p q N = pq N=pq,求N的欧拉函数值 ϕ ( N ) = ( p − 1 ) ( q − 1 ) \phi(N)=(p-1)(q-1) ϕ(N)=(p−1)(q−1)
- 选择 e , 1 < e < ϕ ( n ) e, 1 < e < \phi(n) e,1<e<ϕ(n), e e e与 ϕ ( n ) \phi(n) ϕ(n)互为质数
- 求 d d d,要求 d d d满足 e ∗ d m o d ϕ ( n ) = 1 e*d \bmod \phi(n)=1 e∗dmodϕ(n)=1
根据参数加密:
将明文M视为数字,假设
M
<
n
M < n
M<n
则密文
c
=
M
e
m
o
d
n
c=M^e \bmod n
c=Memodn
根据参数解密:
则明文
M
=
c
d
m
o
d
n
M=c^d \bmod n
M=cdmodn
相关软件包
c语言中可以#include <openssl/bn.h>
python中可以直接import gmpy2
Task 1: 推导RSA私钥
已知相关参数求秘钥
p = F7E75FDC469067FFDC4E847C51F452DF
q = E85CED54AF57E53E092113E62F436F4F
e = 0D88C3
vim task1.py
python3 task1.py
# 导入python中的高精度数学库
import gmpy2
# 已知参数
p = 0xF7E75FDC469067FFDC4E847C51F452DF
q = 0xE85CED54AF57E53E092113E62F436F4F
e = 0x0D88C3
# 计算n和n的欧拉函数值,并求出d
n = q * p
phi = (p - 1) * (q - 1)
# 求e mod phi的逆元d
d = gmpy2.invert(e, phi)
# 输出秘钥的16进制表示
print("private key:" + hex(d))
Task 2: 用RSA加密一个消息
使用公钥(e,n)对明文M进行加密,并且使用私钥(d,n)验证加密的正确性
n = DCBFFE3E51F62E09CE7032E2677A78946A849DC4CDDE3A4D0CB81629242FB1A5
e = 010001 (this hex value equals to decimal 65537)
M = A top secret!
d = 74D806F9F3A62BAE331FFE3F0A68AFE35B3D2E4794148AACBC26AA381CD7D30D
vim task2.py
python3 task2.py
import gmpy2
# 公钥参数
n = 0xDCBFFE3E51F62E09CE7032E2677A78946A849DC4CDDE3A4D0CB81629242FB1A5
e = 0x010001
# 明文
# 将字符串转换成16进制字符串,然后转换成16进制的数字
m = "A top secret!".encode("utf-8").hex()
m = int(m, 16)
# 进行加密
c = gmpy2.powmod(m, e, n)
# 输出16进制的加密结果
print(hex(c))
Task 3: 解密这个消息
公钥秘钥与上一个任务相同,让我们解密以下密文C,并将其转换为纯ASCII字符串。
C = 8C0F971DF2F3672B28811407E2DABBE1DA0FEBBBDFC7DCB67396567EA1E2493F
vim task3.py
python3 task3.py
import gmpy2
# 公钥参数
n = 0xDCBFFE3E51F62E09CE7032E2677A78946A849DC4CDDE3A4D0CB81629242FB1A5
d = 0x74D806F9F3A62BAE331FFE3F0A68AFE35B3D2E4794148AACBC26AA381CD7D30D
# 密文
C = 0x8C0F971DF2F3672B28811407E2DABBE1DA0FEBBBDFC7DCB67396567EA1E2493F
# 进行解密
M = gmpy2.powmod(C, d, n)
# 得到16进制的解密结果字符串
m = str(hex(M))[2:]
# 得到ASCII字符串
print("M:" + bytes.fromhex(m).decode("utf-8"))
Task 4: 产生一个消息的数字签名
让我们产生一个消息的签名;接着对消息进行变化,再次产生签名并进行对比
两条消息分别是:
M = I owe you $2000.
M = I owe you $3000.
vim task4.py
python3 task4.py
import gmpy2
# 公钥参数
n = 0xDCBFFE3E51F62E09CE7032E2677A78946A849DC4CDDE3A4D0CB81629242FB1A5
e = 0x010001
d = 0x74D806F9F3A62BAE331FFE3F0A68AFE35B3D2E4794148AACBC26AA381CD7D30D
# 两个消息
msg = ["I owe you $2000", "I owe you $3000"]
for m in msg:
print(m)
# 将字符串转换成16进制字符串,然后转换成16进制的数字
m = int(m.encode("utf-8").hex(), 16)
# 进行加密
c = gmpy2.powmod(m, d, n)
# 输出16进制的加密结果
print(hex(c))
Task 5: 验证这个数字签名是否正确
Bob收到来自Alice的消息M = “Launch a missile.”,其签名为s。我们知道Alice的公钥是(e, n),请验证该签名是否确实是Alice的。公钥和签名(十六进制)如下所示:
M = Launch a missile.
S = 643D6F34902D9C7EC90CB0B2BCA36C47FA37165C0005CAB026C0542CBDB6802F
e = 010001 (this hex value equals to decimal 65537)
n = AE1CD4DC432798D933779FBD46C6E1247F0CF1233595113AA51B450F18116115
假设in的签名已损坏,签名的最后一个字节从2F更改为3F,即只有一个比特的更改。请重复这个任务,并描述验证过程会发生什么。
vim task5.py
python3 task5.py
import gmpy2
# 消息
M = "Launch a missile."
# 原始消息签名
S_o = 0x643D6F34902D9C7EC90CB0B2BCA36C47FA37165C0005CAB026C0542CBDB6802F
# 损坏的消息签名
S_e = 0x643D6F34902D9C7EC90CB0B2BCA36C47FA37165C0005CAB026C0542CBDB6802A
# 公钥参数
n = 0xAE1CD4DC432798D933779FBD46C6E1247F0CF1233595113AA51B450F18116115
e = 0x010001
sig = [S_o, S_e]
for S in sig:
# 对消息进行解密
m = gmpy2.powmod(S, e, n)
# 得到16进制的字符串
m = str(hex(m))[2:]
try:
# 转成ASCLL
msg = bytes.fromhex(m).decode('utf-8')
print(msg)
if msg == M:
print("验证成功")
else:
print("验证失败")
except:
print(bytes.fromhex(m))
print("验证失败")