tryptodecrypt.com
Hard 级别的密钥嵌入在密文结构本身。
Text 13
59656A6B6F9F656A67746767
首字节 0x59 (89) 为全局 key。后续每字节减 key 得 charset 位置。
1 2 3 4 5 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。
1 2 3 4 5 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...个字符)。字符加密 =
子密钥 + 字符专用偏移量。
第一层:静态替换表
每个字符硬编码一个唯一的偏移量,跟字符集索引无关:
1 2 3 a→0x27 b→0x0b c→0x41 d→0x45 e→0x0e ... A→0x1e B→0x13 空格→0x12 句号→0x03
这就是个查表替换,只不过替换结果不是另外一个字符,是一个数字。
第二层:类维吉尼亚加密
拿替换后的数字,加上循环密钥(57→41→68→57→…),得到最终密文:
1 2 3 4 5 A → 查表得 0x1e → +密钥 0x57 → 0x75 l → 查表得 0x18 → +密钥 0x41 → 0x59 i → 查表得 0x2f → +密钥 0x68 → 0x97 c → 查表得 0x41 → +密钥 0x57 → 0x98 ...
加密工具虽然每请求随机化(Hard
特性),但是同一个字符在同一个位置的加密结果每次都一样。所以:
加密 "aaaaaa" → 看密文的重复规律,发现每 3 个字节一个周期 → 密钥长度
3
加密 "aaaaaaaaaaaa" → 同一位置加密 "a" 多次 → 确认 "a" 的密文总是
0x7e(当密钥=0x57时)
加密 "ba"、"ca"、"da"… → 算出每个字符的偏移量
密钥值本身:从密文前 6
位直接读出来的(这就是为什么说密钥嵌在密文结构里)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 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 , } OFF_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 plain
Alice 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。
1 2 3 4 5 6 7 8 9 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 pt
N3XT CRYPT0 5TUFF
Text 17
5D2EAF346C9271B7489BBA3A52326752248C2255826771378D741E48205A
密文前半为密钥,后半为编码数据。密钥 - 编码数据 = 字符集索引。
1 2 3 4 5 6 7 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 pt
bazinga he said
Text 18
35445FA0D18F47618981AE5D3A98A5138EAE2A303A5D688B6C4461703B902F308F5F125F7725
与 Text 17 相同算法,但明文在加密前被反转了。
1 2 3 def decode_text18 (ct ): """同 Text 17 但结果反转""" return decode_text17(ct, reverse=True )
5TL1 9aKu p03z U2a5