AI摘要
云影密码(01248)是一种利用0、1、2、4、8通过贪婪求和分解字母序号的古典替换密码。文章阐述了其原理、编码表、Python加解密实现及CTF实战技巧。
概述
云影密码(又称 01248 密码)是一种古典替换密码,它仅使用数字 0、1、2、4、8 来编码完整的 A-Z 字母表。
原理详解
编码逻辑
云影密码采用贪婪求和分解的方式:每个字母的序号 $n$ (1~26) 被拆分为 $\{1, 2, 4, 8\}$ 的允许重复的加权和,数字间用 0 分隔。
核心规则:
- 用
0分割不同字母对应的编码组 - 每组内的数字(1、2、4、8)可以重复出现
- 组内所有数字之和 = 字母在字母表中的序号
- 序号映射:1→A, 2→B, ..., 26→Z
密文: 8842101220480224404014224202480122
│ │ │ │ ...
▼ ▼ ▼ ▼
分割: 88421 122 8
↓ ↓ ↓
求和: 8+8+4+2+1=23 1+2+2=5 8=8
↓ ↓ ↓
字母: W E H完整编码表
| 字母 | 序号 | 分解 | 密文组 |
|---|---|---|---|
| A | 1 | 1 | 1 |
| B | 2 | 2 | 2 |
| C | 3 | 2+1 | 21 |
| D | 4 | 4 | 4 |
| E | 5 | 4+1 | 41 |
| F | 6 | 4+2 | 42 |
| G | 7 | 4+2+1 | 421 |
| H | 8 | 8 | 8 |
| I | 9 | 8+1 | 81 |
| J | 10 | 8+2 | 82 |
| K | 11 | 8+2+1 | 821 |
| L | 12 | 8+4 | 84 |
| M | 13 | 8+4+1 | 841 |
| N | 14 | 8+4+2 | 842 |
| O | 15 | 8+4+2+1 | 8421 |
| P | 16 | 8+8 | 88 |
| Q | 17 | 8+8+1 | 881 |
| R | 18 | 8+8+2 | 882 |
| S | 19 | 8+8+2+1 | 8821 |
| T | 20 | 8+8+4 | 884 |
| U | 21 | 8+8+4+1 | 8841 |
| V | 22 | 8+8+4+2 | 8842 |
| W | 23 | 8+8+4+2+1 | 88421 |
| X | 24 | 8+8+8 | 888 |
| Y | 25 | 8+8+8+1 | 8881 |
| Z | 26 | 8+8+8+2 | 8882 |
编码使用贪婪策略:从大到小依次从 $\{8, 4, 2, 1\}$ 中选取,可重复。同一序号可以有多种合法编码(如 16 =88也可写成4444或84211),上表采用的是"最少位数"贪婪编码。
Python 加解密实现
解密(密文 → 明文)
与原文思路一致,用 0 分割、逐组求和、chr(sum+64) 映射字母:
def decode_01248(cipher: str) -> str:
"""云影密码解密:密文 → 明文"""
groups = cipher.split('0')
result = []
for group in groups:
if not group:
continue
total = sum(int(d) for d in group)
result.append(chr(total + 64))
return ''.join(result)
# 示例
print(decode_01248('8842101220480224404014224202480122'))
# 输出: WELCOMETOCFF解密流程:
| 步骤 | 操作 | 示例 (884210...) |
|---|---|---|
| 1 | cipher.split('0') | ['88421', '122', '8', ...] |
| 2 | 逐组求和 | 23, 5, 8, ... |
| 3 | chr(sum+64) | 23→W, 5→E, 8→H, ... |
加密(明文 → 密文)
使用贪婪算法,从 $\{8, 4, 2, 1\}$ 中从大到小反复减去可用的最大值:
def encode_01248(plain: str) -> str:
"""云影密码加密:明文 → 密文(贪婪策略)"""
weights = [8, 4, 2, 1] # 从大到小,贪婪选取
code = []
for ch in plain.upper():
if not 'A' <= ch <= 'Z':
raise ValueError(f'无效字符: {ch}')
n = ord(ch) - ord('A') + 1 # 序号 1~26
group = ''
for w in weights:
while n >= w: # 关键:允许重复!
group += str(w)
n -= w
code.append(group)
return '0'.join(code)
# 示例
print(encode_01248('HELLO'))
# 输出: 801404801248
print(encode_01248('WXYZ'))
# 输出: 884210888108881088820加密流程(以 Z=26 为例):
| 轮次 | 当前 n | 权重 8 | 剩余 n |
|---|---|---|---|
| 1 | 26 | while 26>=8 → "8", n=18 | |
| 2 | 18 | while 18>=8 → "88", n=10 | |
| 3 | 10 | while 10>=8 → "888", n=2 | |
| 4 | 2 | 8 > 2 跳过 → 4 > 2 跳过 → while 2>=2 → "8882", n=0 | |
| 5 | 0 | 结束,密文组 =8882 |
命令行工具
import sys
if __name__ == '__main__':
if len(sys.argv) < 3:
print('用法: python yunying.py decode|encode <data>')
sys.exit(1)
mode, data = sys.argv[1], sys.argv[2]
if mode == 'decode':
print(decode_01248(data))
elif mode == 'encode':
print(encode_01248(data))编码同值歧义
由于允许重复,同一字母存在多种合法编码。以下均解码为同一个字母:
| 字母 | 序号 | 编码方式 A(8 优先) | 编码方式 B | 编码方式 C |
|---|---|---|---|---|
| C | 3 | 21 (2+1) | 111 (1+1+1) | 12 (1+2) |
| P | 16 | 88 (8+8) | 4444 (4+4+4+4) | 84211 (8+4+2+1+1) |
| Z | 26 | 8882 (8+8+8+2) | 88442 (8+8+4+4+2) | 88811 (8+8+8+1+1) |
与其他古典密码对比
| 密码 | 编码空间 | 核心机制 | 常见场景 |
|---|---|---|---|
| 云影密码 (01248) | A~Z | 1/2/4/8 允许重复求和 | CTF Crypto 入门 |
| 培根密码 (Bacon) | A~Z | 5-bit 二进制映射 | 隐写、历史密码 |
| 栅栏密码 (Rail Fence) | 不限 | 字符位置重排 | 简单置换 |
| 凯撒密码 (Caesar) | A~Z | 固定偏移替换 | 最经典替换密码 |
| 维吉尼亚密码 (Vigenère) | A~Z | 多表替换 | 进阶古典密码 |
| 棋盘密码 (Polybius) | A~Z | 5×5 矩阵坐标 | 坐标替换 |
CTF 实战技巧
识别特征
密文仅由数字 0、1、2、4、8 组成,且 0 频繁出现作为分隔符:
8842101220480224404014224202480122
↑ 仅含 0 1 2 4 8混淆变体
| 变体 | 示例 | 解密要点 |
|---|---|---|
| 标准 | 884210122048 | 直接split('0') |
| 多 0 分隔 | 8842100012200048 | 过滤空串或压缩连续 0 |
| 数字乱序 | 488210221048 | 不受影响(求和与顺序无关) |
| 套娃编码 | Base64 → 云影 → Hex | 需逐层解码 |
套娃解密示例
import base64
# 混合编码的密文(先 Base64,再云影)
raw = base64.b64decode('某某Base64字符串').decode()
flag = decode_01248(raw)
print(flag) # 得到最终 Flag

