CTF-Crypto 出题思路与解题思路

CTF-Crypto


出题思路:区块链、公钥RSA、流密码、分组密码

机密性(加密算法)、完整性(消息摘要)、可用性、认证性(认证签名)、不可否认性、

  1. 编码基础|HEX:a-f 0-9,考虑ascii解码

  2. 编码基础|Base64:A-W a-w 0-9 + / 共64个字符使用4字符表达3字节,不足用0替换,也即是=

    import base64
    str = "解密字符串" //将数字用!@#等替换
    basestr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
    
    newstr = ''
    table = ')!@#$%^&*('
    for i in str:
    	if i not in table:
    		newstr=newstr + i
    	else 
    		newstr=newstr+(table.index(i))
    
    import base64
    print(base.b64decode(newstr))
    
  3. 编码基础|古典密码学:单表代换加密–爆破和词频分析

    1. 凯撒密码:向前或后移动若干位。特定凯撒密码名–偏移量10 Avocat、偏移量13 ROT13、偏移量-5 Cassis、偏移量-6 Cassette
    2. 摩斯密码:点线
    3. 键盘密码:用手机九宫格或键盘位置加密
    4. 猪圈密码:以格子为基础的替换密码
    5. 培根密码:使用两种不同字体代表AB结合加密表加密
    6. 栅栏密码:要加密明文分成N个一组,然后每组第一个字相连
    7. 曲路密码:明文划分为矩阵
    8. 维吉尼亚密码:使用多表替换,同凯撒,利用重合性字频分析爆破
    9. Polybius、BrainFuck、与佛论禅、社会主义核心价值观编码、Ook!、云影密码(01246)、JsFuck(()[]!+)、圣堂武士密码、夏多密码(曲折加密)、跳舞的小人密码、
  4. 编码基础|仿射密码:一小串字母数字,有2个以上重复字母

    加密函数:E(x) = (ax + b) (mod m),其中 a与b互质,m是编码系统中字母的个数(通常都是26)。

    解密函数:D(x) = a^-1(x-b)(mod m),a的逆元可以用pow(a,-1,m)求出,

  5. 异或加密|OTP一次性密码本:key长度大于message,一次性key

  6. 现代密码|哈希函数:散列算法,单向性、固定长度、雪崩效应—MD5 16字节

    flag = 'd0g3{' + hashlib.md5(SECRET).hexdigest() + '}'
    broken_flag = 'd0g3{71b2b5616**2a4639**7d979**de964c}'
    assert flag[:14] == broken_flag[:14]
    assert flag[16:22] == broken_flag[16:22]
    assert flag[24:29] == broken_flag[24:29]
    ciphier = hashlib.sha256(flag).hexdigest()
    print(ciphier)
    '''ciphier = '0596d989a2938e16bcc5d6f89ce709ad9f64d36316ab80408cb6b89b3d7f064a'''
    
    //多线程爆破hash#!/usr/bin/python
    from pwn import pwnlib
    from pwnlib.util.iters import mbruteforce 
    import hashlib
    
    # flag = 'd0g3{71b2b5616**2a4639**7d979**de964c}'
    msgbroken = 'd0g3{71b2b5616**2a4639**7d979**de964c}'
    table = '0123456789abcdef'
    assert len(table) ==16
    
    m1 = 'd0g3{71b2b5616' 
    m2='2a4639' 
    m3='7d979' 
    m4='de964c}'
    
    def f(res):
    	ciphier = '0596d989a2938e16bcc5d6f89ce709ad9f64d36316ab80408cb6b89b3d7f064a'
    	msgbroken = m1+res[0:2]+m2+res[2:4]+m3+res[4:6]+m4
    	tmp = hashlib.sha256(msgbroken.encode("utf-8")).hexdigest()
    	if tmp ==ciphier:
    		return True
    
    if __name__ == "__main__":
        res = mbruteforce(f,table,6,method='fixed')
        print(m1+res[0:2]+m2+res[2:4]+m3+res[4:6]+m4)
    
  7. 现代密码|steam crypto:明文与随机数进行位异或得到密文,下面是随机数产生的一些函数

    Pseudorandom Number Generator PNG,伪随机生成器

    #Linear Congruential Generator
    S0 = seed   Si+1 = ASi + B mod m
    class LCG() :
    	def __init__(self, seed) :
    		self .state = seed
    		self.m = 2**32
    		self.A = random.getrandbits(32)| 1
    		self.B = random.getrandbits(32)| 1
    	def getbits(self):
    		self .clock()
    		return self .state
    	def clock(self):
    		self.state = (self.A * self.state + self.B) % self.m
    #decrypto
    S1 = S0A+B %m
    S2 = S1A+B %m
    A = (S2-S1)//gmpy2.invert(S1-S0,m)%m
    B = S0*A+B%m
    
    example:MT19937
    

    LFSR:liner feedback shift register

    P(x) = x^m + Pm-1 * x^(m-1) + ...+p1x+p0
    class LFSR:
    	def_init__ (self, key, taps): 
    		d = max(taps)
    		assert len(key) == d, "Error: key of wrong size."
    		self. S = key
    		self.t=[d-tfortintaps]
    	def sum(self, L) :
    		S=0
    		forxinL:
    		s^=x
    		return S
    	def_ clock(self):
    		b = self._ s[0]
    		self. S = self. _s[1:] + [self._ sum(self._ s[p] for p in self._ t)]
    		return b
    	def getbit(self):
    		return self._ clock()
    

    Correlation Attack

  8. 现代密码|block crypto

    1. Feistel结构:加解密相同,仅轮密钥顺序相反输入,round key按轮次与key进行进行function最后得到c m

      1. example:DES-》分组长度64bit,密钥长度64位,共16轮迭代
      2. blowfish
    2. Substitution-permutation network:每轮keyn与m做异或后产生多个固定大小s,s输入类似hashtable产出下个m,轮n次后输出c

      1. example:AES->输入输出长度固定,加密任意长度明文需要一些额外加工(不够就padding)->加工方式 ECB CBC CFB OFB CTR

      2. ECB:相同明文出现相同密文(攻击:通过剪切达到改变数据目的)

        def ecb_encrypto(text):
        	return text+flag
        #通过类似ascii爆破sql的方法,一个s里面的16个byte,只输入填充flag前15个,即放一位flag进来,此时得到加密后c1,这时候填充16个进去,通过遍历第16个的字符判定相等即可得出flag[0],如此反复最后得到整段flag
        
      3. CBC:每块密文都依赖前面的明文->有初始IV,与m异或后得到m0和key进行function_encrypto,得到的作为IV参与下一轮次的m异或(攻击:字节翻转攻击->通过修改iv和c来控制m)

        #encrypto
        flag="d0g3{1235346547}"
        key = "0123456789abcdef"
        iv = flag.strip('d0g3{').strip('}')
        
        hint = os.urandom(4) * 8
        msg = b'Welcome to this competition, I hope you can have fun today!!!!!!'
        
        def encrypto(message):
            aes = AES.new(key,AES.MODE_CBC,iv)
            return aes.encrypt(message)
        
        #解密aes-CBC
        #get key
        tmp = 56631233292325412205528754798133970783633216936302049893130220461139160682777
        hint = int(str(hex(tmp))[2:10] * 8, 16)
        key = long_to_bytes(tmp ^ hint)
        
        #get iv
        msg = b'Welcome to this competition, I hope you can have fun today!!!!!!'
        msgs = [msg[ii:(ii+16)] for ii in range(0,len(msg),16)]
        msgs.reverse()
        IV = binascii.unhexlify('3c976c92aff4095a23e885b195077b66')
        
        def decry(key,IV,ms):
        	aes = AES.new(key,AES.MODE_ECB)
        	return strxor(aes.decrypt(IV),ms)
        
        for ms in msgs:
        	IV=decry(key,IV,ms)
        print(b'd0g{'+IV+b'}')
        
      4. Padding:PKCS#7–>定义了一种padding方法,要填充n个bytes就填充n个0xn(攻击:padding oracle attack->因为padding错误oracle会报错)

        def pad(data):
        	p=16-len(data)%16
        	return data + bytes([p]) * p
        def unpad(data):
        	if not all([x == data[-1] for x in data[-data[-1]:]):
        		raise Va lueError
        	return data[:-data[-1]]
        
        
      5. CTR:产生个随机数字counter1,按顺序到countern,counter1与key参与func_encry运算得到的结果与m1异或,得到第一段密文m1,这样可以输入m马上得到c

      6. GCM:

  9. 现代密码|公钥密码:Factoring Integers大数分解 | Discrete Logrithm 离散对数| Elliptic Curves椭圆曲线

  10. RSA:最大公约数GCD:

def gcd(a,b):
 while b:
 	a,b = b, a%b
 	return a
def gcd(a,b):
 if b==0:	return a
 else 
 	a=gcd(b,a%b)
 	return a
def egcd(a,b):
 if b==0:	return (a,1,0)
 else:
 	g,x,y = egcd(b,a%b)
 	return (g,y,x-(a//b)*y)
  1. RSA|费马小定理 and 中国剩余定理
a^p = a mod p   推出 a^(q-1) = 1 mod p
由中国剩余定理得到 a^(q-1) = 1 mod p;a^(q-1) = 1 mod q;a^(q-1) = 1 mod n;
c^d = m ^ed = m^kphi+1 =m mod n
  1. RSA|过程分解:密钥生成,公钥加密,私钥解密

    1. 密钥生成:选大质数p、q, N=p*q,再选一个符合欧拉函数n的e,这样e必有倒数e-1,可得私钥d=e-1 mod(p-1)(q-1),公钥=(N,e),e大加密慢,e小不安全

    2. 公钥加密:明文m,计算密文C=m^e(mod N)

    3. 私钥解密:密文C,计算明文m=C^d(mod N)

  2. RSA|基于N分解的RSA几种情况

    1. 在线查询分解网站 http://www.factordb.com/index.php
    2. 使用yafu分解
    3. 使用费马或pollard泊拉分解
    4. p q相差过小:题目给p=nextprinme(q),说明pq特别接近,等价n=p^2,所以对n开方直接得pq之间值t,进而求nextprime(t)可得p
    5. 模n有公约数:利用gcd求
  3. RSA|共模攻击相同模数n加密,两个密文c 原理:a * e1+b * e2 = 1,有n,e1,c1,e2,c2,求e1 e2的逆元和公因子

  4. RSA|维纳攻击e指数特别大,d作为倒数特别小,有n,e,c, phi = (p-1)*(q-1) = pq - (p+q)+1 = n-(pq)+1 => p+q = n-phi+1,连分子计算

  5. RSA|低加密指数攻击(小明文攻击):e一般是65525,当e=3时,可直接破解

    如果e=3,且m^en,那么设k,有:
     c= m^e +kn
     
    爆破k,如果c−kn能开三次根式,得到m.
    
  6. RSA|低加密广播攻击:如果选取的加密指数较低,并且使用了相同的加密指数给一个接受者的群发送相同的信息,那么可以进行广播攻击得到明文。n、c不同,明文m,e相同,其e比较小。爆破e后求根,使用中国剩余定理求解

  7. RSA|共享素数:两个n里使用有相同的素数p或q。在CTF中,同样一个e(一般为65537)和m, 有两个或多个n和c时,那么n之间可能是共享素数

  8. RSA|dp泄露:dp=d%(p-1),有n,e,dp,c

  9. RSA|dp dq:dp=d%(p-1) dq=d%(q-1),有p,q,c,dp,dq

  10. RSA|n是p的r次方:n=p^r,有q,n,e,c

  11. RSA|N分解三个素数:n分解出三个素数

  12. RSA|e和phi_n不互素:不互素就没倒数d,需要e除两者最大公约数再互素

  13. RSA|选择密文攻击:

  14. 现代密码|离散对数Diffle-Hellman密钥协商协议,约定大质数p、模p下的生成元g(p,g必互素)

    1. A选a,计算A=g^a(mod p) -> B
    2. B选b,计算B=g^b(mod p) -> A
    3. KEY=Ba=Ab=g^ab(mod p)
  15. 现代密码|离散对数:ElGamal Encryption Scheme

    1. alice在范围2:p-2范围选d, 计算b=a^d,发送(p, a, b)给bob;
    2. bob在范围2:p-2范围选i,计算ephemeral key为Ke=a^i, 计算masking key为Km=b^i, 密文c=m*Km mod p,发送(c, Ke)给alice
    3. alice收到后计算masking key Km=Ke^d, 解密出密文m=c*Km^-1 mod p
  16. 现代密码|离散对数:DLP

  17. 现代密码|椭圆曲线:三个问题:密钥交换、数字签名、离散对数

    1. 定义:y^2 = x^3 + ax + b mod p,有限域上的计算,零元是O, 4a^3 +27b^2 !=0 mod p ;p不能等于E
    2. ECDLP困难问题:P+P+…+P=dP=Q , 给P Q,计算d很困难,但是dP很简单
    3. point addition点加法:沿曲线的P+Q两点画线,继续这条线直到第三次相交曲线,最后在第三点(x,y)沿y取反,即(x,-y),一个点的话就是切线找第二个点
    4. 点的阶:对于ecc上一点P,若存在一个最小的正整数n,使nP=0,则称n是P的阶
    5. 椭圆曲线的阶:有限域上ecc由有限点组成,多少点ecc就是多少阶
    6. 估计曲线上点数:p+1-2根p <=#E <=p+1+2根p ,点数靠近素数p
    7. ECDH:Elliptic Curve Diffie-Hellman Key Exhange椭圆曲线Dh秘钥交换
      1. 用素数p生成椭圆曲线E和点P=(xp-yp)
      2. Alice和bob选择随机私钥keya=1:#E-1, 交换A=keya*P和B=keyb*P ,即使被截取,也无法通过A B计算出两者的key
      3. Alice和Bob的公钥为K=aB=a(keyb*P)=bA=b(keya*P)
      4. 还原方法:Pohlig-Hellman

总结

攻击 需求 使用
共模攻击 1n(同), 2e, 2c 同n,求e1 e2的逆元和公因子
广播攻击 多n, 1e, 多c 共享素数,即中国剩余定理,gcd(n1,n2)出p,分别求q1q2
维纳攻击 n, e(大), c e很大,d很小,e/n近似k/d,连分子计算
小e攻击 n, e(小), c 小明文攻击,通过m^e%n反向得出当e小时,可通过c开根爆破出m
模(n)不互素 2n, 1e, 2c gcd(n1,n2)出p
NC不互素 n, e, c gcd(n,c)出p
仅dp泄露 n, e, c, dp dp放d位置,计算后删掉dp,重新计算出d填入
dp dq泄露 p, q, c, d, dp, dq dp dq放入d位置计算,计算n后选e del_f不互素
e del_f p, q, e, c
rabin算法 p, q, n, c, e
n是p的r次方 n, e, c p位置重复r次填

example

nc不互素:指n与c有最大公约数,这个公约数是与p相关数,通过p可求出q,最后通过题目给出算式得出m

#M = 2021 *m*1001*p  
#c = pow(M,e,n) //题目给条件,给c n e
#推理:c = M^e%n = M^e+kn = (2021 *m*1001*p)^e + k*p*q
#两边同时mod p , c%p = (2021 *m*1001*p)^e%p + k*p*q%p
# c % p = 0,所以c=kp,n=qp,c与n存在公因数
import gmpy2
import libnum
n= c= e= 65537

p = gmpy2.gcd(n,c) //求最大公因数
q = n//p
phi_n = (p-1)*(q-1)  
d = gmpy2.invert(e,phi_n)
M = pow(c,d,n)
m = M//(2021*1001*p)#需要除掉无关数得到真正的密文m
print(libnum.n2s(int(m)))

#2 题目给c=pow(m*p+n,e,n),同上步骤
#(m*p+n)^e%n=c,两边mod p,c=kp,n c存在公约数,求解出m1,此时m1=m*p+n,因为n=kp,与前面合并即m1=m*p
#m = m1//p

pq的逆元:不给q,p,但是给出p,q的逆元,可以通过推理公式,最后计算长度得知k值,使用脚本联立方程跑出p q

#p = libnum.generate_prime(512)
#q = libnum.generate_prime(512)
#p1 = gmpy2.invert(p,q)
#q1 = gmpy2.invert(q,p)
#c = pow(m,e,n) 题目给p1,q1,phi_n,e,c
#推理:
#p1*p%q=1	p1*p-1=k1q	 
#q1*q%p=1	q1*q-1=k2p
#上下两方程相乘 (p1*p-1)*(q1*q-1)=kpq 
#				p1*q1*n+1-p1p-q1q=kn
#					p1p+q1q-1=kn ,此时由于给出pq长度,pq=n,所以n长度不超过1024,推出k=1
#联立phi=(q-1)*(p-1),p1p+q1q-1=n,可得pq

#解题
import gmpy2
import libnum
from z3 import *
e= 65537 phi=  c=  p1= q1= 

s = Solver()
p=Int("p")
q=Int("q")
s.add(phi==(q-1)*(p-1))  #联立方程组
s.add(p1*p+q1*q-1==p*q)
if s.check()==sat:
    print(s.model())
p = 
q = 
n = q*p
d = gmpy2.invert(e, phi)
m = pow(c,int(d),int(n))
print(libnum.n2s(int(m)))

费马小定理运用:a^p=a mod p

#hint = pow(2020*p+2021, q, n)   题目给出n c hint 
#推理:h=(2020*p+2021)^q%n=(2020*p+2021)^q+kn=k1p^q+2021^q+k2n
#两边mod p	h%p=2021^q%p
#				2021^q%p-h=kp(p与n有倍数关系,即n与2021^p-h存在公约数,可以用gcd,但q不知道,需要替换)
#由费马小定理,a^p=a mod p 得,(2021^q)^p%p-h=kp 可推2021^q%p-h=kp,所以可证2021^n%p=2021^q%p
#最后得2021^n%p-h=kp,n与2021^n-h存在公因数,用gcd求解出p

import libnum
import gmpy2
n=
c=
hint=
e = 65537

p = gmpy2.gcd(pow(2021,n,n)-hint,n)  
#原本是gcd(2021^n-hint,n),但是太大无法计算,等化为2021^n%n,即pow(2021,n,n)
q = n//p
print(q,p)
phi = (p-1)*(q-1)
d = gmpy2.invert(e, phi)
m = pow(c,d,n)
print(libnum.n2s(int(m)))

pq在两条不同公式,通过消去得到n替代

# h1=pow(2022*p+2021*q,1919,n)
# h2=pow(2021*p+2022*q,9191,n)  题目给出条件,p q在通过h1 h2给出
# c=pow(m, e ,n)
h1= h2= n= c= e=65537
#推理
# h1 = 2022*p+2021*q ^ 1919 %n
# h2 = 2021*p+2022*q ^ 9191 %n
#两边同乘,直到右边相等,相减消去
# h1^9191*2021^(9191*1919)%q = 2022^(9191*1919)*p^(1919*9191)*2021^(9191*1919)
# h2^1919*2022^(9191*1919)%q = 2021^(9191*1919)*p^(9191*1919)*2022^(9191*1919)

# h2^1919*2022^(9191*1919)-h1^9191*2021^(9191*1919)
#存在公约数
# h2^1919 *p^ 9191*1919-h1^9191 =kn
#数字太大,需要通过pow减小
h3 = pow(h2,1919,n)*pow(2022,9191*1919,n)-pow(h1,9191,n)*pow(2021,9191*1919,n)
p = gmpy2.gcd(h3,n)
q = n//p
phi = (p-1)*(q-1)
d = gmpy2.invert(e,phi)
m = pow(c,d,n)
print(libnum.n2s(int(m)))

二项式:(n+1)^p = (kpn+1)

# g=n+1
# c= (pow(g,p,n*n) *pow (m,n,n*n))%(n*n)
# print("c="+str(c))
# print("n="+str(n))
# print("hint="+str(pow(m,n,n*n)))  题目给出条件
#推理:c = [(g^p)%n*n * (m^n)%n*n]%(n*n) = (g^p * m^n)%(n*n) =(n+1)^p%(n*n)*hint
#		c + knn = (kpn+1)*hint = kpn*hint+hint 
#		c-hint = kpn*hint + knn
#		(c-hint) // n = kp*hint + kn
#两边同时mod p, (c-hint) // n =kp ,[(c-hint)//n]与n存在公约数

p = gmpy2.gcd((c-hint)//n,n)
print(p)
q = n//p
phi = (p-1)*(q-1)
d = gmpy2.invert(n,phi)
m = pow(c,d,n)
print(libnum.n2s(int(m)))

pq接近但无c:通过c的其他表达替换解出c,pq接近证明可用yafu分解

#给e n  c1  c2
#解析:n扔yafu解出p q, c1=c+kp c2=c+kq 
# c1=c2+kp+kq  (c1-c2)%q=kp  两边同除p,即pq逆元p1,(c1-c2)*p1%q = k
#即c = c1-(c1-c2)*p1%q
p1 = gmpy2.invert(p,q)
d = gmpy2.invert(e,(p-1)*(q-1))
m = pow(c1-(c1-c2)*p1%q, d, n)
print(libnum.n2s(int(m)))

共享素数(广播攻击):同素数,直接gcd(n1,n2),p是共同的素数,后面就按照题目逻辑继续

e = n1 = c1 = n2 = c2 = 
q = gmpy2.gcd(n1,n2)
p = n1//q
d = gmpy2.invert(e,(q-1)*(p-1))
m = libnum.n2s(int(pow(c1,d,n1)))
print(m)

小明文攻击(e很小):题目只给c n,通过m^e%n反向得出当e小时,可通过c开根爆破出m

题目只给了出
e=2  c= n= 
import libnum
import gmpy2
for i in range(2**6):
    if i ==0:
        continue
    if gmpy2.iroot(c,i)[1]==True:  #开根
        print(gmpy2.iroot(c,i)[0])
# print(libnum.n2s(int(29305044677847256883031643626546437461373017758852477))) #明文转字符

共模攻击:n相同,求e1 e2逆元再用公因子求根

#e1e2 = 3087   flag1 = pow(m1,e1,n)  flag2 = pow(m1,e2,n)
#推理:给了e1*e2,和c1 c2,爆破拆散e1e2组合,然后分别放入等式
#c1 = m1^e1%n ,c2 = m1^e2%n ,两边同时开方e1 e2的逆元k1 k2,让右边等于m1
#c1^k1%n= m1,c2^k2%n=m1,等式相乘后对结果用公因子求根,m = gmpy2.iroot(m0,k)[0]

import libnum
import gmpy2

flag1=  flag2=  n=  e1e2=3087
for e1 in range(1, e1e2 + 1):
    if e1e2 % e1 == 0:
        e2 = e1e2 // e1
        k ,k1,k2= gmpy2.gcdext(e1,e2) #k1 k2此时是逆元,即求d
        m0 = pow(flag1,k1,n)*pow(flag2,k2,n)%n   
        m = gmpy2.iroot(m0,k)[0]
        print(libnum.n2s(int(m)))

相邻素数:有next_prime必能分解,分解出pq观察代码,c1 c2有两条公式组成,上z3,出原文

p = sympy.nextprime(secret_num)
q = sympy.nextprime(p)
n=pq
c1 = F1 + F2
c2 = pow(F1, 3) + pow(F2, 3)
assert(c2 < N)
m1 = pow(c1, e, N)
m2 = pow(c2, e, N)
#提供n,e,m1,m2
#解题
s = Solver()
f1=Int("f1")
f2=Int("f2")
s.add((f1+f2)==int(c1))
s.add((f1**3)+(f2**3)==int(c2))
if s.check()==sat:
    print(s.model())

n分解出3个素数:有多余的,需要n后面除掉

#初始化n和phi。遍历3素数,查看e与哪个互素,是就乘进去n和phi,然后正常流程
import libnum
import gmpy2
from z3 import *
n = 3454083680130687060405946528826790951695785465926614724373
e = 3
c = 1347530713288996422676156069761604101177635382955634367208

p=11761833764528579549
q=17100682436035561357
r3=17172929050033177661
n, phi = 1, 1  #初始化n phi,也可以除掉不互素的
for i in [p,q,r3]:
    if not gmpy2.gcd(e, i - 1) - 1:
        phi *= i - 1
        n *= i
#或  phi = (p-1)*(r3-1)          n=n//q
d = gmpy2.invert(e, phi)
flag = pow(c, d, n)
print(libnum.n2s(int(flag)))

爆破公式和e

# A=(((y%x)**5)%(x%y))**2019+y**316+(y+1)/x
# p=next_prime(z*x*y)
# q=next_prime(z)   题目条件,给出n A c
#解析:没有pq,试试扔工具拆分,不行就用A等式爆破x y,爆破后n=z^2*x*y,n开方后即得到z,在附近找素数
#题目给的n可以拆分,所以直接出pq,然后爆破e
# print(p//q)
# for x in range(1,1000):
#     for y in range(1,1000):
#         try:
#             if ((((y%x)**5)%(x%y))**2019+y**316+(y+1)//x==A):
#                 print(x,y)
#         except:
#             continue
x = 2   y = 83
for e in range(1,2^50):
    if gmpy2.is_prime(e)==True:
        try:
            d = gmpy2.invert(e, (p-1)*(q-1))
            flag = pow(c,d,n)
            if b'CTF{' in libnum.n2s(int(flag)):
                print(libnum.n2s(int(flag)))
        except:
            continue

p高位泄露:有p>>200,只剩高位

p3 = getPrime(512)
q3 = getPrime(512)
N3 = p3*q3
给e n3 p3>>200  c

#解析,上sage,打开sage notebook
from sage.all import *
c3 = n3 = p3_200 =

pbits = 512
kbits = pbits - p3_200.nbits()
p3 = p3_200 << 200
print(p3.nbits())

PR. = PolynomialRing(Zmod(n3))       # 构建多项式环
f = x + p3      # 定义函数
roots = f.small_roots(X = 2^kbits,beta = 0.4)       #直接解出低位
if roots:
    print(roots[0])
    p = p3 + int(roots[0])
    print("n3: "+str(n3))
    print("p: "+str(p))
    print("q: "+str(n3//p))

密钥加密及打开

import libnum
import gmpy2
from z3 import *
from Crypto.Util.number import *
from Crypto.PublicKey import RSA
import base64
from Crypto.Cipher import PKCS1_OAEP

p=
q=

with open("public.key","rb") as f:
    key = RSA.import_key(f.read())
    n=key.n
    e=key.e
    print(n,e)
with open("flag.enc","rb") as f:
    c=f.read()
    c=base64.b64decode(c)
    c=libnum.s2n(c)
    print(c)

d = gmpy2.invert(e, (p-1)*(q-1))
# flag = pow(c1, d, n2)
rsa_components = (n, e, int(d), p, q)
arsa = RSA.construct(rsa_components)
rsakey = RSA.importKey(arsa.exportKey())
rsakey = PKCS1_OAEP.new(rsakey)
decrypted = rsakey.decrypt(libnum.n2s(c))
print(decrypted)

你可能感兴趣的:(CTF,python,网络安全)