from Crypto.Cipher import AES from hashlib import ...

创建于:2025年8月15日

使用 GPT-5 Thinking 回答 Chat01

问题

from Crypto.Cipher import AES
from hashlib import md5
from params import vecs
from os import urandom

key = int("".join([vecs[int.from_bytes(urandom(2)) & 0xfff] for _ in range(50)]), 2)

print("🎁 :", [[nonce := int(urandom(50*2).hex(), 16), (bin(nonce & key).count("1")) % 2] for _ in range(600)])
print("🚩 :", AES.new(key=md5(str(key).encode()).digest(), nonce=b"Tiffany", mode=AES.MODE_CTR).encrypt(open("flag.txt", "rb").read()))
帮我解决这个问题

思考

Interpreting Python code

I think the user is sharing a code snippet that generates a key from a "vecs" list, using random sampling to extract 50 bits (or more?) based on certain conditions. These bits, probably from a binary string, are then interpreted as a binary number. The code also seems to print samples related to the parity of the key.

Clarifying linear algebra approach

The user's task seems related to learning parity with noise, but without the noise element. The parity of a bitwise AND is comparable to the dot product of bit vectors modulo 2. With 600 samples, more than enough for the key's bit length, linear algebra over GF(2) is possible. The key and nonce are different in size, modifying the parity calculation.

Reconstructing the key

I'm interpreting this: the key's full bitstring length is based on vecs elements, which might each be 12-bit vectors (based on the 0xfff mask). After selecting 50 of them, we can form a bitstring, which may be 1200 bits if each vec is 24 bits. To solve the challenge, the goal is to reconstruct the key using linear algebra or brute force.

Formulating key recovery

The user’s approach involves 600 samples of (nonce, parity), where each nonce is 100 bytes (800 bits). Using the parity of the AND operation with the key, we get linear equations. The challenge is solving for the key bits, but we don't know the key's exact bit length, so that becomes a variable to determine.

Key Recovery Approach

The user is trying to solve for a key using equations derived from parity of bitwise AND between nonce (100 bytes) and key. The solution involves using Gaussian elimination over GF(2) on 600 samples of nonce-parity pairs. The key length is 50 bits so only the lower bits are important, and the AES key is derived from the MD5 of this 50-bit vector.

Providing Solution Steps

The main task is to reconstruct the 50-bit key using Gaussian elimination mod 2 on a matrix built from 600 nonce-parity pairs. I’ll prepare a Python solver that parses the '🎁' and '🚩' printouts, performs the necessary matrix operations, and extracts the key. The code will handle input parsing, Gaussian elimination, and AES decryption using the reconstructed key.

Creating Solution Script

I'll write a Python script that parses the "🎁" and "🚩" data, performs Gaussian elimination on the nonce and parity pairs, and decrypts the ciphertext using the reconstructed key. The user can then run it locally without needing clarifications. I'll provide the necessary code, packaging it as a downloadable script.

Thought for 1m 36s

回答

这是个经典的“线性代数/奇偶点积”型密码题。你拿到了 600 组样本
(nonce, parity),其中 parity = popcount(nonce & key) mod 2。这等价于把未知密钥 key 的各位看成 GF(2)(模2)上的未知数,样本给出了 600 条线性方程。密钥是 50 位(二进制拼接 50 个 vecs[...] 的结果),所以只要把每个 nonce 的低 50 位展开成一行,和 parity 作为右端项,就能用高斯消元在 GF(2) 上直接解出整份密钥。拿到 key(整数)后,按题面做 md5(str(key).encode()) 得到 AES 密钥,再用 AES-CTR(nonce=b"Tiffany") 解密即可。

我已经把完整的可直接跑的解题脚本给你准备好了(包含:解析打印输出 → GF(2) 高斯消元求 50 位密钥 → 复现 AES-CTR 解密):

下载 solve_parity_aes_ctr.py

使用方法(一步到位)

  1. 跑你给的原题脚本,把两行输出(以 🎁 :🚩 : 开头)复制保存到一个文件,比如 dump.txt
  2. 本地装一下依赖:
bash
pip install pycryptodome
  1. 运行解题脚本:
bash
python solve_parity_aes_ctr.py dump.txt # 如果密钥位数不是 50,可在第二个参数指定位数,比如: # python solve_parity_aes_ctr.py dump.txt 50

脚本会:

  • 🎁 : [[nonce, parity], ...] 中解析出 600 组样本;
  • 取每个 nonce 的低 50 位构造矩阵 A,在 GF(2) 上做完全消元(RREF),直接读出每一位密钥;
  • 还原 key(整数),计算 md5(str(key)) 作为 AES key;
  • nonce=b"Tiffany" 做 AES-CTR 解出 🚩 对应明文,并打印出来。

原理要点(简述)

  • popcount(n & k) mod 2 就是向量点积 ⟨n, k⟩ 在 GF(2) 上的结果;
  • 600 条方程 >> 50 个未知,通常满秩,直接唯一解;
  • nonce 是 100 字节(800 位),但与 50 位密钥相与后只有低 50 位起作用;
  • 复原的 key 用十进制字符串喂给 MD5,这一点注意别写错(不是二进制串也不是 big-endian bytes)。

如果你把 dump.txt 准备好了,按上面三步跑脚本就能直接把 flag 打出来。需要我帮你检查结果或把两行输出贴过来一起跑也行。

分享这个问答