Hard 级别的密钥嵌入在密文结构本身。
Text 13
59656A6B6F9F656A67746767
首字节 0x59 (89) 为全局 key。后续每字节减 key 得 charset 位置。
def decode_text13(ct): """首字节为全局 key""" key = int(ct[:2], 16) data = [int(ct[i:i+2], 16) for i in range(2, len(ct), 2)] return "".join(C[b - key] for b in data)chim cheree
Text 14
6F5657A6606B7D9C7480649D7A6B757D9C70816B6CB4
前 3 字节 [0x6F, 0x56, 0x57] 为旋转 key。后续每字节依次减去对应 key。
def decode_text14(ct): """前 3 字节为旋转 key""" keys = [int(ct[i:i+2], 16) for i in range(0, 6, 2)] data = [int(ct[i:i+2], 16) for i in range(6, len(ct), 2)] return "".join(C[data[i] - keys[i % 3]] for i in range(len(data)))Take the blue pill!
Text 15
574168755997984F7A7E76AD6954A662538F764F7A5C4F876544
前 6 位 hex 是三个 2 位子密钥 (57, 41, 68)。子密钥交替加密后续字符(密钥 1 加密第 4/7/10…个字符)。。
第一层:静态替换表
每个字符硬编码一个唯一的偏移量,跟字符集索引无关:
a→0x27 b→0x0b c→0x41 d→0x45 e→0x0e ...A→0x1e B→0x13空格→0x12 句号→0x03这就是个查表替换,只不过替换结果不是另外一个字符,是一个数字。
第二层:类维吉尼亚加密
拿替换后的数字,加上循环密钥(57→41→68→57→…),得到最终密文:
A → 查表得 0x1e → +密钥 0x57 → 0x75l → 查表得 0x18 → +密钥 0x41 → 0x59i → 查表得 0x2f → +密钥 0x68 → 0x97c → 查表得 0x41 → +密钥 0x57 → 0x98...加密工具虽然每请求随机化(Hard 特性),但是同一个字符在同一个位置的加密结果每次都一样。所以:
- 加密 “aaaaaa” → 看密文的重复规律,发现每 3 个字节一个周期 → 密钥长度 3
- 加密 “aaaaaaaaaaaa” → 同一位置加密 “a” 多次 → 确认 “a” 的密文总是 0x7e(当密钥=0x57时)
- 加密 “ba”、“ca”、“da”… → 算出每个字符的偏移量
- 密钥值本身:从密文前 6 位直接读出来的(这就是为什么说密钥嵌在密文结构里)
CHAR_OFF = { 'a': 0x27, 'b': 0x0b, 'c': 0x41, 'd': 0x45, 'e': 0x0e, 'f': 0x10, 'g': 0x11, 'h': 0x05, 'i': 0x2f, 'j': 0x1c, 'k': 0x16, 'l': 0x18, 'm': 0x04, 'n': 0x35, 'o': 0x3e, 'p': 0x37, 'q': 0x1d, 'r': 0x1f, 's': 0x15, 't': 0x21, 'u': 0x1a, 'v': 0x23, 'w': 0x00, 'x': 0x0c, 'y': 0x3b, 'z': 0x30, '.': 0x03, ' ': 0x12, 'A': 0x1e, 'B': 0x13,}# 反转: 偏移 -> charOFF_CHAR = {v: k for k, v in CHAR_OFF.items()}
def decode_text15(ct): """前 6 hex 为 3 子密钥, data - key[i%3] 得偏移查表""" keys = [int(ct[i:i+2], 16) for i in range(0, 6, 2)] data = [int(ct[i:i+2], 16) for i in range(6, len(ct), 2)] plain = "" for i, d in enumerate(data): off = d - keys[i % 3] plain += OFF_CHAR.get(off, "?") return plainAlice and Bob are here.
Text 16
32632E3149844B82115794BA78AD87C36DA01148707080C65459255C2C6487B02851
每 4 位 hex 一组(2 位偏移 + 2 位编码字符)。。
编码:0=00, 1=01, ..., 9=09, a=0A, ..., z=23, A=24, ..., Z=3D, space=46, fullstop=40。
def decode_text16(ct): """4-hex 一组 (2偏移 + 2编码)""" pt = "" for i in range(0, len(ct), 4): off = int(ct[i:i+2], 16) enc = int(ct[i+2:i+4], 16) cp = enc - off pt += C[cp] if 0 <= cp < len(C) else "?" return ptN3XT CRYPT0 5TUFF
Text 17
5D2EAF346C9271B7489BBA3A52326752248C2255826771378D741E48205A
密文前半为密钥,后半为编码数据。。
def decode_text17(ct, reverse=False): """前半 key 后半数据, key - 数据""" half = len(ct) // 2 keys = [int(ct[i:i+2], 16) for i in range(0, half, 2)] data = [int(ct[i:i+2], 16) for i in range(half, len(ct), 2)] pt = "".join(C[keys[i] - data[i]] for i in range(len(data))) return pt[::-1] if reverse else ptbazinga he said
Text 18
35445FA0D18F47618981AE5D3A98A5138EAE2A303A5D688B6C4461703B902F308F5F125F7725
与 Text 17 相同算法,但明文在加密前被反转了。
def decode_text18(ct): """同 Text 17 但结果反转""" return decode_text17(ct, reverse=True)5TL1 9aKu p03z U2a5