依然有最喜欢的maple师傅的题,依然做不来几道,不过还是记录一下。打*的赛后才会做,打$的不会做。
base64
题目描述:
1 | yet another base64 decoding challenge |
题目:
1 | from Crypto.Util.number import bytes_to_long |
就是简单的把flag用64进制表示而已。
exp:
1 | from Crypto.Util.number import * |
integrity
题目描述:
1 | I think this is how signing works |
题目:
1 | from Crypto.Util.number import * |
题目给出了两组数据:
似乎比较复杂,但是搜索一下发现说这个crchqx其实就是计算从给定数值42开始的d的crc16的值,所以其实加密指数也只有16bit,因此爆破一下这个指数,然后共模就可以了。
exp:
1 | from Crypto.Util.number import * |
tango
题目描述:
1 | Let's dance! |
题目:
1 | from Crypto.Cipher import Salsa20 |
连上靶机后,靶机会随机生成32字节的KEY,之后有两个选项供选择:
- 输入E,可以输入一个command,靶机会对command进行加密
- 输入R,可以输入一段打包的密文,靶机会拆开这段密文,进行解密+检查
两种交互均可以无限次进行。
然后来看下加密的encrypt_command函数和解密的run_command函数分别在做什么。
对于encrypt,需要输入一个长度为3的字符串当作command,然后靶机会用KEY初始化一个Salsa20的加密器,并加密下面这段json:
1 | {'user': 'user', 'command': command, 'nonce': token_hex(8)} |
同时,靶机会计算这段json的crc32值checksum,之后返回如下值作为密文:
1 | nonce + checksum + ciphertext |
这里需要注意一下返回的密文中的nonce和json里的nonce是不一样的。返回的nonce是本次Salsa20加密所用的nonce,而json里的nonce就是保证每次的json数据都不同而已
而对于decrypt,其接受的数据格式就是encrypt的密文格式。在接收到输入后,会先按照格式拆分出nonce、checksum和ciphertext,然后会依次执行下面的步骤:
- 用nonce和KEY初始化Salsa20加密器
- 用Salsa20加密器对ciphertext进行解密,得到plaintext
- 检查plaintext的crc32值是否与checksum相等,不相等则返回
- 用json加载plaintext,从中取出user和command
- 如果user为root,且command为flag,则得到flag
步骤就到这里结束了。
首先就是Salsa20之前完全没了解过,搜索一下发现是一种流密码。也就是说给定KEY和nonce,Salsa20会以某种方式产生密钥流,然后与明文加密就得到最终密文。这也就是说,对于同样的KEY和nonce,产生的密钥流也是一样的。
而要利用run_command解密之前,肯定首先是要加密一次的,这样才能获取nonce从而得到完全一样的密钥流。然而对于加密,我们唯一能输入的是长为3的command,也就是不能输入flag,并且user也不能改为root,此外最后的json里的nonce每次加密都是随机产生的,也未知,就更没办法计算出crc32的值了。
但是处理方法也很简单,由于密钥流确定,所以我们可以随意篡改每次data的任意字节和长度,也就是说,我就输入fla作为command,那么我得到的ciphertext是对下面这段json的加密:
1 | {'user': 'user', 'command': 'fla', 'nonce': xxxxxxxxxxxxxxxx} |
那么直接用下面这段json作为target:
1 | {"user": "root", "command": "flag"} |
与上面密文的对应长度做异或就得到diff,然后把ciphertext异或上这段diff并送回去解密就可以了,checksum直接对这段target做crc32就行。
exp:
1 | from Crypto.Util.number import * |
solitude
题目描述:
1 | The best thinking has been done in solitude. The worst has been done in turmoil. |
题目:
1 | #!/usr/bin/env python3 |
相当杂乱的一个RNG,大致来说是把0-129这些数字按某种方式每次选出一个,然后这些数字就组成了密钥流与flag异或。
其中,可以输入i来指定次数,每次会重新生成一个RNG并开始产生密钥流。次数多大都可以,目的是还原flag。
由于这个RNG感觉实在是太乱了,所以我先放弃理解直接上手试了试他的统计特性,结果发现一个结果:0这个数字几乎百分百在每个新RNG的前64个数字中最少出现一次。
直观一点用代码表示这个特征就是:
1 | res = [] |
得到结果:
1 | [(0, 996), (93, 546), (106, 542), (112, 539), (32, 534), (44, 533), (99, 530), (91, 530), (61, 528), (49, 527)] |
而剩下的之所以都是500次多一点,是因为除了0以外,所有数字出现概率较为随机,也就是有大约64/128的概率出现在密钥流的前64个之中。
虽然实际上flag长度是32,但是0“更容易出现在一个新RNG的前面”这个特点是不会改变的,所以光解题来说就很容易,由于所有flag字符都与0异或的最多,所以只需要发一个很大的i过去,统计出现次数最多的也就是flag字符。
exp:
1 | from pwn import * |
做完之后写wp的时候决定深究一下原因,具体流程用叙述的话有点长,可以自己看看。主要来说这个RNG有这么几个特点:
- 数字有0-129,共130个
- RNG只会产生0-127这128个数字
- 128、129这两个数字可以类比于“指针”的作用,他们在调控state如何变换
但即使这样做,还是太难看出有啥地方导致这种统计特性了,所以决定用删的方式来逐个判断一下是哪一部份在作怪,最终发现即使删成这样:
1 | def next(self): |
统计特性依然存在,并且发现前面总结的规律并不正确,0并不是在前面的位置出现概率大,而是在所有位置出现概率都更大。
但是还是没看明白为啥就有这个规律了,先放着吧TT。
lf3r
题目描述:
1 | LFSR's weakness comes from its linearity, so I come up with a new way to make it non-linear. Can you help me analyze it? |
题目:
1 | import secrets, os |
output.txt:
1 | stream = [2, 2, 0, 1, 0, 0, 0, 0, 0, 2, 1, 0, 0, 0, 2, 2, 1, 1, 2, 1, 0, 0, 1, 0, 0, 0, 0, 1, 2, 1, 0, 1, 0, 1, 0, 0, 0, 2, 2, 2, 0, 2, 1, 2, 0, 1, 1, 2, 1, 0, 0, 0, 0, 0, 2, 1, 2, 1, 2, 2, 1, 2, 2, 2, 2, 1, 0, 1, 0, 1, 0, 1, 2, 1, 2, 2, 1, 0, 0, 1, 2, 1, 2, 2, 1, 2, 1, 1, 1, 2, 2, 2, 1, 2, 1, 2, 0, 2, 2, 1, 2, 1, 1, 2, 1, 1, 0, 1, 1, 0, 2, 0, 2, 1, 2, 1, 2, 0, 1, 2, 1, 2, 1, 1, 2, 1, 2, 2, 0, 0, 2, 0, 0, 1, 2, 0, 2, 0, 1, 0, 2, 2, 1, 1, 2, 1, 2, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 1, 1, 0, 2, 1, 2, 1, 1, 2, 1, 2, 1, 1, 2, 1, 1, 2, 1, 0, 0, 2, 1, 1, 1, 1, 2, 0, 0, 1, 2, 1, 2, 2, 1, 1, 1, 2, 1, 0, 0, 1, 0, 0, 2, 0, 2, 2, 1, 1, 2, 1, 2, 0, 2, 0, 1, 1, 1, 2, 1, 1, 0, 0, 0, 2, 2, 0, 0, 1, 2, 1, 0, 0, 0, 0, 0, 2, 2, 1, 2, 1, 2, 0, 0, 0, 2, 1, 1, 2, 1, 1, 2, 1, 0, 2, 1, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 2, 1, 0, 2, 0, 2, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 2, 1, 2, 0, 2, 1, 2, 0, 2, 1, 1, 0, 1, 2, 0, 1, 2, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 2, 0, 1, 1, 2, 0, 2, 1, 1, 2, 1, 2, 0, 0, 1, 2, 2, 1, 2, 1, 1, 2, 1, 0, 2, 2, 2, 1, 1, 2, 2, 2, 0, 0, 1, 2, 0, 0, 0, 1, 2, 2, 2, 2, 2, 0, 1, 2, 1, 0, 2, 0, 1, 0, 0, 2, 1, 2, 1, 2, 1, 2, 1, 1, 2, 1, 2, 1, 1, 2, 0, 1, 2, 1, 2, 0, 0, 2, 2, 1, 2, 1, 1, 0, 2, 1, 0, 1, 1, 1, 0, 0, 1, 1, 2, 0, 1, 0, 2, 1, 2, 1, 2, 1, 2, 1, 1, 1, 2, 2, 0, 1, 2, 1, 2, 2, 2, 0, 0, 0, 0, 2, 1, 0, 1, 2, 2, 1, 0, 2, 1, 1, 2, 1, 2, 0, 0, 0, 0, 0, 1, 2, 1, 2, 0, 1, 2, 1, 1, 2, 1, 2, 1, 0, 2, 2, 2, 1, 2, 0, 2, 1, 1, 1, 0, 1, 1, 2, 2, 1, 2, 2, 2, 1, 0, 1, 2, 2, 1, 2, 0, 0, 0, 0, 0, 2, 1, 2, 0, 2, 1, 0, 2, 0, 1, 2, 0, 2, 1, 2, 1, 2, 1, 1, 2, 1, 2, 2, 1, 2, 2, 1, 1, 0, 0, 1, 0, 0, 2, 1, 2, 0, 0, 0, 1, 0, 1, 2, 1, 0, 0, 0, 0, 0, 1, 2, 1, 0, 0, 0, 0, 0, 1, 2, 1, 1, 0, 0, 2, 2, 0, 1, 2, 0, 0, 0, 0, 0, 2, 2, 0, 0, 1, 1, 2, 1, 1, 1, 0, 0, 2, 1, 2, 1, 0, 0, 0, 2, 2, 0, 1, 1, 1, 2, 1, 2, 0, 0, 1, 2, 1, 2, 1, 0, 2, 0, 1, 1, 1, 2, 1, 2, 1, 1, 1, 2, 1, 2, 0, 2, 1, 0, 0, 1, 0, 1, 0, 1, 1, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 2, 1, 0, 2, 2, 1, 2, 0, 0, 1, 1, 1, 2, 1, 1, 2, 1, 1, 2, 1, 1, 2, 0, 0, 1, 0, 1, 2, 2, 1, 2, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 2, 0, 2, 0, 2, 1, 1, 2, 0, 0, 1, 2, 1, 0, 0, 0, 2, 2, 1, 2, 1, 0, 0, 2, 1, 1, 0, 1, 2, 0, 2, 0, 0, 2, 0, 2, 1, 0, 0, 0, 1, 0, 2, 0, 1, 2, 0, 2, 0, 0, 2, 1, 1, 1, 0, 0, 0, 1, 2, 1, 1, 0, 2, 1, 2, 1, 0, 1, 0, 0, 0, 1, 2, 0, 1, 2, 0, 0, 0, 1, 2, 1, 2, 0, 2, 1, 0, 0, 2, 2, 1, 1, 0, 0, 2, 0, 0, 0, 0, 0, 1, 2, 1, 2, 1, 0, 1, 1, 0, 0, 2, 1, 1, 1, 2, 0, 0, 1, 1, 0, 2, 2, 1, 0, 2, 1, 2, 1, 2, 0, 2, 1, 1, 1, 0, 0, 1, 2, 2, 2, 1, 0, 0, 1, 2, 1, 1, 0, 0, 2, 0, 0, 0, 0, 0, 0, 2, 1, 2, 1, 0, 2, 2, 0, 1, 1, 1, 1, 1, 2, 2, 0, 1, 2, 1, 0, 1, 1, 1, 2, 1, 0, 1, 1, 0, 0, 1, 2, 1, 1, 2, 0, 2, 0, 2, 1, 2, 2, 0, 0, 2, 1, 0, 1, 0, 2, 2, 1, 2, 2, 2, 0, 0, 0, 0, 2, 1, 0, 0, 1, 1, 0, 1, 1, 2, 2, 1, 0, 0, 0, 2, 2, 2, 1, 2, 1, 0, 2, 0, 0, 2, 2, 0, 2, 1, 1, 1, 0, 0, 1, 2, 0, 1, 2, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 2, 0, 0, 1, 2, 1, 2, 2, 0, 1, 0, 0, 1, 1, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 1, 2, 1, 2, 1, 2, 0, 1, 2, 1, 0, 2, 0, 0, 2, 1, 2, 2, 1, 0, 1, 2, 2, 0, 0, 2, 0, 1, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 2, 1, 1, 2, 2, 0, 1, 2, 0, 2, 1, 2, 2, 1, 0, 0, 0, 0, 2, 1, 2, 1, 1, 2, 1, 2, 1, 2, 2, 2, 0, 0, 0, 2, 2, 0, 0, 2, 1, 1, 2, 1, 0, 0, 0, 0, 1, 0, 1, 0, 2, 2, 0, 2, 0, 2, 0, 2, 2, 1, 2, 2, 2, 1, 0, 0, 0, 0, 2, 1, 2, 1, 2, 2, 1, 2, 0, 1, 1, 0, 2, 1, 0, 1, 0, 2, 1, 0, 2, 1, 2, 1, 1, 2, 1, 0, 0, 2, 0, 1, 1, 0, 0, 1, 0, 0, 2, 1, 0, 1, 0, 0, 1, 2, 1, 1, 2, 2, 0, 2, 1, 2, 0, 0, 0, 2, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 2, 2, 0, 2, 1, 2, 2, 2, 1, 1, 0, 1, 0, 2, 1, 2, 0, 0, 2, 2, 1, 0, 1, 2, 0, 0, 0, 0, 1, 2, 1, 2, 2, 0, 0, 0, 0, 1, 1, 2, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 0, 0, 0, 0, 1, 2, 1, 1, 2, 1, 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 1, 0, 1, 2, 1, 1, 2, 1, 1, 2, 2, 1, 2, 2, 1, 1, 1, 1, 2, 0, 2, 2, 0, 1, 0, 2, 1, 0, 0, 0, 1, 2, 2, 0, 2, 1, 2, 2, 1, 0, 2, 1, 2, 1, 0, 0, 0, 0, 0, 1, 2, 1, 0, 2, 1, 1, 0, 0, 2, 0, 0, 0, 1, 1, 2, 1, 0, 2, 1, 2, 1, 2, 2, 1, 0, 0, 1, 2, 1, 2, 0, 2, 1, 2, 1, 1, 1, 1, 2, 1, 2, 2, 2, 1, 2, 2, 2, 0, 0, 0, 2, 1, 1, 1, 0, 1, 2, 2, 1, 0, 1, 2, 1, 2, 1, 0, 0, 0, 2, 2, 1, 1, 1, 1, 0, 0, 2, 1, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 1, 2, 0, 2, 1, 2, 2, 2, 2, 1, 1, 1, 2, 0, 0, 0, 1, 2, 0, 0, 1, 1, 0, 1, 2, 0, 1, 0, 0, 1, 0, 2, 1, 1, 2, 0, 0, 1, 2, 0, 0, 2, 1, 2, 1, 0, 0, 2, 1, 2, 0, 0, 2, 1, 2, 2, 1, 2, 1, 1, 2, 1, 1, 2, 2, 0, 0, 1, 1, 2, 2, 2, 0, 0, 0, 0, 1, 2, 2, 2, 2, 1, 2, 2, 1, 1, 2, 1, 2, 1, 0, 2, 1, 2, 1, 2, 0, 2, 1, 0, 0, 1, 2, 1, 2, 0, 0, 0, 0, 2, 1, 2, 2, 2, 1, 2, 0, 0, 0, 2, 1, 2, 1, 0, 1, 2, 1, 0, 2, 1, 2, 0, 0, 0, 1, 0, 0, 0, 0, 2, 2, 0, 0, 1, 2, 1, 0, 1, 1, 2, 1, 2, 1, 0, 2, 1, 0, 0, 1, 2, 1, 2, 0, 0, 1, 2, 2, 0, 1, 2, 0, 1, 0, 0, 0, 0, 0, 1, 2, 1, 1, 2, 1, 0, 0, 1, 2, 1, 0, 0, 2, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 2, 1, 2, 0, 0, 1, 2, 1, 2, 0, 0, 1, 2, 1, 0, 2, 0, 0, 2, 1, 1, 2, 2, 1, 1, 0, 2, 1, 0, 1, 1, 2, 2, 1, 2, 0, 0, 0, 1, 1, 1, 1, 0, 0, 2, 2, 1, 2, 1, 1, 0, 0, 1, 1, 2, 1, 2, 0, 0, 1, 0, 2, 1, 2, 2, 0, 1, 0, 1, 2, 1, 1, 1, 2, 1, 1, 1, 2, 0, 2, 1, 2, 1, 2, 1, 2, 0, 1, 0, 1, 0, 1, 0, 2, 1, 2, 1, 2, 1, 2, 1, 0, 1, 2, 1, 0, 0, 1, 2, 2, 1, 0, 0, 0, 0, 0, 2, 2, 1, 2, 0, 1, 0, 0, 1, 1, 2, 1, 2, 0, 0, 0, 2, 1, 0, 0, 1, 2, 2, 0, 0, 0, 1, 0, 2, 2, 1, 1, 2, 2, 1, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 2, 1, 2, 0, 0, 0, 1, 2, 1, 2, 1, 0, 0, 0, 2, 0, 2, 1, 0, 1, 1, 2, 1, 1, 2, 0, 2, 1, 2, 1, 1, 0, 0, 0, 0, 0, 0, 2, 1, 0, 0, 0, 1, 2, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 2, 2, 1, 1, 2, 1, 0, 1, 1, 2, 1, 2, 0, 1, 2, 1, 2, 1, 2, 0, 0, 2, 0, 2, 2, 1, 1, 1, 1, 1, 1, 2, 1, 0, 2, 1, 0, 0, 2, 0, 2, 1, 0, 0, 0, 0, 0, 2, 1, 0, 0, 0, 2, 1, 2, 0, 2, 1, 1, 0, 0, 2, 0, 1, 2, 0, 0, 1, 2, 0, 0, 0, 0, 1, 2, 1, 0, 1, 1, 0, 0, 0, 1, 2, 2, 1, 0, 2, 0, 2, 1, 2, 0, 2, 1, 2, 1, 1, 0, 2, 0, 0, 0, 0, 0, 1, 1, 2, 2, 2, 2, 1, 0, 0, 0, 1, 1, 2, 0, 1, 1, 2, 0, 0, 0, 2, 1, 1, 1, 2, 0, 1, 0, 0, 2, 1, 0, 0, 0, 0, 2, 2, 0, 2, 1, 0, 0, 0, 2, 1, 2, 1, 2, 1, 2, 0, 0, 2, 1, 1, 1, 2, 2, 0, 2, 1, 2, 0, 2, 0, 2, 1, 0, 0, 0, 0, 2, 1, 1, 0, 1, 1, 1, 2, 2, 0, 2, 1, 2, 0, 2, 1, 1, 2, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 2, 0, 1, 1, 1, 2, 1, 0, 2, 1, 0, 0, 1, 1, 1, 1, 0, 1, 2, 0, 0, 2, 2, 0, 0, 1, 1, 0, 0, 2, 2, 2, 0, 0, 0, 2, 2, 0, 2, 0, 2, 2, 0, 2, 1, 2, 2, 2, 0, 2, 1, 1, 1, 0, 2, 0, 0, 0, 1, 0, 2, 2, 0, 1, 0, 2, 1, 2, 2, 1, 0, 0, 1, 0, 2, 0, 2, 1, 0, 2, 0, 2, 2, 1, 0, 0, 0, 0, 2, 2, 2, 0, 2, 2, 1, 0, 0, 0, 2, 1, 1, 1, 0, 2, 2, 0, 2, 0, 2, 1, 0, 1, 2, 1, 1, 2, 1, 1, 1, 2, 1, 1, 0, 2, 2, 2, 2, 2, 1, 2, 1, 0, 1, 0, 1, 0, 1, 2, 2, 1, 2, 2, 1, 1, 2, 1, 1, 1, 1, 2, 0, 1, 2, 1, 0, 2, 0, 0, 2, 0, 2, 0, 1, 0, 0, 1, 2, 2, 2, 0, 1, 2, 1, 0, 0, 1, 1, 2, 0, 1, 1, 0, 2, 1, 0, 2, 2, 2, 0, 1, 2, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 2, 0, 1, 2, 0, 0, 0, 2, 0, 0, 1, 1, 1, 0, 2, 1, 2, 2, 2, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 2, 1, 2, 0, 1, 2, 0, 1, 2, 1, 2, 2, 1, 2, 0] |
这题自己做的时候路走偏了,感觉挺麻烦,但rec一来就给出了正解。
题目基于一个已知mask,未知初始state的LFSR递推。然而一个特殊的地方在于,每次递推之后给的并不是产生的二进制位,而是当前state模3的值。给出2048组数据,要求能够继续向后预测LFSR的递推过程,从而还原flag。
首先明确一个事情,就是LFSR依然完完全全在模2下递推,仅仅是给出的值是整个当前state在模3下的,这才使得整个系统显得不那么线性。那么不妨假设第一次递推前,也就是初始状态的256个bit为
那么这个state对应的256bit的整数是:
而如果把2模3看作是等于-1的话,那么整个式子模3就变成了:
也就等价于:
而下一个state也就是:
然后把这两个相加就可以消去绝大部分项:
此时注意,由于s256和s0都是一个二进制位,所以相减的取值仅有-1,0,1三种情况(-1也就对应2)。可以看出,当相减取值为1或-1时,就可以确定下两个bit的值分别为1、0和0、1,所以搜集足够的比特位就可以解线性方程得到初始state了。
exp:
1 | from Crypto.Util.number import * |
coast
题目描述:
1 | Isogeny cryptography seems so fun, so I build a new cryptosystem based on CSIDH. |
题目:
1 | from Crypto.Cipher import AES |
output.txt:
1 | base_ser = (1, 0, 6395576350626777292729821677181541606370191430555605995902296654660733787961884662675205008112728910627829097716240328518277343733654560980779031197383306195903192278996242667385893559502924064335660043910231897229406366701069814748813352528977494567341233293392314984276702732050363273792561347300313, 4989628161531004318153788074304291273577473031059606908412965124036974844963743869216684686020120111949770513589687750670438648526142795689802013040914101895565898055896213731473214310303864435287131739468789570598441615792162769805326802317670196010077382560220110366549259348962142078308153647899274) |
这是一道基于CSIDH的密钥交换,先简要介绍一下CSIDH与SIDH主要有哪些不同:
CSIDH一般工作在由p+1光滑的素数的一次域上
Alice与Bob的私钥是一个指数列表,用来指示在每个p+1的奇素因子上进行同源移动的次数
由于是一次域,所有奇素数都只对应一个唯一的torsion,因此每个度数的同源均只有一个
也就是对于一个确定的曲线来说,经过一个度数确定的同源,一定会到达另一条确定的曲线,这个目的地有且仅有一个。且如果按相同的度数一直同源下去最后会走出一个循环。
一般是用最后到达的曲线的Montgomery form的系数A作为共享密钥,不过题目中是j不变量,应该也行
而经过测试可以发现这里的CSIDH本身密钥交换的实现就有问题,在指数为负数的时候根本没有利用quadratic twisted来倒着走,所以他的整个作为私钥的指数列表其实是完全没有负数这个概念的,完全等价于01列表(-1就等价于1)。此外,由于给了初始曲线E0的生成元G,且给出了经历双方私钥交换的$\phi_A(G)$和$\phi_B(G)$,注意到刚才说过同样的torsion只有一个,所以经历了一个度为k的同源后,生成元G的阶中因子k也会随之消失,就破坏了他作为生成元的特点。
一个简单但不太严谨的解释是,由于k-torsion作为同源的核,也就是说k-torsion中的所有点会映射到O,因此生成元的因子k自然就消失了
因此简单的遍历一下G的阶中因子是否还存在就可以求出双方的私钥了,之后进行错误的密钥交换即可。
exp:
1 | from Crypto.Cipher import AES |
lcasm$
二进制的,默认自己不会。
notitle*
题目描述:
1 | The keys are obfuscated by a weird magic operation. |
题目:
1 | from sage.all import * |
output.txt:
1 | magic_pi = 5148814821900119542741261450055292586113647535732067369080655482691554380052565459741879836667166985122205831918390644340336597281539053251470086499523221365132775020379803159725553942273967210168653981106714132657280843578263021148705351143778776029557496571051812809658662726067976153186472043930315453925013490294642486555939775792002395538684028065710983702501767061099948677637628170785784723184512036672606688238070423752236657778483603721097906556034261993570775222774608063476541749544916702299880398045617340589746748928485972604335018907462971390470546547369413439887745742610507865846805659916187409855769246066 |
题目给了一个很奇怪的运算magic_op,为了方便表示就把他记为$f$,然后给出了以下几个奇怪的值:
然后又给了很多组:
其中k都是未知的,要求解出k才能解AES,此外h是某个未知的SHA512值。
做这个题的时候真是一点头脑也摸不到,因为magic_op看上去是个矩阵之类的运算,但是想上手写发现完全不会写,最后也没有一点进展。
赛后看maple的wp,才知道这个神奇的运算其实是某种群的运算,由于经测试,对于任意x,下列条件有且仅有一个成立:
也就是说这一定同构于一个阶为p-1或阶为p+1的子群,并且所有元素x一定在其中一个里。而分解一下p-1和p+1可以发现,p-1有一部分是光滑的,而p+1甚至可以完全分解。并且经过测试得到:
所以由于p+1的因子全部知道,因此对第二组数据在p+1下求dlp,如果有个512bit的h,那就是h本身了。
因为如果的确在p+1这个子群下,实际上求出来的是h % (p+1),也就是h本身
然而实操的时候发现,虽然p+1能完全分解掉,但是最后一个因子38738895416631107有接近60bit,不是很利于求dlp,所以maple的方法是分别对两组数据的光滑因子求pohlig-hellman,然后crt起来得到最终的h,以h的大小是否接近512bit来判定是不是正确。
这个部分是我这题最昏的地方,这群太神奇了,不知道为什么一定需要映射到二次扩域上才能dlp,我这里直接在一次的乘法群上去pohlig-hellman一直打不通。同时也不知道为啥还要分正负crt,先将就着用吧,之后再回头看
求出了h之后,那么我们现在等于拥有多个如下形式的值:
由群的知识可以知道,如果ki在阶为p-1的群中,那么hki当然也在,所以依然可以通过magic_op来判定某个元素在哪个群中,然后求h关于群阶的逆元就可以解密了。
但是有一个问题就是h求出来是个偶数,所以会有多解,难以确定到底哪个解才是真正的ki。但这个问题也很容易,由于我们知道每个ki中有且仅有一个是正确的,并且所有正确的ki的和是AES的key,仅仅只有128bit,所以其和很小,可以用noise_crt的类似做法来规约出这个很小的和以及真正的系数。
exp:
1 | from Crypto.Util.number import * |
后面看discord有看到maple提了这个群的名字:
然后还有个师傅提供了篇论文,以后再看看吧:
http://wayback.cecm.sfu.ca/CAG/papers/Cheb.pdf
pacap*
题目描述:
1 | The "capac" challenge from Crypto CTF 2024 can be directly solved by factorizing the modulus, but is it still solvable if the modulus is much larger? |
题目:
1 | #!/usr/bin/env sage |
心酸,自己明明还改过这题,这次没做出来,因为明文实在是太大了。
改过的那个初级版在:Capac’s revenge | NSSCTF
总的来说就是由于明文较小,所以可以利用曲线方程和已知点去构建等式,等式有小根所以可以造格或二元copper。一些技巧是:
直接造等式的话度会比较大,所以代换变量可以得到度仅为2的等式,利于copper
由于(0,0)是平凡解,所以需要自己找规约出来的一些向量,转化为多项式后观察他的形式,从而确定接下来的求解办法,具体直接看maple的解释吧:pacap
赛中一直没想到怎么处理好这个平凡解,当时想的是利用明文前缀来确定根,但这样的代价是度会增高到4,不利于copper了,上界就不太够。密码挑战赛过了太久,把自己手提多项式这一招都给忘记了