cry1 题目如下,就是一个脚本:
from Crypto.Util.number import *from secret import flag,keyassert len (key) <= 5 assert flag[:5 ] == b'cazy{' def can_encrypt (flag,key ): block_len = len (flag) // len (key) + 1 new_key = key * block_len return bytes ([i^j for i,j in zip (flag,new_key)]) c = can_encrypt(flag,key) print(c)
zip() 函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表。
如果各个迭代器的元素个数不一致,则返回列表长度与最短的对象相同,利用 * 号操作符,可以将元组解压为列表。
这道题就是一个简单的异或,从can_encrypt()函数中能看出来flag的每一位都和密钥进行了异或,只要再异或回去即可得到flag,即从a^b=c还原a,a=b^c
提示里给出了flag的前5位,并且密钥的长度小于等于5,再根据密文的前5位,将他们异或,即可得到密钥
根据密文的长度27,密钥的长度5还原出block_len为6
解题脚本如下:
from Crypto.Util.number import *def can_encrypt (flag,key ): block_len = len (flag) // len (key) + 1 new_key = key * block_len return bytes ([i^j for i,j in zip (flag,new_key)]) c=b'<pH\x86\x1a&"m\xce\x12\x00pm\x97U1uA\xcf\x0c:NP\xcf\x18~l' clue='cazy{' key=[] flag='' for i in range (5 ): key.append(ord (clue[i])^c[i]) key=key*6 for i in range (27 ): flag+=chr (c[i]^key[i]) print(flag)
cry2 题目如下:
import randomfrom Crypto.Util.number import long_to_bytesfrom Crypto.Cipher import AESfrom secret import flagassert flag[:5 ] ==b'cazy{' def pad (m ): tmp = 16 -(len (m)%16 ) return m + bytes ([tmp for _ in range (tmp)]) def encrypt (m,key ): aes = AES.new(key,AES.MODE_ECB) return aes.encrypt(m) if __name__ == "__main__" : flag = pad(flag) key = pad(long_to_bytes(random.randrange(1 ,1 <<20 ))) c = encrypt(flag,key) print(c)
先理解题目意思,pad函数将m的长度补成16的整数倍,encrypt函数调用了aes加密。算一下1<<20为1048576不是很大,可以爆破,同样调用库里的aes解密函数即可,通过前5位来判断是否为目的flag。
解题脚本:
import randomfrom Crypto.Util.number import long_to_bytesfrom Crypto.Cipher import AESdef pad (m ): tmp = 16 -(len (m)%16 ) return m + bytes ([tmp for _ in range (tmp)]) def encrypt (m,key ): aes = AES.new(key,AES.MODE_ECB) return aes.encrypt(m) c=b'\x9d\x18K\x84n\xb8b|\x18\xad4\xc6\xfc\xec\xfe\x14\x0b_T\xe3\x1b\x03Q\x96e\x9e\xb8MQ\xd5\xc3\x1c' for i in range (1 <<20 ): key = pad(long_to_bytes(i)) aes=AES.new(key,AES.MODE_ECB) plain=aes.decrypt(c) if plain[:5 ]==b'cazy{' : print(plain)
cry3 题目如下:
from Crypto.Util.number import *from secret import flagassert len (flag) <= 80 def sec_encry (m ): cip = (m - (1 <<500 ))**2 + 0x0338470 return cip if __name__ == "__main__" : m = bytes_to_long(flag) c = sec_encry(m) print(c)
没啥好说的,按照他的操作逆过来就行
有一点需要注意,python内置的函数用来开方精度不够,需要用gmpy2里的iroot函数:
gmpy2.iroot(x,n):x开n次根,返回两个参数,第一个为开方结果,第二个布尔参数,表示是否能开尽
解题脚本:
from Crypto.Util.number import *from gmpy2 import *def sec_encry (m ): cip = (m - (1 <<500 ))**2 + 0x0338470 return cip c=10715086071862673209484250490600018105614048117055336074437503883703510511248211671489145400471130049712947188505612184220711949974689275316345656079538583389095869818942817127245278601695124271626668045250476877726638182396614587807925457735428719972874944279172128411500209111406507112585996098530169 c-=0x0338470 assert iroot(c,2 )[1 ]c=iroot(c,2 )[0 ] m=-1 *c+(1 <<500 ) print(long_to_bytes(m))
cry4 题目如下:
from Crypto.Util.number import *from secret import flagassert flag[:5 ] == b'cazy{' assert flag[-1 :] == b'}' flag = flag[5 :-1 ] assert (len (flag) == 24 )class my_LCG : def __init__ (self, seed1 , seed2 ): self.state = [seed1,seed2] self.n = getPrime(64 ) while 1 : self.a = bytes_to_long(flag[:8 ]) self.b = bytes_to_long(flag[8 :16 ]) self.c = bytes_to_long(flag[16 :]) if self.a < self.n and self.b < self.n and self.c < self.n: break def next (self ): new = (self.a * self.state[-1 ] + self.b * self.state[-2 ] + self.c) % self.n self.state.append( new ) return new def main (): lcg = my_LCG(getRandomInteger(64 ),getRandomInteger(64 )) print("data = " + str ([lcg.next () for _ in range (5 )])) print("n = " + str (lcg.n)) if __name__ == "__main__" : main()
根据题目意思,flag被拆成了三部分,在next函数里线性递推,已知n和递推出来的五个new值,根据题目意思我们可以得到如下的同余式组:
由于seed2和seed1未知,我们只考虑下面三个方程,并且下面三个方程也只有三个未知数,由此断定方程有解。
我们把方程组写成矩阵形式如下:
解出a,b,c如下:
由于python的numpy精度不够,所以我们用sagemath,下面给出一点基本使用方法:
SageMath矩阵操作及解线性方程组_m0_46161993的博客-CSDN博客_sagemath 矩阵
SageMath常用函数_panfengblog-CSDN博客_sagemath
解出a,b,c后写个脚本flag就出来了
解题脚本:
from Crypto.Util.number import *data = [2626199569775466793 , 8922951687182166500 , 454458498974504742 , 7289424376539417914 , 8673638837300855396 ] n = 10104483468358610819 a,b,c=5490290802446982981 ,8175498372211240502 ,6859390560180138873 flag=long_to_bytes(a)+long_to_bytes(b)+long_to_bytes(c) print(b'cazy{' +flag+b'}' )
cry5 题目如下:
pinvq:0x63367a2b947c21d5051144d2d40572e366e19e3539a3074a433a92161465543157854669134c03642a12d304d2d9036e6458fe4c850c772c19c4eb3f567902b3 qinvp:0x79388eb6c541fffefc9cfb083f3662655651502d81ccc00ecde17a75f316bc97a8d888286f21b1235bde1f35efe13f8b3edb739c8f28e6e6043cb29569aa0e7b c:0x5a1e001edd22964dd501eac6071091027db7665e5355426e1fa0c6360accbc013c7a36da88797de1960a6e9f1cf9ad9b8fd837b76fea7e11eac30a898c7a8b6d8c8989db07c2d80b14487a167c0064442e1fb9fd657a519cac5651457d64223baa30d8b7689d22f5f3795659ba50fb808b1863b344d8a8753b60bb4188b5e386 e:0x10005 d:0xae285803302de933cfc181bd4b9ab2ae09d1991509cb165aa1650bef78a8b23548bb17175f10cddffcde1a1cf36417cc080a622a1f8c64deb6d16667851942375670c50c5a32796545784f0bbcfdf2c0629a3d4f8e1a8a683f2aa63971f8e126c2ef75e08f56d16e1ec492cf9d26e730eae4d1a3fecbbb5db81e74d5195f49f1
一看特征就知道考察rsa,出于简便,我们把pinvq记为x,qinvp记为y。其中pinvq是q关于q的逆元,qinvp是q关于p的逆元,由此得出以下同余式:
将其改写成如下形式:
将上面两式做差得:$p(k_{2}+x)=q(k_{1}+y)$
由于p和q为素数,所以我们得到:
将p和q代回上面 的$k_{1}q+1=p\ x$并化简得到
所以$k_{2}=\frac{xy-1}{k_{1}} $
又由于$\phi (n)=(p-1)(q-1)=(k_{1}+y-1)(k_{2}+x-1)$
将k2代入得$\phi(n)=(k_{1}+y-1)(\frac{xy-1}{k_{1}}+x-1 ) $
为避免出现除法,我们写成如下形式:
由于$e*d \equiv 1 \pmod{\phi (n)} $,所以$e*d =k*\phi (n)+1$,所以
注意到$d< \phi (n)$,所以k是小于e的,而e给的并不大,所以我们可以枚举k
通过$\phi (n)=\frac{e*d-1}{k} $求出$\phi (n)$,这样上面的方程只有一个未知数$k_{1}$了,利用python的z3库即可解方程
z3基本使用如下:
python z3库 - Hello World
Z3Py教程(翻译)_40KO的博客-CSDN博客_python z3
解题脚本:
from Crypto.Util.number import *from gmpy2 import *from z3 import *pinvq = 0x63367a2b947c21d5051144d2d40572e366e19e3539a3074a433a92161465543157854669134c03642a12d304d2d9036e6458fe4c850c772c19c4eb3f567902b3 qinvp = 0x79388eb6c541fffefc9cfb083f3662655651502d81ccc00ecde17a75f316bc97a8d888286f21b1235bde1f35efe13f8b3edb739c8f28e6e6043cb29569aa0e7b c = 0x5a1e001edd22964dd501eac6071091027db7665e5355426e1fa0c6360accbc013c7a36da88797de1960a6e9f1cf9ad9b8fd837b76fea7e11eac30a898c7a8b6d8c8989db07c2d80b14487a167c0064442e1fb9fd657a519cac5651457d64223baa30d8b7689d22f5f3795659ba50fb808b1863b344d8a8753b60bb4188b5e386 e = 0x10005 d = 0xae285803302de933cfc181bd4b9ab2ae09d1991509cb165aa1650bef78a8b23548bb17175f10cddffcde1a1cf36417cc080a622a1f8c64deb6d16667851942375670c50c5a32796545784f0bbcfdf2c0629a3d4f8e1a8a683f2aa63971f8e126c2ef75e08f56d16e1ec492cf9d26e730eae4d1a3fecbbb5db81e74d5195f49f1 for k in range (1 ,e): phi=(e*d-1 )//k if (e*d-1 )%k!=0 : continue if e*d%phi!=1 : continue x=Int('x' ) s=Solver() s.add(x*phi==(x+qinvp-1 )*(pinvq*qinvp-1 +x*(pinvq-1 ))) if s.check()==sat: print(s.model()) k1=int (str (s.model()[x])) k2=(pinvq*qinvp-1 )//k1 p=k1+qinvp q=k2+pinvq print(long_to_bytes(pow (c,d,p*q)))