trytodecrypt.com — middle (7-12)

tryptodecrypt.com

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

Text 7

21052F151200271512413E35101A152F3511

固定 2-hex 替换表(步长 2)。

same script as easy level

1
2
3
❯ python decrypt_cipher.py 7 2
密文: 21052F151200271512413E35101A152F3511
******************
this was confusing

Text 8

eaidagdagenpmgodlceijmgoefodlceijcnllonmgodlcfilfgamgodnnflgfgafilmgofildihdagmgoefodlccnlcnledddagmgoedddagfobdagedd

3 字符一组的替换密码。

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
47
48
49
50
51
52
53
54
#!/usr/bin/env python3
import re
import subprocess
import sys

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


def encrypt(text_id, text, cookie=""):
cmd = ["curl", "-s"]
if cookie:
cmd += ["-b", cookie]
cmd += [
f"https://www.trytodecrypt.com/decrypt.php?id={text_id}",
"-d",
f"text={text}&encrypt=Encrypt",
]
r = subprocess.run(cmd, capture_output=True, text=True, timeout=10)
# m = re.findall(r"panel-body[^>]>([0-9a-fA-F]+)</div>", r.stdout)
m = re.findall(r"panel-body[^>]*>([0-9a-zA-Z]+)</div>", r.stdout)
return m[1] if len(m) >= 2 else None


def build_mapping(text_id, step, cookie=""):
mapping = {}
for i in range(0, len(C), 20): # 每次 20 字符,多数服务端限制 50
batch = C[i : i + 20]
enc = encrypt(text_id, batch, cookie)
if enc:
for j, ch in enumerate(batch):
mapping[enc[j * step : (j + 1) * step]] = ch
return mapping


def decode(ct, step, mapping):
return "".join(mapping.get(ct[i : i + step], "?") for i in range(0, len(ct), step))


if __name__ == "__main__":
if len(sys.argv) < 3:
print(f"用法: {sys.argv[0]} <text_id> <step>")
sys.exit(1)

text_id = int(sys.argv[1])
step = int(sys.argv[2])

ct = sys.stdin.read().strip() if not sys.stdin.isatty() else input("密文: ").strip()

mapping = build_mapping(text_id, step)
if not mapping:
print("ERROR: 映射表为空,检查 text_id / step / 网络连接")
sys.exit(1)

print(decode(ct, step, mapping))
1
2
3
❯ python decrypt_cipher_alpha.py 8 3
密文: eaidagdagenpmgodlceijmgoefodlceijcnllonmgodlcfilfgamgodnnflgfgafilmgofildihdagmgoefodlccnlcnledddagmgoedddagfobdagedd
***************************************
keep in mind: its just the middle level

Text 9

6224F12C1C3FAA5AA54836B3C446D6415E74

反转输入后,每字符映射到固定 3-hex 码。解码时反向操作。

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
47
48
49
50
51
52
53
54
55
#!/usr/bin/env python3
import re
import subprocess
import sys

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


def encrypt(text_id, text, cookie=""):
cmd = ["curl", "-s"]
if cookie:
cmd += ["-b", cookie]
cmd += [
f"https://www.trytodecrypt.com/decrypt.php?id={text_id}",
"-d",
f"text={text}&encrypt=Encrypt",
]
r = subprocess.run(cmd, capture_output=True, text=True, timeout=10)
m = re.findall(r"panel-body[^>]*>([0-9a-zA-Z]+)</div>", r.stdout)
return m[1] if len(m) >= 2 else None


def build_mapping(text_id, step, cookie=""):
mapping = {}
# 或者把加密块大小改成 1
for i in range(0, len(C), 20): # 每次 20 字符,多数服务端限制 50
batch = C[i : i + 20]
enc = encrypt(text_id, batch, cookie)
if enc:
for j, ch in enumerate(batch):
# mapping[enc[j * step : (j + 1) * step]] = ch
mapping[enc[-(j + 1) * step : len(enc) - j * step]] = ch
return mapping


def decode(ct, step, mapping):
return "".join(mapping.get(ct[i : i + step], "?") for i in range(0, len(ct), step))


if __name__ == "__main__":
if len(sys.argv) < 3:
print(f"用法: {sys.argv[0]} <text_id> <step>")
sys.exit(1)

text_id = int(sys.argv[1])
step = int(sys.argv[2])

ct = sys.stdin.read().strip() if not sys.stdin.isatty() else input("密文: ").strip()

mapping = build_mapping(text_id, step)
if not mapping:
print("ERROR: 映射表为空,检查 text_id / step / 网络连接")
sys.exit(1)

print(decode(ct, step, mapping))
1
2
3
echo "6224F12C1C3FAA5AA54836B3C446D6415E74" | python trytodecrypt_cipher_reverse.py 9 3 | rev

************
fireball 123

