RSA
gcd(a,b)
def gcd(a:int,b:int):
# a%b=c
# b%c=d
# 当余数为0,除数就是最大公约数
while b:
a,b = b,a%b
return a
互素
def prime(a,b):
# a和b的最大公约数为1
if gcd(a,b)==1:
return True
else:
return False
Euler(n)
def Euler(n):
# 找到所有小于n且和n互素的数的个数
count=0
for i in range(1,n):
if prime(i,n):
count+=1
return count
Exgcd(a,b)
- ax + by = gcd(a,b)
- 求存在整数x,y
- 对于a>b,当b=0,gcd(a,b)=a;x=1,y=0
- 设ax1+by1=gcd(a,b)
- 有bx2+(a%b)y2=gcd(b,a%b)
- 有gcd(a,b)=gcd(b,a%b)
- 则ax1+by1=bx2+(a%b)y2
- ax1+by1=bx2+(a-[a/b]*b)*y2=ay2+bx2-[a/b]*by2
- 即ax1+by1 == ay2+b(x2-[a/b]*y2)
- x1=y2, y1=x2-[a/b]*y2
- x1,y1的值根据x2,y2求出
递归定义,b总有为0的时候
def exgcd(a,b): if b==0: return a,1,0 else: d,x,y=exgcd(b,a%b) x,y=y,x-(a//b)*y return d,x,y
mod_invert(a,b)
def mod_invert(a,b): # 求模逆 d,x,y=exgcd(a,b) # 判断是否互质 if d!=1: print('no') else: print((x%b+b)%b)
中国剩余定理
- 有x≡x1 mod n1
- x≡x2 mod n2
- x≡x3 mod n3...
- 求解所有模数的乘积N=n1*n2*n3...
- 对于每个i计算ni'=N//ni,求解m*ni'≡1(mod ni)的一个解m,m和ni'互质,用扩展欧几里得算法求解
计算x=求和(xi*ni'*m)
import gmpy2 from funtools import reduce def CRT(items): N=reduce(lamda: x,y:x*y, (i[1] for i in items)) result=0 for x,n in items: ni=N//n d,r,s=gmpy2.gcdext(n,ni) if d!=1: raise "gcd error" result+=x*ni*s return result%N, N
RSA已知p,q,e求解私钥D
原理
- φ(pq)=(p-1)*(q-1)
e*d ≡1 mod φ(pq) 求解d
题目
在一次RSA密钥对生成中,假设p=473398607161,q=4511491,e=17 求解出d作为flag提交
题解
import gmpy2 p=473398607161 q=4511491 e=17 phi_n=(p-1)*(q-1) d=gmpy2.invert(e,phi_n) print(d)
RSA已知p,q,e,c求解明文
- c=m^e(mod n)
m=c^d(mod n)
题目
Math is cool! Use the RSA algorithm to decode the secret message, c, p, q, and e are parameters for the RSA algorithm. p = 9648423029010515676590551740010426534945737639235739800643989352039852507298491399561035009163427050370107570733633350911691280297777160200625281665378483 q = 11874843837980297032092405848653656852760910154543380907650040190704283358909208578251063047732443992230647903887510065547947313543299303261986053486569407 e = 65537 c = 83208298995174604174773590298203639360540024871256126892889661345742403314929861939100492666605647316646576486526217457006376842280869728581726746401583705899941768214138742259689334840735633553053887641847651173776251820293087212885670180367406807406765923638973161375817392737747832762751690104423869019034 Use RSA to find the secret message
题解
import gmpy2 # p= # q= # e= # c= n=p*q phi_n=(p-1)*(q-1) d=gmpy2.invert(e,phi_n) m=pow(c,d,n) print(m)
RSA已知q,p,dp,dq,c求解明文
- dp=d(mod p-1)
- dq=d(mod q-1)
- n=p*q
- m1=c^dp(mod p)
- m2=c^dq(mod q)
- invp=gmpy2.invert(p,q)
(m=((m2-m1)*invp%q)+m1)(mod n)
题目
p = 8637633767257008567099653486541091171320491509433615447539162437911244175885667806398411790524083553445158113502227745206205327690939504032994699902053229 q = 12640674973996472769176047937170883420927050821480010581593137135372473880595613737337630629752577346147039284030082593490776630572584959954205336880228469 dp = 6500795702216834621109042351193261530650043841056252930930949663358625016881832840728066026150264693076109354874099841380454881716097778307268116910582929 dq = 783472263673553449019532580386470672380574033551303889137911760438881683674556098098256795673512201963002175438762767516968043599582527539160811120550041 c = 24722305403887382073567316467649080662631552905960229399079107995602154418176056335800638887527614164073530437657085079676157350205351945222989351316076486573599576041978339872265925062764318536089007310270278526159678937431903862892400747915525118983959970607934142974736675784325993445942031372107342103852
题解
import gmpy2 import libnum # p = # q = # dp = # dq = # c = # gmpy2.invert返回mpz类型转为int型 invq=int(gmpy2.invert(p,q)) mp=pow(c,dp,p) mq=pow(c,dq,q) m=((mp-mq)*invq%p)*q+mq print(libnum.n2s(m))
dp泄露,已知e,n,c,dp
- dp = d (mod p-1)
- n=p*q
- m = c^d (mod n)
- e dp = e d(mod p-1)
- e d = k2(p-1) + e dp
- d e = k1(p-1) (q-1) +1
- k2(p-1) + e dp = k1(p-1) (q-1) +1
- (p-1) (k1 (q-1) -k2 )+1=e * dp
- 设i=k1 * (q-1) -k2
- (p-1)i + 1 = dp * e
1< i < e
# e= # n= # dp= # c= import gmpy2 from Crypto.Util.number import long_to_bytes for i in range(1,e): #在范围(1,e)之间进行遍历 if(dp*e-1)%i == 0: if n%(((dp*e-1)//i)+1) == 0: #存在p,使得n能被p整除 p=((dp*e-1)//i)+1 q=n//p phi=(q-1)*(p-1) #欧拉定理 d=gmpy2.invert(e,phi) #求模逆 m=pow(c,d,n) #快速求幂取模运算 print(long_to_bytes(m))
共模攻击,已知c1,c2,e1,e2,n
适用情况:明文m、模数n相同,公钥指数e、密文c不同,gcd(e1,e2)=1也就是e1和e2互质。
# c1= # c2= # e1= # e2= # n= import gmpy2 from Crypto.Util.number import long_to_bytes assert gmpy2.gcd(e1,e2)==1 _, r, s = gmpy2.gcdext(e1, e2) m = pow(c1, r, n) * pow(c2, s, n) % n print (long_to_bytes(m))
rsa公钥读取
import gmpy2 from Crypto.Util.number import * from Crypto.PublicKey import RSA # 从公钥里面提取n 和 e with open('./pub.key','r') as f: key = RSA.import_key(f.read()) e = key.e n = key.n #通过分解n得到p和q #p = #q = d = gmpy2.invert(e,(p-1)*(q-1)) with open('./flag.enc','rb')as f: c = bytes_to_long(f.read()) m = pow(c,d,n) print(long_to_bytes(m))
rsaroll
import libnum from Crypto.Util.number import long_to_bytes import gmpy2 # list1=[1123,123,123,132] flag="" n=920139713 q=18443 p=49891 e=19 for i in list1: c=i d = gmpy2.invert(e,(p-1)*(q-1)) m = pow(c, d, n) string = long_to_bytes(m) flag+=string.decode() print(flag)
低加密指数攻击
普通
- e很小,n很大
- 设e=3,m^3 = c (mod n)
- c = m^3(mod n)
c^(-3) = m(mod n)
import gmpy2 import os from functools import reduce from Crypto.Util.number import long_to_bytes # gmpy2.crt(c,n) def CRT(items): N = reduce(lambda x, y: x * y, (i[1] for i in items)) result = 0 for a, n in items: m = N // n d, r, s = gmpy2.gcdext(n, m) if d != 1: raise Exception("Input not pairwise co-prime") result += a * s * m return result % N, N # e, n, c # e = 0x3 # n=[] # c=[] data = list(zip(c, n)) x,n = CRT(data) m = int(gmpy2.iroot(x,e)[0]) print(long_to_bytes(m))
利用二分法逼近明文数值
from math import isqrt, gcd from Crypto.Util.number import long_to_bytes def rsa_low_exponent_attack(n, e, c): # 计算n的平方根 sqrt_n = isqrt(n) # 使用二分搜索逐步逼近m的值 low = 0 high = n while low <= high: mid = (low + high) // 2 # 计算mid ^ e % n result = pow(mid, e, n) # 如果result和c的值一样,说明mid是m的一个候选值 if result == c: return mid # 如果result比c的值小,则将搜索范围移到[mid+1, high] elif result < c: low = mid + 1 # 如果result比c的值大,则将搜索范围移到[low, mid-1] else: high = mid - 1 # 如果搜索失败,则返回None return None # 测试 if __name__ == "__main__": # n= # e= # c= m = rsa_low_exponent_attack(n, e, c) # 通过整数转换成明文并打印出来 print(long_to_bytes(m))
爆破
爆破e,给出多组c和n
import gmpy2 import os from functools import reduce from Crypto.Util.number import long_to_bytes import numpy as np # 生成15个素数 primes = np.array([2]) p = 3 while len(primes) < 15: if np.all(p % primes != 0): primes = np.append(primes, p) p += 2 # 步长为2 def CRT(items): N = reduce(lambda x, y: x * y, (i[1] for i in items)) result = 0 for a, n in items: m = N // n d, r, s = gmpy2.gcdext(n, m) if d != 1: raise Exception("Input not pairwise co-prime") result += a * s * m return result % N, N # n1 = # c1 = # n2 = # c2 = # n3 = # c3 = # c=[c1,c2,c3] # n=[n1,n2,n3] data = list(zip(c, n)) x,n = CRT(data) for i in primes: e = int(i) m = int(gmpy2.iroot(x, e)[0]) print(long_to_bytes(m))
公因数求解d,p
当有多个n和c时,求解ni和nj的公因数d,当d!=1,ni=d*p,分解成功
import gmpy2 import libnum # e=65537 # c=[c1,c2,c3,c4...] # n=[n1,n2,n3,n4...] for i in range(len(n)): for j in range(i+1,len(n)): d=gmpy2.gcd(n[i],n[j]) if d!=1: p=d q=n[i]//p d=gmpy2.invert(e,(p-1)*(q-1)) m=pow(c[i],d,n[i]) print(libnum.n2s(int(m)))
低解密指数攻击
s
from fractions import Fraction import gmpy2 # 分数连分展开函数 def continued_fraction(numerator, denominator): while denominator: q = numerator // denominator yield q numerator, denominator = denominator, numerator % denominator # Wiener攻击函数 def wiener_attack(e, n): cf = list(continued_fraction(e, n)) for i in range(1, len(cf)): convergents = cf[:i] fraction = 0 for j in range(len(convergents) - 1, -1, -1): fraction = Fraction(1, convergents[j] + fraction) if fraction.numerator == 0: continue d = fraction.denominator if pow(pow(2, e*d, n), 1, n) == 2: return d # 示例用法 e = 178733 n = 60593872938422941902673221260072586012037242157592041897301512918429293145157 d = wiener_attack(e, n) print("Private key d:", d)