笔者在图书馆敲了一上午的内容,奖励一块榴莲披萨!
模运算法则 (a + b) % p = (a % p + b % p) % p (a - b) % p = (a % p - b % p) % p (a b) % p = (a % p b % p) % p a ∧ b % p = ((a % p) ∧ b) % p
结合律 ((a + b) % p + c) = (a + (b + c) % p) % p ((a b) % p c) = (a (b c) % p) % p
交换律 (a + b) % p = (b + a) % p (a b) % p = (b a) % p
分配律 (a + b) % p = (a % p + b % p) % p ((a + b) % p c) % p = ((a c) % p + (b * c) % p)
重要定理 若 a ≡ b (mod p),则对于任意的 c,都有 (a + c) ≡ (b + c) (mod p) 若 a ≡ b (mod p),则对于任意的 c,都有 (a c) ≡ (b c) (mod p) 若 a ≡ b (mod p),c ≡ d (mod p),则 (a + c) ≡ (b + d) (mod p) (a - c) ≡ (b - d) (mod p) (a c) ≡ (b d) (mod p) (a / c) ≡ (b / d) (mod p)
RSA基础 (以下等号都是同余的意思)
加密 c=m^e(mod n)
解密m=c^d (mod n)
n=p*q
phi_n=(p-1)(q-1)
ed=1(mod phi_n)
接下来来证明解密过程的正确性
c^d=m^(ed)(mod n) 1式
ed=1+k*phi_n 2式
c^d=m^(1+k*phi_n)(mod n) 2代1
=m m^(k phi_n) (mod n)
={ m(mod n)*(m^phi_n)^k(mod n) }(mod n)
根据模运算和欧拉定理
c^d=m(mod n)
1 2 3 4 5 6 7 for i in range (10 ): flag = "" for j in range (10 ): flag += a[random.randint(0 , 99 )] flag = hashlib.md5(flag.encode()).hexdigest() print (f"flag{" + flag + " } " )
题目一:已知n,e,d,c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import gmpy2import libnump=libnum.gernerate_prime(1024 ) q=libnum.gernerate_prime(1024 ) n=p*q e=65537 phi_n=(p-1 )(q-1 ) d=gmpy2.invert(e,phi_n) m=libnum.s2n(flag) c=pow (m,e,n) print ("n=" ,n)print ("e=" ,e)print ("d=" ,d)print ("c=" ,c)
1 2 3 4 5 6 7 import libnumn=... d=... c=... m=pow (c,d,n) print (libnum.n2s(m))
题目2:已知n,e,c(n能分解的情况下) 1 2 3 4 5 6 7 8 9 10 11 12 13 import gmpy2import libnump=libnum.gernerate_prime(1024 ) q=gmpy2.next_prime(1024 ) n=p*q e=65537 m=libnum.s2n(flag) c=pow (m,e,n) print ("n=" ,n)print ("e=" ,e)print ("c=" ,c)
要求d,需知phi_n;要知phi_n,需知p,q,
使用yafu分解得到p,q
1 2 3 4 5 6 7 8 9 10 11 12 13 14 import gmpy2import libnumn=... p=... q=... e=... c=... assert n=p*qphi_n=(p-1 )(q-1 ) d=gmpy2.invert(e,phi_n) m=pow (c,d,n) print (libnum.n2s(int (m))
题目3:给出不同的e,但n,c相同(共模攻击) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 import gmpy2import libnump=libnum.gernerate_prime(1024 ) q=libnum.gernerate_prime(1024 ) n=p*q e1=2333 e2=23333 m=libnum.s2n(flag) c1=pow (m,e1,n) c2=pow (m,e2,n) print ("n=" ,n)print ("e1=" ,e1)print ("e2=" ,e2)print ("c1=" ,c1)print ("c2=" ,c2)
c1=m^e1%n
c2=m^e2%n
想办法得到m
令
c1^s =m^(e1*s)%n
c2^t=m^(e2*t)%n
m^(e1s+e2t)=(c1^s*c2^t )%n
根据扩展欧几里德算法
对于不完全为 0 的整数 (a, b), gcd(a, b) 表示 (a, b) 的最大公约数。
那么一定存在整数 (x, y) 使得 gcd(a, b) = ax + by
得到s,t
1 2 3 4 5 6 7 8 9 10 11 12 import gmpy2import libnumn=... e1=... e2=... c1=... c2=... s,s1,s2=gmpy2.gcdexd(e1,e2) m=(pow (c1,s1,n)*pow (c2,s2,n)%n) print (libnum.n2s(int (m))
题目4:给出n,e,c,但e的值较小,可直接爆破(低加密指数攻击) 如果 ( e = 3 ),且 ( m^e < n ),( c ) 开 3 次根式,得到 ( m )。
如果 ( e = 3 ),且 ( m^e > n ),那么设 ( k ),有: [ c = m^e + kn ]
爆破 ( k ),如果 ( c - kn ) 能开三次根式,得到 ( m )。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 import gmpy2import libnumn=... e=... c=... def exp (n,e,c ): k=0 while 1 : m1=k*n+c m,t=gmpy2.iroot(m1,e) if t: print (m) print (libnum.n2s(int (m))) break k+=1
题目5:给出不同的n,c,但m,e相同且e较小(低加密指数广播攻击) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 import gmpy2import libnump=libnum.gernerate_prime(1024 ) q=libnum.gernerate_prime(1024 ) n1=p*q p=libnum.gernerate_prime(1024 ) q=libnum.gernerate_prime(1024 ) n2=p*q p=libnum.gernerate_prime(1024 ) q=libnum.gernerate_prime(1024 ) n3=p*q while 1 : e=random.randint(10 ,20 ) if gmpy2.is_prime(e): break m=libnum.s2n(flag) c1=pow (m,e,n1) c2=pow (m,e,n2) c3=pow (m,e,n3) print ("n1=" ,n1)print ("n2=" ,n2)print ("n3=" ,n3)print ("c1=" ,c1)print ("c2=" ,c2)print ("c3=" ,c3)
根据前面学习的数论知识,可以使用中国剩余定理 解出m^e,然后进行开方
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 import gmpy2import libnumn1=... n2=... n3=... c1=... c2=... c3=... def GCRT (m, a ): assert (len (m) == len (a)) curm, cura = m[0 ], a[0 ] for m, a in zip (m[1 :], a[1 :]): d = gmpy2.gcd(curm, m) c = a - cura assert (c % d == 0 ) K = c // d * gmpy2.invert(curm // d, m // d) cura += curm * K curm = curm * m // d return cura % curm n=[n1,n2,n3] c=[c1,c2,c3] mm= GCRT(n,c) for e in range (10 ,20 ): m,t=gmpy2.iroot(mm,e) if t: print (m) print (libnum.n2s(int (m)))
题目6:给出不同的n,c,但m,e相同且e较大(n不互素) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 import gmpy2import libnumflag="flag{" +str (uuid.uuid4())+"}" m=libnum.s2n(flag) p=libnum.gernerate_prime(1024 ) q1=libnum.gernerate_prime(1024 ) q2=libnum.gernerate_prime(1024 ) n1=p*q1 n2=p*q2 e=65537 c1=pow (m,e,n1) c2=pow (m,e,n2) print ("n1=" ,n1)print ("n2=" ,n2)print ("c1=" ,c1)print ("c2=" ,c2)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import gmpy2import libnumn1=... n2=... c1=... c2=... e=65537 p=gcd(n1,n2) q1=n1//p phi_n=(p-1 )*(q1-1 ) d=gmpy2.invert(e,phi_n) m=pow (c1,d,n1) print (libnum.n2s(int (m)))
变形(将flag分成前后两段分别算m) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 import gmpy2import libnumimport uuidflag="flag{" +str (uuid.uuid4())+"}" m1=libnum.s2n(flag[:21 ]) m2=libnum.s2n(flag[21 :]) p=libnum.gernerate_prime(1024 ) q1=libnum.gernerate_prime(1024 ) q2=libnum.gernerate_prime(1024 ) n1=p*q1 n2=p*q2 e=65537 c1=pow (m1,e,n1) c2=pow (m2,e,n2) print ("n1=" ,n1)print ("n2=" ,n2)print ("c1=" ,c1)print ("c2=" ,c2)
上一个脚本多走一步,得到m1,m2,拼起来
题目7:已知n,e,c,dp(dp泄露) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 import gmpy2import libnumimport uuidflag="flag{" +str (uuid.uuid4())+"}" m=libnum.s2n(flag) p=libnum.gernerate_prime(1024 ) q=libnum.gernerate_prime(1024 ) n=p*q e=65537 phi_n=(p-1 )(q-1 ) d=gmpy2.invert(e,phi_n) dp=d%(p-1 ) print ("n=" ,n)print ("e=" ,e)print ("c=" ,c)print ("dp=" ,dp)
dp=d+k*(p-1)
edp=e d+e k (p-1)
=1+e*k1(p-1) (mod phi_n)
e dp-1=e k1(p-1)+k *phi_n
phi_n=(p-1)(q-1)
e dp-1=e k1(p-1)+k (p-1)(q-1)=(ek1+k(q-1))(p-1)=k2 (p-1)
又因为dp<p-1(dp=d%(p-1)是其余数)
所以e>k2,即k2<65537
遍历e找到k2然后就能算出p
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 import gmpy2import libnumn=... e=... c=... dp=... for i in range (1 ,65535 ): p=(dp*e-1 )//i+1 if n%p==0 : q=n//p break print (p)print (q)phi_n=(p-1 )*(q-1 ) d=gmpy2.invert(e,phi_n) m=pow (c,d,n) print (libnum.n2s(int (m)))
题目8:给出p,q,c,dp,dq(dp,dq泄露) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 import gmpy2import libnumimport uuidflag="flag{" +str (uuid.uuid4())+"}" m=libnum.s2n(flag) p=libnum.generate_prime(1024 ) q=libnum.generate_prime(1024 ) e=65537 n=p*q phi=(p-1 )*(q-1 ) d=gmpy2.invert(e,phi) dp=d%(p-1 ) dq=d%(q-1 ) c=pow (m,e,n) print ("p=" ,p)print ("q=" ,q)print ("c=" ,c)print ("dp=" ,dp)print ("dq=" ,dq)
dp=d%(p-1)
dp=d-k(p-1) d=dp+k (p-1)
m=c^d%n
m=c^d+kpq
m%p=(c^d%p+kpq%p)%p
m=c^d%p(当m<p时)
m=c^d+kp=c^(dp+k *(p-1))+kp
m%p=(c^dp%pc^k (p-1)%p)%p
m=c^dp%p(m<p时)
1 2 3 4 5 6 7 8 9 10 11 12 import gmpy2import libnum p=... q=... c=... dp=... dq=... m=pow (c,dp,p) m=pow (c,dq,q) print (libnum.n2s(int (m)))
题目9:已知n,e,c,p,且n是p的r次方 根据欧拉函数
若n=p^r
phi_n=p^r-p^(r-1)
证明如下
phi_n代表从1到n中与n互质的素数的个数
在1到p^r中,1和p是其唯二素公因子
那么有1p,2p,3p,…..p^(r-1)p与其不互质
一共有p^r个数,减去着p^(r-1)个数就是最终phi_n的值
1 2 3 4 5 6 7 8 9 10 11 12 13 import gmpy2import libnumn=... e=... c=... p=... phi_n=(p-1 )*p**2 d=gmpy2.inverrt(t1,phi_n) m=pow (c,d,n) print (libnum,n2s(int (m)))
变形(n=p^r*q) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 import gmpy2import libnumn=... e=... c=... p=... q=n//p phi_n=(p-1 )*p**2 *(q-1 ) d=gmpy2.inverrt(t1,phi_n) m=pow (c,d,n) print (libnum,n2s(int (m)))
题目10:n分解3个素数(p和q能分解出来) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 import libnumimport uuidimport gmpy2flag="flag{" +str (uuid.uuid4())+"}" m=libnum.s2n(flag) p=libnum.generate_prime(512 ) q=gmpy2.next_prime(p) r=libnum.generate_prime(512 ) n=p*q*r e=65537 c=pow (m,e,n) print ("r=" ,r)print ("n=" ,n)print ("e=" ,e)print ("c=" ,c)
n=pq r
p*q=n//r
phi_n=(p-1)(q-1)(r-1)
由此可继续
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import gmpy2import libnumr=... n=... pq=n//r print ("pq=" ,pq)p=... q=... phi_n=(p-1 )(q-1 )(r-1 ) d=gmpy2.inverrt(t1,phi_n) m=pow (c,d,n) print (libnum,n2s(int (m)))
题目11:e和phi_n不互素(就求不出e在模n下的逆元d了) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 import gmpy2import libnumimport randomimport uuidflag="flag{" +str (uuid.uuid4())+"}" m=libnum.s2n(flag) while 1 : e = random.randint(100 ,1000 ) p=libnum.generate_prime(1024 ) q=libnum.generate_prime(1024 ) phi_n=(p-1 )*(q-1 ) t=gmpy2.gcd(e,phi_n) if gmpy2.invert(e // t, phi_n) and t != 1 : break n=p*q c=pow (m,e,n) print ("p=" ,p)print ("q=" ,q)print ("e=" ,e)print ("c=" ,c)
我们可以求出一个与phi_n互素的公钥t1,然后转换成原来的题目
令t=gcd(e,phi_n)
t1=e//t
c=m^e=m^(t*t1)=(m^t)^t1%n
此时m^t进行开方后就能得到m了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import gmpy2import libnump=... q=... e=... c=... phi_n=(p-1 )*(q-1 ) t=gcd(e,phi_n) t1=e//t d=gmpy2.inverrt(t1,phi_n) m1=pow (c,d,n) s,m=gmpy.iroot(m1,t) print (s,m)print (libnum.n2s(int (m)))
题目12:n,c不互素 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 import libnumimport gmpy2import uuidflag="flag{" +str (uuid.uuid4())+"}" m=libnum.s2n(flag) p=libnum.generate_prime(1024 ) q=libnum.generate_prime(1024 ) n=p*q e=65537 c=pow (m*p,e,n) print ("n=" , n) print ("c=" , c) print ("e=" , e)
c=pow(m*p,e,n)
c=(m*p)^e-kpq
c%p=0
p=gcd(c,n)
q=n//p
然后解密即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 import libnumimport gmpy2n=... c=... e=... p=gcd(n,c) q=n//p phi_n=(p-1 )*(q-1 ) d=gmpy2.invert(e,phi_n) m=pow (c,d,n) m1=m//p print (libnum.s2n(int (m1)))
https://www.bilibili.com/read/readlist/rl472724