Text 10

261129152E152B

7 -> 9 单表替换 每个字符固定映射到一个密文块,不依赖位置

10 -> 12 多表替换 映射关系随位置变化(Vigenère 风格)

步长 2,偏移量 [16, 17, 18] 循环。enc = charset_pos + offset[pos % 3]

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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
#!/usr/bin/env python3
"""trytodecrypt CPA solver — 基于网站加密工具建映射表解码

三种模式:
simple 固定映射(Text 1-8)
reverse 先反转再加密(Text 9)
vigenere 逐位置映射(Text 10-12)
derive 自动推导公式,少量请求解码(Text 10-12 推荐)

用法:
python trytodecrypt_solve.py <text_id> [options]
echo '密文' | python trytodecrypt_solve.py <text_id> [options]

选项:
-s, --step 步长(默认 auto)
-r, --reverse 反转模式(Text 9)
-v, --vigenere Vigenere 模式(逐位置建表,请求多)
-d, --derive 推导模式(少量请求算公式,Text 10-12 推荐)
-c, --cookie PHPSESSID
-q, --quiet 静默模式
"""

import argparse
import re
import subprocess
import sys
import time

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


def eprint(*args, **kwargs):
print(*args, file=sys.stderr, **kwargs)


def encrypt(text_id, text, cookie="", retry=3):
for attempt in range(retry):
cmd = ["curl", "-s", "--max-time", "15", "--retry", "2"]
if cookie:
cmd += ["-b", cookie]
cmd += [
f"https://www.trytodecrypt.com/decrypt.php?id={text_id}",
"-d", f"text={text}&encrypt=Encrypt",
]
try:
r = subprocess.run(cmd, capture_output=True, text=True, timeout=20)
m = re.findall(r"panel-body[^>]*>([0-9a-zA-Z]+)</div>", r.stdout)
if len(m) >= 2:
return m[1]
except subprocess.TimeoutExpired:
pass
if attempt < retry - 1:
time.sleep(1)
return None


def detect_step(text_id, cookie=""):
for step in [2, 3, 4]:
enc = encrypt(text_id, "0" * 10, cookie)
if enc and len(enc) == step * 10:
return step
enc = encrypt(text_id, "0", cookie)
if enc:
return len(enc)
return 2


def build_mapping_simple(text_id, step, cookie="", batch=20, reverse=False):
mapping = {}
for i in range(0, len(C), batch):
plain = C[i:i + batch]
enc = encrypt(text_id, plain, cookie)
if not enc:
continue
groups = [enc[j * step:(j + 1) * step] for j in range(len(plain))]
if reverse:
groups.reverse()
for j, ch in enumerate(plain):
mapping[groups[j]] = ch
return mapping


def build_mapping_vigenere(text_id, step, ct_len, cookie="", quiet=False):
mapping = [{} for _ in range(ct_len)]
total = ct_len * len(C)
done = 0
t0 = time.time()
for pos in range(ct_len):
prefix = "0" * pos
for ch in C:
plain = prefix + ch
enc = encrypt(text_id, plain, cookie)
if enc:
key = enc[pos * step:(pos + 1) * step]
mapping[pos][key] = ch
done += 1
if not quiet and done % 50 == 0:
elapsed = time.time() - t0
eprint(f" [{done}/{total}] {done/total*100:.0f}% eta {elapsed/done*(total-done):.0f}s")
if not quiet:
eprint(f" [{total}/{total}] 100% ({time.time()-t0:.0f}s)")
return mapping


def derive_vigenere(text_id, step, ct_len, cookie=""):
"""推导公式模式:少量请求算出 key,直接解码"""
# 加密 "0"*n 获取每个位置的基值
enc_zeros = encrypt(text_id, "0" * ct_len, cookie)
if not enc_zeros:
return None
bases = [int(enc_zeros[p * step:(p + 1) * step], 16) for p in range(ct_len)]

# 加密 "1"*n 获取梯子
enc_ones = encrypt(text_id, "1" * ct_len, cookie)
if enc_ones:
steps = [int(enc_ones[p * step:(p + 1) * step], 16) - bases[p] for p in range(ct_len)]
else:
steps = [0] * ct_len

return bases, steps


