trytodecrypt.com — easy (1-6)

tryptodecrypt.com

字符集 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_.,;:?!(71 个字符)。

easy 都是简单替换密码。

网站提供加密工具,可用 chosen-plaintext 查询建立替换表。以下脚本保存为 script.py,要求每个字符对应固定宽度 hex token,且加密面板位于返回 HTML 的第二个匹配项;输出缺失、截断或冲突都会中止。站点请求与 Text 6 的完整替换表未复现,正文密文中的固定答案保留为题目记录。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
import subprocess
import re
import sys
from urllib.parse import urlencode

C = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_.,;:?! "

def encrypt(text_id, text, cookie=""):
cmd = ["curl", "--silent", "--show-error", "--fail", "--max-time", "10"]
if cookie:
cmd += ["-b", cookie]
# form 编码保留空格、+、& 与非 ASCII 文本的边界
cmd += [f"https://www.trytodecrypt.com/decrypt.php?id={text_id}",
"-d", urlencode({"text": text, "encrypt": "Encrypt"})]
result = subprocess.run(cmd, capture_output=True, text=True, timeout=12, check=True)
panels = re.findall(r"panel-body[^>]*>([0-9a-fA-F]+)</div>", result.stdout)
if len(panels) < 2:
raise ValueError("Encryption response does not contain two expected hex panels")
return panels[1].upper()

def build_mapping(text_id, step, cookie=""):
if step <= 0:
raise ValueError("step must be positive")
mapping = {}
for i in range(0, len(C), 20):
batch = C[i:i + 20]
enc = encrypt(text_id, batch, cookie)
if len(enc) != len(batch) * step:
raise ValueError("Truncated or variable-width oracle output")
for j, ch in enumerate(batch):
token = enc[j * step:(j + 1) * step]
if token in mapping and mapping[token] != ch:
raise ValueError("Substitution collision")
mapping[token] = ch
return mapping

def decode(ct, step, mapping):
ct = ct.strip().upper()
if step <= 0 or len(ct) % step or not re.fullmatch(r"[0-9A-F]*", ct):
raise ValueError("Invalid ciphertext width or hex syntax")
return "".join(mapping[ct[i:i + step]] for i in range(0, len(ct), step))

if __name__ == "__main__":
text_id, step = int(sys.argv[1]), int(sys.argv[2])
ct = sys.stdin.read() if not sys.stdin.isatty() else input("密文: ")
print(decode(ct, step, build_mapping(text_id, step)))

Text 1

131017171A48221A1D170F

偏移 2。

1
2
3
4
5
6
7
8
9
C = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_.,;:?! "
OFF = 2
def dec(s):
r = []
for i in range(0, len(s), 2):
r.append(C[int(s[i:i+2], 16) - OFF])
return "".join(r)

print(dec("131017171A48221A1D170F"))
hello world

Text 2

4A3E374A4973483F3D3E4A

偏移 45(charset 索引偏移);给定密文中空格 73 减 45 得到索引 70。

1
2
3
4
5
6
7
8
C = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_.,;:?! "
def dec(s, OFF=45):
r = []
for i in range(0, len(s), 2):
r.append(C[int(s[i:i+2], 16) - OFF])
return "".join(r)

print(dec("4A3E374A4973483F3D3E4A"))
thats right

Text 3

0A0B1339150B1139070A0B13390510

偏移 -13(58 mod 71)。解码时减去 -13,再对 71 取模。

1
2
3
4
5
6
7
8
C = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_.,;:?! "
def dec(s, OFF=-13):
r = []
for i in range(0, len(s), 2):
r.append(C[(int(s[i:i+2], 16) - OFF) % len(C)])
return "".join(r)

print(dec("0A0B1339150B1139070A0B13390510"))
now you know it

Text 4

0C02D8010D0C02D8010606D8101402FCD80F0603D8FC0600DA

\(\mathrm{enc} = (30 - \mathrm{charset\_pos}) \bmod 256\)

1
2
3
4
5
6
7
8
9
C = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_.,;:?! "
ct = "0C02D8010D0C02D8010606D8101402FCD80F0603D8FC0600DA"
plaintext = []
for value in bytes.fromhex(ct):
index = (30 - value) % 256
if not 0 <= index < len(C):
raise ValueError("Invalid charset index")
plaintext.append(C[index])
print("".join(plaintext))
is this too easy for you?

Text 5

90DE633F425148DE51546CDE725466DE3F2A6936DE4263CCDEAB362A3372DE39545DDE633F36DE51366F63DE545136D8

\(\mathrm{enc} = \mathrm{charset\_pos} \times 3 + 12\)

1
2
3
4
5
6
7
8
9
10
11
C = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_.,;:?! "
ct = "90DE633F425148DE51546CDE725466DE3F2A6936DE4263CCDEAB362A3372DE39545DDE633F36DE51366F63DE545136D8"
plaintext = []
for value in bytes.fromhex(ct):
if (value - 12) % 3:
raise ValueError("Ciphertext is outside the affine image")
index = (value - 12) // 3
if not 0 <= index < len(C):
raise ValueError("Invalid charset index")
plaintext.append(C[index])
print("".join(plaintext))
I think now you have it. Ready for the next one?

Text 6

4D586CFC2DB449D47B0CF99C3BC46CFC7B0C

固定 4-hex 替换表。

1
2
3
$ python script.py 6 4
密文: 4D586CFC2DB449D47B0CF99C3BC46CFC7B0C
*********
lucky guy