古典密码合集
Atbash/培根/栅栏/仿射
关于本工具
了解工具定位 · 使用场景 · 对比优势
使用场景
谜题设计辅助
剧本杀作者或密室设计师需要为玩家设计一道多层密码谜题,比如第一层是培根密码(二进制转字母),第二层是栅栏密码(重新排列字母顺序)。本工具提供四种古典密码的加密与解密功能,作者可以快速测试谜题的可解性,确保难度适中且逻辑自洽,避免出现无解或歧义的情况。
古籍手稿破译
历史爱好者研究古籍手稿时,遇到一段疑似经过简单替换加密的文本。例如,一份 19 世纪的日记中反复出现特定符号,怀疑是 Atbash 密码(字母表反转替换)。使用本工具的 Atbash 解密功能,可以直接粘贴符号对应的字母序列,一键还原为明文,快速验证猜测,无需手动对照字母表。
密码学作业验证
大学信息安全或数学系的学生在完成密码学作业时,需要手动计算仿射密码的加密与解密过程(涉及模逆元计算)。本工具内置仿射密码算法,输入密钥 a 和 b,即可获得加解密结果。学生可以用它来验证自己的手工推导是否正确,快速定位计算错误,提高作业效率。
小说密码线索构思
推理小说作家在构思情节时,需要设计一个符合逻辑的密码线索,例如:角色收到的纸条上是一串数字,需要先按栅栏密码的栏数拆分,再通过培根密码映射为字母。本工具支持多算法组合测试,作者可以快速迭代不同密钥和算法顺序,找到最符合故事设定且不出现漏洞的加密方案。
游戏关卡谜题生成
独立游戏开发者制作解谜游戏时,需要为关卡设计一种简单的加密交互:玩家在游戏中收集到一串字符,需要在游戏外或游戏内置工具中解密才能获得下一关的提示。本工具提供四种古典密码的即时加解密,开发者可以快速生成谜题答案,并测试不同密钥长度对游戏难度的影响。
对比矩阵本工具 vs 竞品 vs 传统方法
| 维度 | 本工具 | 竞品 A (Cryptii) | 传统方法 |
|---|---|---|---|
| 数据隐私 | 纯浏览器,零上传 | 上传到服务器 | 依赖工作人员接触明文 |
| 处理速度 | 1 秒内 | 2-5 秒(含网络延迟) | 数分钟至数小时(手动计算) |
| 离线可用 | 完全离线 | 需联网 | 无需设备,但需纸笔 |
| 支持算法 | Atbash/培根/栅栏/仿射 | 支持 20+ 种密码(含 AES/RSA) | 仅限人类可手算的古典密码 |
| 大小限制 | 无限制(受浏览器内存限制) | 单次输入上限约 1MB | 受限于手算能力,通常仅几个单词 |
| 收费 | 免费 | 免费(有高级版) | 免费(需自备纸笔) |
| 操作复杂度 | 输入即出,一键切换算法 | 需选择算法、配置参数 | 需记忆算法规则,手动逐字转换 |
使用指南
上手步骤 · 输入输出 · 避坑提示
输入输出示例8 个典型场景,覆盖常规、边界与易错
| 输入 | 输出 | 说明 |
|---|---|---|
| HELLO WORLD | SVOOL DLIOW | 典型场景:Atbash 加密英文短句 |
| A | Z | 边界 case:单字符输入,对称映射 |
| HELLO | AABBB ABABA AABBB AABBB AABBB | 典型场景:培根密码(标准版)加密单词 |
| AABAB | C | 边界 case:培根密码解码,5 位二进制对应单个字母 |
| HELLO WORLD | HLOOL ELWRD | 典型场景:栅栏密码(栏数=2)加密 |
| HELLO WORLD | HWEOLRLLOD | 易错 case:栏数=3 时,用户常误以为栏数=2 的结果 |
| HELLO | HKNNS | 典型场景:仿射密码(a=5, b=8)加密 |
| HKNNS | HELLO | 易错 case:仿射密码需 a 与 26 互质,否则不可逆 |
常见错误对照8 个常踩的坑 · 错误 → 修复
1. Atbash 只对英文字母有效,却输入数字或中文
Atbash('你好123') → 期望输出 '你好876'Atbash('Hello') → 'Svool';非字母字符原样保留,数字不会被反转Atbash 算法只映射 A↔Z, B↔Y, … 共26个字母;数字和中文不在映射表内,不会产生可读结果。
2. 培根密码用错字母表(AB vs 01)
输入 '01001' 作为培根编码,期望输出 'A'培根密码用 'A' 和 'B' 表示二进制位,如 'AAAAB' 对应 'A';需先将 '0/1' 手动替换为 'A/B'培根密码的原始定义使用 A/B 两组字母代表 0/1,直接输入数字串会被当作普通字符处理,不触发解码逻辑。
3. 栅栏密码栏数设为 1(等于没加密)
栅栏('HELLO', rails=1) → 输出 'HELLO'(用户以为加密了)栅栏('HELLO', rails=3) → 'HOELL';栏数至少为 2 才有置换效果栏数=1 时,所有字母排在同一行,输出与输入完全相同,无任何加密效果。
4. 仿射密码的 a 值与 26 不互质
仿射('A', a=4, b=5) → 输出 'E'(a=4 与 26 有公因子 2)仿射('A', a=3, b=5) → 输出 'F'(a=3 与 26 互质,解密可逆)仿射密码要求 gcd(a, 26)=1,否则加密是多对一映射,无法唯一解密。常见合法 a 值:1,3,5,7,9,11,15,17,19,21,23,25。
5. 培根密码输入长度不是 5 的倍数
输入 'ABABAAB'(7 位)期望解码为 2 个字母输入 'ABABAABAB'(10 位)可解码为 'AB' 两个字母培根密码每组 5 个字母对应一个明文字母;输入长度不能被 5 整除时,末尾多余字符会被忽略或导致解码失败。
6. 栅栏密码的栏数大于原文长度
栅栏('AB', rails=5) → 输出 'AB'(用户以为会变乱)栅栏('ABCDE', rails=5) → 'ABCDE'(每栏最多一个字母,无置换效果)当栏数 ≥ 原文长度时,每栏至多一个字母,Z 字形排列退化为逐行排列,输出与输入相同。
7. 仿射密码的 b 值超出 0-25 范围
仿射('A', a=1, b=30) → 期望输出 'E'(30 mod 26 = 4 才对)仿射('A', a=1, b=4) → 输出 'E';b 应取 0-25 之间的整数仿射密码的 b 参数是模 26 的位移量,b=30 等价于 b=4(30 mod 26),但工具通常要求输入 0-25,超范围会报错或自动取模导致预期不符。
8. Atbash 混淆大小写输出
Atbash('Hello') → 期望输出 'Svool'(全小写)Atbash('Hello') → 'Svool'(大小写保留:H→S, e→v, l→o, l→o, o→l)Atbash 保持原始大小写:大写字母映射为大写,小写映射为小写。若用户期望全大写或全小写,需自行转换。
工作原理
公式推导 · 流程图解 · 依据出处
核心公式
E(x) = (a*x + b) mod 26
变量说明
x— 明文字母对应的数字(A=0, B=1, …, Z=25)a— 密钥乘数,需与 26 互质(如 1,3,5,7,9,11,15,17,19,21,23,25)b— 密钥偏移量(0~25 的整数)E(x)— 密文字母对应的数字
示例
明文 'HELLO',取 a=5, b=8。H(7)→5×7+8=43 mod 26=17→R;E(4)→5×4+8=28 mod 26=2→C;L(11)→5×11+8=63 mod 26=11→L;L(11)→11→L;O(14)→5×14+8=78 mod 26=0→A。密文 'RCLLA'。
适用范围
仅适用于 26 个英文字母(A-Z),不区分大小写。密钥 a 必须与 26 互质,否则无法解密。非字母字符(空格、标点、数字)保持原样不加密。
原理图
开发者集成
3 种主流语言 · 复制即用
import string
# Atbash 密码:字母表反转映射
# 例:"abc" → "zyx"
def atbash(text: str) -> str:
trans = str.maketrans(
string.ascii_lowercase + string.ascii_uppercase,
string.ascii_lowercase[::-1] + string.ascii_uppercase[::-1]
)
return text.translate(trans)
print(atbash("hello")) # svool
print(atbash("svool")) # hello
# 栅栏密码(Rail Fence Cipher):按锯齿形排列后按行读取
# rails=3 时 "HELLO" → "HOELL"
def rail_fence_encrypt(text: str, rails: int) -> str:
fence = [[] for _ in range(rails)]
row, step = 0, 1
for ch in text:
fence[row].append(ch)
if row == 0:
step = 1
elif row == rails - 1:
step = -1
row += step
return ''.join(''.join(r) for r in fence)
print(rail_fence_encrypt("HELLO", 3)) # HOELL
# 仿射密码:加密公式 E(x) = (a*x + b) mod 26
# 要求 gcd(a, 26) == 1 才可逆
import math
def affine_encrypt(text: str, a: int, b: int) -> str:
if math.gcd(a, 26) != 1:
raise ValueError(f"a={a} 与 26 不互质,无法解密")
result = []
for ch in text:
if ch.isalpha():
base = ord('A') if ch.isupper() else ord('a')
x = ord(ch) - base
result.append(chr((a * x + b) % 26 + base))
else:
result.append(ch)
return ''.join(result)
print(affine_encrypt("hello", 5, 8)) # rcllopackage main
import (
"fmt"
"math"
"strings"
"unicode"
)
// Atbash 密码:字母表反转
func atbash(s string) string {
var b strings.Builder
for _, r := range s {
switch {
case 'a' <= r && r <= 'z':
b.WriteRune('z' - (r - 'a'))
case 'A' <= r && r <= 'Z':
b.WriteRune('Z' - (r - 'A'))
default:
b.WriteRune(r)
}
}
return b.String()
}
// 培根密码:A/B 二进制表示,5 位一组
// 例:"a" → "AAAAA"
func baconEncode(text string) string {
bacon := []string{
"AAAAA", "AAAAB", "AAABA", "AAABB", "AABAA",
"AABAB", "AABBA", "AABBB", "ABAAA", "ABAAB",
"ABABA", "ABABB", "ABBAA", "ABBAB", "ABBBA",
"ABBBB", "BAAAA", "BAAAB", "BAABA", "BAABB",
"BABAA", "BABAB", "BABBA", "BABBB", "BBAAA", "BBAAB",
}
var out strings.Builder
for _, r := range strings.ToUpper(text) {
if 'A' <= r && r <= 'Z' {
out.WriteString(bacon[r-'A'])
out.WriteByte(' ')
}
}
return strings.TrimSpace(out.String())
}
// 仿射加密:E(x) = (a*x + b) mod 26
func affineEncrypt(text string, a, b int) (string, error) {
if math.GCD(a, 26) != 1 {
return "", fmt.Errorf("a=%d 与 26 不互质", a)
}
var out strings.Builder
for _, r := range text {
if unicode.IsLetter(r) {
base := 'A'
if unicode.IsLower(r) {
base = 'a'
}
x := int(r - base)
out.WriteRune(rune((a*x+b)%26 + base))
} else {
out.WriteRune(r)
}
}
return out.String(), nil
}
func main() {
fmt.Println(atbash("hello")) // svool
fmt.Println(baconEncode("a")) // AAAAA
res, _ := affineEncrypt("hello", 5, 8)
fmt.Println(res) // rcllo
}// Atbash 密码:字母表反转
// 例:"abc" → "zyx"
function atbash(text) {
const a = 'a'.charCodeAt(0), z = 'z'.charCodeAt(0);
const A = 'A'.charCodeAt(0), Z = 'Z'.charCodeAt(0);
return text.replace(/[a-zA-Z]/g, ch => {
const code = ch.charCodeAt(0);
if (code >= a && code <= z)
return String.fromCharCode(z - (code - a));
return String.fromCharCode(Z - (code - A));
});
}
console.log(atbash('hello')); // svool
// 栅栏密码(Rail Fence Cipher)
// rails=3 时 "HELLO" → "HOELL"
function railFenceEncrypt(text, rails) {
const fence = Array.from({ length: rails }, () => []);
let row = 0, step = 1;
for (const ch of text) {
fence[row].push(ch);
if (row === 0) step = 1;
else if (row === rails - 1) step = -1;
row += step;
}
return fence.flat().join('');
}
console.log(railFenceEncrypt('HELLO', 3)); // HOELL
// 仿射密码:E(x) = (a*x + b) mod 26
// 要求 gcd(a, 26) === 1
function gcd(a, b) {
while (b) { [a, b] = [b, a % b]; }
return a;
}
function affineEncrypt(text, a, b) {
if (gcd(a, 26) !== 1)
throw new Error(`a=${a} 与 26 不互质`);
return text.replace(/[a-zA-Z]/g, ch => {
const base = ch >= 'a' ? 97 : 65;
const x = ch.charCodeAt(0) - base;
return String.fromCharCode(((a * x + b) % 26) + base);
});
}
console.log(affineEncrypt('hello', 5, 8)); // rcllo常见问题
8 个高频疑问