def decode_with_key(ct, step, bases, steps):
"""用推导出的 key 解码"""
pt = ""
for i in range(len(ct) // step):
val = int(ct[i * step:(i + 1) * step], 16)
# enc = base + cp * step
if steps[i] != 0:
cp = round((val - bases[i]) / steps[i])
else:
cp = val - bases[i]
if 0 <= cp < len(C):
pt += C[cp]
else:
pt += "?"
return pt


def decode_simple(ct, step, mapping):
return "".join(mapping.get(ct[i:i + step], "?") for i in range(0, len(ct), step))


def decode_vigenere(ct, step, mapping):
return "".join(
mapping[i].get(ct[i * step:(i + 1) * step], "?")
for i in range(len(mapping))
)


def main():
ap = argparse.ArgumentParser(description="trytodecrypt CPA solver")
ap.add_argument("text_id", type=int, help="题目 ID")
ap.add_argument("-s", "--step", type=int, default=0, help="步长(默认 auto)")
ap.add_argument("-r", "--reverse", action="store_true", help="反转模式(Text 9)")
ap.add_argument("-v", "--vigenere", action="store_true", help="Vigenere 模式(逐位置建表)")
ap.add_argument("-d", "--derive", action="store_true", help="推导模式(少量请求算公式)")
ap.add_argument("-c", "--cookie", default="", help="PHPSESSID")
ap.add_argument("-q", "--quiet", action="store_true", help="静默模式")
ap.add_argument("--batch", type=int, default=20, help="每批字符数(默认 20,simple 专用)")
args = ap.parse_args()

ct = sys.stdin.read().strip() if not sys.stdin.isatty() else input("密文: ").strip()
if not ct:
eprint("ERROR: 未提供密文")
sys.exit(1)

step = args.step or detect_step(args.text_id, args.cookie)
if not args.quiet:
eprint(f"[*] 步长: {step}")

if args.derive:
ct_len = len(ct) // step
if not args.quiet:
eprint(f"[*] 推导模式: {ct_len} 个位置")
result = derive_vigenere(args.text_id, step, ct_len, args.cookie)
if result is None:
eprint("ERROR: 推导失败")
sys.exit(1)
bases, steps = result
if not args.quiet:
eprint(f"[*] bases: {bases}")
eprint(f"[*] steps: {steps}")
print(decode_with_key(ct, step, bases, steps))

elif args.vigenere:
ct_len = len(ct) // step
if not args.quiet:
eprint(f"[*] Vigenere: {ct_len} × {len(C)} = {ct_len * len(C)} 次请求")
mapping = build_mapping_vigenere(args.text_id, step, ct_len, args.cookie, args.quiet)
if not mapping[0]:
eprint("ERROR: 映射表为空")
sys.exit(1)
print(decode_vigenere(ct, step, mapping))

else:
mode = "reverse" if args.reverse else "simple"
if not args.quiet:
eprint(f"[*] 模式: {mode}")
mapping = build_mapping_simple(args.text_id, step, args.cookie, args.batch, args.reverse)
if not mapping:
eprint("ERROR: 映射表为空")
sys.exit(1)
print(decode_simple(ct, step, mapping))


if __name__ == "__main__":
main()
1
2
3
4
5
6
7
❯ python trytodecrypt_solve.py -v 10 -c "8rubc5nmtqala9gvdj8t7cigqn" -s 2 -d
密文: 261129152E152B
[*] 步长: 2
[*] 推导模式: 7 个位置
[*] bases: [16, 17, 18, 16, 17, 18, 16]
[*] steps: [1, 1, 1, 1, 1, 1, 1]
*******
m0n5t3r

Text 11

3785824AD56B2531A7150DF44C21434A61E63F040A42F2012BC2F43F0AD535D24D46013213866D7E0

步长 3 hex,6 位循环。基值 [168, 282, 567, 57, 245, 180],乘数 [12, 47, 21, 19, 35, 9]

密文值 = 基值[位置] + 字符位置 × 倍率[位置]

same as Text 10

1
2
3
4
5
6
7
❯ python trytodecrypt_solve.py -v 11 -c "8rubc5nmtqala9gvdj8t7cigqn" -s 3 -d
密文: 3785824AD56B2531A7150DF44C21434A61E63F040A42F2012BC2F43F0AD535D24D46013213866D7E0
[*] 步长: 3
[*] 推导模式: 27 个位置
[*] bases: [168, 282, 567, 57, 245, 180, 168, 282, 567, 57, 245, 180, 168, 282, 567, 57, 245, 180, 168, 282, 567, 57, 245, 180, 168, 282, 567]
[*] steps: [12, 47, 21, 19, 35, 9, 12, 47, 21, 19, 35, 9, 12, 47, 21, 19, 35, 9, 12, 47, 21, 19, 35, 9, 12, 47, 21]
***************************
You are very good. Respect!

Text 12

00D02703603C0450461340870A50B50EA10A0BD133

基值为三角数 T(pos+1) = (pos+1)(pos+2)/2,步长 (pos+2)/2。

1
2
3
4
C = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_.,;:?! "
ct = "00D02703603C0450461340870A50B50EA10A0BD133"
vals = [int(ct[i*3:(i+1)*3], 16) for i in range(14)]
print("".join(C[round((v - (i+1)*(i+2)//2) / ((i+2)/2))] for i, v in enumerate(vals)))
cookie monster