密码协议学习笔记(1.5):几种常用的非对称密码体系
RSA密码体系:
RSA密码体系是一种依赖于依赖于大数质因数分解的难解性的密码体系.
RSA加密算法:
参与者:
- 私钥持有者Alice
- 公钥持有者Bob
运行步骤:
- Alice选取两个大质数
(需要使用Miller-Rabin算法判定其是否为质数),计算 ,其欧拉函数 - Alice选取大质数
,这保证了 - Alice(使用扩展欧几里得算法或欧拉定理)计算出
,使得 ,其中 是任意的整数,这意味着, - Alice将
作为公钥发送给Bob,将 作为私钥自己保留 - 若Bob要给Alice发送信息(明文)
,用以下加密(encryption)算法将其加密为密文 : - Alice收到密文
后,用以下解密(decryption)算法还原出明文 : .
正确性:
至于为什么
当
当
不妨记
重新观察解密过程
综上,
安全性:
Alice的私钥
代码:
def divi(a): #分解质因数
i=2
ans=[]
while(i*i<a):
while(a%i==0):
ans.append(i)
a=a//i
i=i+1
if(a>1):
ans.append(a)
return ans
def gcd(a,b): #辗转相除法
if(b == 0):
return a
else:
return gcd(b,a%b)
def exgcd(a,b): #扩展欧几里得算法
if(b == 0):
x = 1
y = 0
return a,x,y
ans,t,x = exgcd(b,a%b)
y = t-a//b*x
return ans,x,y
def qpow(base,exp,mod): #快速幂
ans = 1
while(exp>0):
if(exp%2 == 1):
ans = ans*base%mod
exp = exp//2
base = base*base%mod
return ans
def rev(a,mod,type ='not_prime'):
if(type =='prime'): #费马小定理求逆元
return qpow(a,mod-2,mod)
else: #辗转相除法求逆元
g,x,y = exgcd(a,mod)
if(g!= 1):
return -1 #逆元不存在
else:
return (x+mod)%mod
p = 97
q = 103 #实际上这两个大整数是随机生成并通过Miller-Rabin算法判定的
print("Gen()->pk,sk")
print('p =',p,end=' = ')
print(*divi(p),sep='*')
print('q =',q,end=' = ')
print(*divi(q),sep='*')
g,x,y = exgcd(p,q)
n = p*q
print('n = pq =',n)
φ = (p-1)*(q-1)
print('φ = (p-1)(q-1) =',φ)
e = 197
print('e =',e,'\ngcd(z,e) =',gcd(φ,e))
d = rev(e,φ,type ='not_prime')
print('''d = e^{-1}(mod φ) =''',d)
print('pk:(n =',n,',e =',e,')')
print('sk:(n =',n,',d =',d,')')
print('\n')
print("Enc(pk,m)->c")
m = 114
print('m =',m)
c = qpow(m,e,n)
print('''c = m^e mod n =''',c)
print('\n')
print('Dec(c,sk)->m')
m1 = qpow(c,d,n)
print('''m = c^d mod n =''',m1)
运行结果:
Gen()->pk,sk
p = 97 = 97
q = 103 = 103
e = 197
gcd(z,e) = 1
d = e^{-1}(mod φ) = 845
pk:(n = 9991 ,e = 197 )
sk:(n = 9991 ,d = 845 )
Enc(pk,m)->c
m = 114
c = m^e mod n = 7731
Dec(c,sk)->m
m = c^d mod n = 114
RSA数字签名算法:
RSA密码体系还可以用于数字签名.
参与者:
- 私钥持有者Alice
- 公钥持有者Bob
运行步骤:
- Alice选取两个大质数
(需要使用Miller-Rabin算法判定其是否为质数),计算 ,其欧拉函数 - Alice选取大质数
,这保证了 - Alice(使用扩展欧几里得算法或欧拉定理)计算出
,使得 ,其中 是任意的整数,这意味着, - Alice将
作为公钥发送给Bob,将 作为私钥自己保留 - 若Alice要对一段信息
进行签名,用以下签名(signature)算法为其签名 : - Bob收到
后,用以下验证(verify)算法验算签名是否有效 .
正确性:
同上,略.
安全性:
同上,攻击者要伪造签名,就需要在仅知道公钥
代码:
def divi(a): #分解质因数
i=2
ans=[]
while(i*i<a):
while(a%i==0):
ans.append(i)
a=a//i
i=i+1
if(a>1):
ans.append(a)
return ans
def gcd(a,b): #辗转相除法
if(b == 0):
return a
else:
return gcd(b,a%b)
def exgcd(a,b): #扩展欧几里得算法
if(b == 0):
x = 1
y = 0
return a,x,y
ans,t,x = exgcd(b,a%b)
y = t-a//b*x
return ans,x,y
def qpow(base,exp,mod): #快速幂
ans = 1
while(exp>0):
if(exp%2 == 1):
ans = ans*base%mod
exp = exp//2
base = base*base%mod
return ans
def rev(a,mod,type ='not_prime'):
if(type =='prime'): #费马小定理求逆元
return qpow(a,mod-2,mod)
else: #辗转相除法求逆元
g,x,y = exgcd(a,mod)
if(g!= 1):
return -1 #逆元不存在
else:
return (x+mod)%mod
p = 97
q = 103 #实际上这两个大整数是随机生成并通过Miller-Rabin算法判定的
print("Gen()->pk,sk")
print('p =',p,end=' = ')
print(*divi(p),sep='*')
print('q =',q,end=' = ')
print(*divi(q),sep='*')
g,x,y = exgcd(p,q)
n = p*q
print('n = pq =',n)
φ = (p-1)*(q-1)
print('φ = (p-1)(q-1) =',φ)
e = 197
print('e =',e,'\ngcd(z,e) =',gcd(φ,e))
d = rev(e,φ,type ='not_prime')
print('''d = e^{-1}(mod φ) =''',d)
print('pk:(n =',n,',e =',e,')')
print('sk:(n =',n,',d =',d,')')
print('\n')
print("Sign(sk,m)->s")
m = 114
print('m =',m)
s = qpow(m,e,n)
print('''s = m^e mod n =''',s)
print('\n')
print('''Ver(pk,s,m)->{Valid,Invalid}''')
m1 = qpow(s,d,n)
print('''s^d mod n =''',m1)
if (m1==m):
print("Valid")
else:
print("Invalid")
运行结果:
Gen()->pk,sk
p = 97 = 97
q = 103 = 103
n = pq = 9991
φ = (p-1)(q-1) = 9792
e = 197
gcd(z,e) = 1
d = e^{-1}(mod φ) = 845
pk:(n = 9991 ,e = 197 )
sk:(n = 9991 ,d = 845 )
Sign(sk,m)->s
m = 114
s = m^e mod n = 7731
Ver(pk,s,m)->{1,0}
s^d mod n = 114
Valid
离散对数密码体系(ElGamal):
ElGamal密码体系是一种利用离散对数难解性问题的密码体系
ElGamal加密算法:
参与者:
- 私钥持有者Alice
- 公钥持有者Bob
运行步骤:
- Alice选取大质数
,整数 ,整数 ,计算 - Alice将
作为公钥发送给Bob,将 作为私钥自己保留 - 若Bob要给Alice发送信息(明文)
,需要先随机生成一个 ,然后用以下加密(encryption)算法将其加密为密文 : 其中 , - Alice收到密文
后,用以下解密(decryption)算法还原出明文 : .
正确性:
安全性:
攻击者在截获密文
代码:
import time #用于生成随机数
def divi(a): #分解质因数
i=2
ans=[]
while(i*i<a):
while(a%i==0):
ans.append(i)
a=a//i
i=i+1
if(a>1):
ans.append(a)
return ans
def gcd(a,b): #辗转相除法
if(b == 0):
return a
else:
return gcd(b,a%b)
def exgcd(a,b): #扩展欧几里得算法
if(b == 0):
x = 1
y = 0
return a,x,y
ans,t,x = exgcd(b,a%b)
y = t-a//b*x
return ans,x,y
def qpow(base,exp,mod): #快速幂
ans = 1
while(exp>0):
if(exp%2 == 1):
ans = ans*base%mod
exp = exp//2
base = base*base%mod
return ans
def rev(a,mod,type ='not_prime'):
if(type =='prime'): #费马小定理求逆元
return qpow(a,mod-2,mod)
else: #辗转相除法求逆元
g,x,y = exgcd(a,mod)
if(g!= 1):
return -1 #逆元不存在
else:
return (x+mod)%mod
print("Gen()->pk,sk")
p=97
print('p =',p,end=' = ')
print(*divi(p),sep='*')
g=5
print('g =',g,', g in [0,p-1]')
α=8
print('α =',α,', α in [0,p-2]')
β=qpow(g,α,p)
print('''β = g^α mod p =''',β)
print('pk:(p =',p,',g =',g,',β =',β,')')
print('sk:(p =',p,',α =',α,')')
print('\n')
print("Enc(pk,m)->c")
m = 66
print('m =',m)
k=int(time.time())%(p-1)
print('随机生成 k in [0,p-2], k =',k)
r=qpow(g,k,p)
s=m*qpow(β,k,p) % p
print('r=g^k mod p =',r)
print('s= m*β^k mod p =',s)
print('c=(r,s)')
print('\n')
print("Dec(sk,c)->m")
m1=s*rev(qpow(r,α,p),p,type='prime')%p
print('''m=s*(r^α)^{-1} mod p =''',m1)
运行结果:
Gen()->pk,sk
p = 97 = 97
g = 5 , g in [0,p-1]
α = 8 , α in [0,p-2]
β = g^α mod p = 6
pk:(p = 97 ,g = 5 ,β = 6 )
sk:(p = 97 ,α = 8 )
Enc(pk,m)->c
m = 66
随机生成 k in [0,p-2], k = 3
r=g^k mod p = 28
s= m*β^k mod p = 94
c=(r,s)
Dec(sk,c)->m
m=s*(r^α)^{-1} mod p = 66
ElGamal数字签名算法:
参与者:
- 私钥持有者Alice
- 公钥持有者Bob
运行步骤:
- Alice选取大质数
,整数 ,整数 ,计算 - Alice将
作为公钥发送给Bob,将 作为私钥自己保留 - 若Alice要对一段信息
进行签名,首先在 中随机选取一个与 互质的数 ,然后用以下签名(signature)算法为其签名 : 其中 - Bob收到
后,用以下验证(verify)算法验算签名是否有效 .
特别注意,这里Alice在计算
然而当
正确性:
安全性:
同上,攻击者若要伪造签名,就需要就需要知道
代码:
import time #用于生成随机数
def divi(a): #分解质因数
i=2
ans=[]
while(i*i<a):
while(a%i==0):
ans.append(i)
a=a//i
i=i+1
if(a>1):
ans.append(a)
return ans
def gcd(a,b): #辗转相除法
if(b == 0):
return a
else:
return gcd(b,a%b)
def exgcd(a,b): #扩展欧几里得算法
if(b == 0):
x = 1
y = 0
return a,x,y
ans,t,x = exgcd(b,a%b)
y = t-a//b*x
return ans,x,y
def qpow(base,exp,mod): #快速幂
ans = 1
while(exp>0):
if(exp%2 == 1):
ans = ans*base%mod
exp = exp//2
base = base*base%mod
return ans
def rev(a,mod,type ='not_prime'):
if(type =='prime'): #费马小定理求逆元
return qpow(a,mod-2,mod)
else: #辗转相除法求逆元
g,x,y = exgcd(a,mod)
if(g!= 1):
return -1 #逆元不存在
else:
return (x+mod)%mod
print("Gen()->pk,sk")
p=97
print('p =',p,end=' = ')
print(*divi(p),sep='*')
g=5
print('g =',g,', g in [0,p-1]')
α=8
print('α =',α,', α in [0,p-2]')
β=qpow(g,α,p)
print('''β = g^α mod p =''',β)
print('pk:(p =',p,',g =',g,',β =',β,')')
print('sk:(p =',p,',α =',α,')')
print('\n')
print("Sign(pk,m)->c")
m = 66
print('m =',m)
k=0
while(gcd(k,p-1)!=1):
k=int(time.time()*1000)%(p-1)
print('随机生成与(p-1)互质的 k in [0,p-2], k =',k,'gcd(p-1,k) =',gcd(p-1,k))
r=qpow(g,k,p)
print('r=g^k mod p =',r)
s=(m-r*α)*rev(k,p-1,type='not_prime')%(p-1)
print('''s= (m-ra)k^{-1} mod (p-1) =''',s)
print('sig=(r,s)')
print('\n')
print('''Ver(pk,sig)->{0,1}''')
m1=qpow(β,r,p)*qpow(r,s,p)%p
m2=qpow(g,m,p)
print('''β^r·r^s mod p =''',m1)
print('''g^m mod p =''',m2)
if (m1==m2):
print("Valid")
else:
print("Invalid")
运行结果:
Gen()->pk,sk
p = 97 = 97
g = 5 , g in [0,p-1]
α = 8 , α in [0,p-2]
β = g^α mod p = 6
pk:(p = 97 ,g = 5 ,β = 6 )
sk:(p = 97 ,α = 8 )
Sign(pk,m)->c
m = 66
随机生成与(p-1)互质的 k in [0,p-2], k = 41 gcd(p-1,k) = 1
r=g^k mod p = 80
s= (m-ra)k^{-1} mod (p-1) = 82
sig=(r,s)
Ver(pk,sig)->{0,1}
β^r·r^s mod p = 70
g^m mod p = 70
Valid
椭圆曲线上定义的交换群:
尝试以最简洁最直接的方式说明椭圆曲线的定义
由一个质数
遍历
群上的运算
- 若
,则 - 否则,
, 由以下规则确定: 其中
类似地,群上的数乘运算
示例代码(
def divi(a): #分解质因数
i=2
ans=[]
while(i*i<a):
while(a%i==0):
ans.append(i)
a=a//i
i=i+1
if(a>1):
ans.append(a)
return ans
def gcd(a,b): #辗转相除法
if(b == 0):
return a
else:
return gcd(b,a%b)
def exgcd(a,b): #扩展欧几里得算法
if(b == 0):
x = 1
y = 0
return a,x,y
ans,t,x = exgcd(b,a%b)
y = t-a//b*x
return ans,x,y
def qpow(base,exp,mod): #快速幂
ans = 1
while(exp>0):
if(exp%2 == 1):
ans = ans*base%mod
exp = exp//2
base = base*base%mod
return ans
def rev(a,mod,type ='not_prime'):
if(type =='prime'): #费马小定理求逆元
return qpow(a,mod-2,mod)
else: #辗转相除法求逆元
g,x,y = exgcd(a,mod)
if(g!= 1):
return -1 #逆元不存在
else:
return (x+mod)%mod
def ECCAdd(p1,p2,p,a,b): #椭圆曲线上的加法
if(p1=='inf'):
return p2
elif(p2=='inf'):
return p1
# 无穷远点定义为零元
x1,y1=p1
x2,y2=p2
if(x1==x2 and y1+y2==p):
return 'inf'
# 定义关于y轴对称两点(在模意义下实际上是相加得p)互为加法逆元,相加得零元
if(x1==x2 and y1==y2):
λ=(3*x1*x1+a)*rev(2*y1,p,type='prime')%p # 两点不重合,过此两点做一条直线
else:
λ=(y2-y1)*rev((x2-x1+p)%p,p,type='prime')%p # 两点重合,则取其与曲线的切线
x3=(λ*λ-x1-x2+p)%p
y3=(λ*(x1-x3)-y1+p)%p
# 定义这条直线与曲线的另一个交点为群上加法的结果
return (x3,y3)
p=11 #定义模数
a=1
b=6 #当4a^3+27b^2 ≠0 mod p 时,可定义一个交换群
print('p =',p,'a =',a,'b =',b)
if(4*a*a*a+27*b*b%p==0):
print("无法构成交换群")
exit()
else:
print("可以构成交换群,群上的元素有:")
for x in range(p):
z=(x*x*x+a*x+b)%p
for y in range(p):
if(y*y%p==z):
print((x,y))
print('inf')
print('请输入第一个点:')
p1=input()
if(p1!='inf'):
p1=tuple(p1.split(','))
p1=(int(p1[0][1:]),int(p1[1][:-1]))
if((p1[0]*p1[0]*p1[0]+a*p1[0]+b)%p!=(p1[1]*p1[1])%p):
print('该点不在椭圆曲线上!')
exit()
print('请输入第二个点:')
p2=input()
if(p2!='inf'):
p2=tuple(p2.split(','))
p2=(int(p2[0][1:]),int(p2[1][:-1]))
if((p2[0]*p2[0]*p2[0]+a*p2[0]+b)%p!=(p2[1]*p2[1])%p):
print('该点不在椭圆曲线上!')
exit()
print(p1,'+',p2,'=',ECCAdd(p1,p2,p,a,b))
运行结果:
p = 11 a = 1 b = 6
可以构成交换群,群上的元素有:
(2, 4)
(2, 7)
(3, 5)
(3, 6)
(5, 9)
(7, 2)
(7, 9)
(8, 3)
(8, 8)
(10, 2)
(10, 9)
inf
输入:
inf
inf
输出:
inf
输入:
(7,2)
inf
输出:
(7,2)
输入:
(5,2)
(5,9)
输出:
inf
输入:
(8,3)
(8,3)
输出:
(7,9)
输入:
(8,3)
(7,2)
输出:
(8,8)
椭圆曲线上的ElGamal密码体系:
椭圆曲线上的离散对数问题也是难解的,由此可构造出此种密码体系并确保其安全.
椭圆曲线密码体系上的明文和密文都是椭圆曲线上的点,因此在使用该密码体系之前需要构造一个整数与点之间的双射.
参与者:
- 私钥持有者Alice
- 公钥持有者Bob
运行步骤:
- 定义椭圆曲线上点的个数
,Alice选取点 ,再选取 ,计算 ,将 作为公钥发送给Bob, 作为私钥保留 - 若Bob要给Alice发送信息
,需要先随机生成一个 ,然后用以下加密(encryption)算法将其加密为密文 : - Alice收到密文
后,用以下解密(decryption)算法还原出明文 : .
正确性:
安全性:
攻击者要想从
代码:
import time
def divi(a): #分解质因数
i=2
ans=[]
while(i*i<a):
while(a%i==0):
ans.append(i)
a=a//i
i=i+1
if(a>1):
ans.append(a)
return ans
def gcd(a,b): #辗转相除法
if(b == 0):
return a
else:
return gcd(b,a%b)
def exgcd(a,b): #扩展欧几里得算法
if(b == 0):
x = 1
y = 0
return a,x,y
ans,t,x = exgcd(b,a%b)
y = t-a//b*x
return ans,x,y
def qpow(base,exp,mod): #快速幂
ans = 1
while(exp>0):
if(exp%2 == 1):
ans = ans*base%mod
exp = exp//2
base = base*base%mod
return ans
def rev(a,mod,type ='not_prime'):
if(type =='prime'): #费马小定理求逆元
return qpow(a,mod-2,mod)
else: #辗转相除法求逆元
g,x,y = exgcd(a,mod)
if(g!= 1):
return -1 #逆元不存在
else:
return (x+mod)%mod
def ECCAdd(p1,p2,p,a,b): #椭圆曲线上的加法
if(p1=='inf'):
return p2
elif(p2=='inf'):
return p1
# 无穷远点定义为零元
x1,y1=p1
x2,y2=p2
if(x1==x2 and y1+y2==p):
return 'inf'
# 定义关于y轴对称两点(在模意义下实际上是相加得p)互为加法逆元,相加得零元
if(x1==x2 and y1==y2):
λ=(3*x1*x1+a)*rev(2*y1,p,type='prime')%p # 两点不重合,过此两点做一条直线
else:
λ=(y2-y1)*rev((x2-x1+p)%p,p,type='prime')%p # 两点重合,则取其与曲线的切线
x3=(λ*λ-x1-x2+p)%p
y3=(λ*(x1-x3)-y1+p)%p
# 定义这条直线与曲线的另一个交点为群上加法的结果
return (x3,y3)
def EccMinus(p1,p2,p,a,b): #做减法就是加上加法逆元
if(p2=='inf'):
return p1
else:
return ECCAdd(p1,(p2[0],p-p2[1]),p,a,b)
def ECCMult(k,base,p,a,b): #椭圆曲线上的数乘(龟速乘)
ans = 'inf'
while(k>0):
if(k%2 == 1):
ans = ECCAdd(ans,base,p,a,b)
k = k//2
base = ECCAdd(base,base,p,a,b)
return ans
p=11 #定义模数
a=1
b=6 #当4a^3+27b^2 ≠0 mod p 时,可定义一个交换群
print('p =',p,'a =',a,'b =',b)
if(4*a*a*a+27*b*b%p==0):
print("无法构成交换群")
exit()
else:
print("可以构成交换群,群上的元素有:")
n=0 #统计椭圆曲线上的元素个数
for x in range(p):
z=(x*x*x+a*x+b)%p
for y in range(p):
if(y*y%p==z):
print((x,y))
n=n+1
print('inf')
n=n+1 #这个值同时也是(除零元O以外的)所有的点的阶数
# 即,使得 nP=O 最小的正整数n
print("Gen()->pk,sk")
P=(5,2)
x=6
Q=ECCMult(x,P,p,a,b)
print('P =',P)
print('x =',x)
print('Q = x * P =',Q)
print('pk:(Q =',Q,')')
print('sk:(x =',x,')')
print('\n')
print("Enc(pk,m)->c")
m = (8,8)
print('m =',m)
k=int(time.time()*1000)%(n-1)+1
print('k =',k)
c1=ECCMult(k,P,p,a,b)
c2=ECCAdd(m,ECCMult(k,Q,p,a,b),p,a,b)
print('c1 = kP =',c1)
print('c1 = m + kQ =',c1)
print('c = ( c1 =',c1,'c2 =',c2,')')
print('\n')
print('Dec(c,sk)->m')
m1 = EccMinus(c2,ECCMult(x,c1,p,a,b),p,a,b)
print('''m = c2 - x * c1 =''',m1)
运行结果:
p = 11 a = 1 b = 6
可以构成交换群,群上的元素有:
(2, 4)
(2, 7)
(3, 5)
(3, 6)
(5, 2)
(5, 9)
(7, 2)
(7, 9)
(8, 3)
(8, 8)
(10, 2)
(10, 9)
inf
Gen()->pk,sk
P = (5, 2)
x = 6
Q = x * P = (2, 4)
pk:(Q = (2, 4) )
sk:(x = 6 )
Enc(pk,m)->c
m = (8, 8)
k = 10
c1 = kP = (7, 2)
c1 = m + kQ = (7, 2)
c = ( c1 = (7, 2) c2 = inf )
Dec(c,sk)->m
m = c2 - x * c1 = (8, 8)
(注:若待加密的消息过长(二进制值超过了模数),可将其二进制形式进行分块,然后参与加密运算)
(若待签名的消息过长,可直接对其哈希值进行签名)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构