原理
第一种参数模式
随机选择两个大质数p,q,满足gcd(pq,(p−1)(q−1))=1。
计算
n=p⋅q
λ=lcm(p−1,q−1)=gcd(p−1,q−1)(p−1)(q−1)
选择随机整数g, 满足0<g<n2。
定义函数
L(x)=nx−1
计算
μ=(L(gλmodn2))−1modn
则公钥为(n,g),私钥为(λ,μ)
第二种参数模式
其余参数不变,主要改变了g,λ,μ的定义:
g=n+1
λ=φ(n)=(p−1)(q−1)
μ=φ(n)−1modn
加密过程
设消息为m,需满足0≤m<n。选择随机数r,满足gcd(r,n)=1。
计算密文
c=gm⋅rnmodn2
解密过程(Decryption)
计算
m=(L(cλmodn2)⋅μ)modn
Proof
第一种参数模式
由解密公式
m=L(cλmodn2)⋅μmodn
又
c=gm⋅rnmodn2,μ=(L(gλmodn2))−1modn
代入得
L(gmλ⋅rnλmodn2)⋅L(gλmodn2)−1modn
因为
(p−1)∣λ,(q−1)∣λ
所以有
λ=k1(p−1)=k2(q−1)
则
gλ=gk1(p−1)≡1(modp),gλ=gk2(q−1)≡1(modq)
由中国剩余定理得
gλ≡1(modn)
所以
gλmodn2=kgn+1,kg<n
同理得到
rλmodn2=krn+1,kg<n
因此
L(gλmodn2)=kg
又因为
(1+kn)m≡1+kn⋅m(modn2)
所以有
gmλ=(kgn+1)nλ≡kgn⋅m+1(modn2)rnλ=(krn+1)nλ≡krn⋅n+1≡1(modn2)
所以
gmλ⋅rnλ≡1+kgn⋅m(modn2)
于是
L(gmλ⋅rnλmodn2)=kg⋅m
综上得到:
L(gmλ⋅rnλmodn2)⋅L(gλmodn2)−1modn=kg⋅m⋅kg−1≡m(modn)
即得到明文m。
第二种参数模式
由解密公式
m=L(cλmodn2)⋅μmodn
根据λ=(p−1)⋅(q−1)=φ(n),μ=φ(n)−1=λ−1modn可写为
L(cλmodn2)⋅μmodn=L(gmλ⋅rnλmodn2)⋅λ−1modn
其中
λ=(p−1)⋅(q−1),μ=φ(n)−1modn
又根据欧拉函数的性质得
rnλ=rn(p−1)(q−1)=rφ(n2)≡1(modn2)
由于g=n+1,代入得
gmλ=(1+n)mλ≡1+n⋅mλ(modn2)
根据 L(x)=nx−1,则
L(gmλ⋅rnλmodn2)=L(1+n⋅mλ)=mλ
所以原式等价于
L(cλmodn2)=mλ⋅λ−1≡m(modn)
即得到明文m。
例题
DASCTF四月月赛 not RSA
题目
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| from Crypto.Util.number import getPrime as bytes_to_long from secret import flag,p,q from sympy import isprime,nextprime import random m=bytes_to_long(flag) n=p*q g=n+1 r=random.randint(1,n) c=(pow(g,m,n*n)*pow(r,n,n*n))%(n*n) print "c=%d"%(c) print "n=%d"%(n) """ n=6401013954612445818165507289870580041358569258817613282142852881965884799988941535910939664068503367303343695466899335792545332690862283029809823423608093 c=29088911054711509252215615231015162998042579425917914434962376243477176757448053722602422672251758332052330100944900171067962180230120924963561223495629695702541446456981441239486190458125750543542379899722558637306740763104274377031599875275807723323394379557227060332005571272240560453811389162371812183549 """
|
分析
可以看到,这一题就是用的paillier cryptosystem,且参数用的是上文中的第二种参数模式。
这里我们用factordb尝试分解n发现可以成功分解,下面直接套公式写脚本即可。
脚本
1 2 3 4 5 6 7 8 9 10 11
| from Crypto.Util.number import * import gmpy2 p=80006336965345725157774618059504992841841040207998249416678435780577798937819 q=80006336965345725157774618059504992841841040207998249416678435780577798937447 n=6401013954612445818165507289870580041358569258817613282142852881965884799988941535910939664068503367303343695466899335792545332690862283029809823423608093 c=29088911054711509252215615231015162998042579425917914434962376243477176757448053722602422672251758332052330100944900171067962180230120924963561223495629695702541446456981441239486190458125750543542379899722558637306740763104274377031599875275807723323394379557227060332005571272240560453811389162371812183549 phin=(p-1)*(q-1) mu=gmpy2.invert(phin,n) m=((pow(c,phin,n**2)-1)//n)*mu%n print(long_to_bytes(m))
|