古典密码合集

Atbash/培根/栅栏/仿射

408 次访问

古典密码合集 · 8 种

原文
密文

关于本工具

了解工具定位 · 使用场景 · 对比优势

使用场景

🔐

谜题设计辅助

剧本杀作者或密室设计师需要为玩家设计一道多层密码谜题,比如第一层是培根密码(二进制转字母),第二层是栅栏密码(重新排列字母顺序)。本工具提供四种古典密码的加密与解密功能,作者可以快速测试谜题的可解性,确保难度适中且逻辑自洽,避免出现无解或歧义的情况。

📜

古籍手稿破译

历史爱好者研究古籍手稿时,遇到一段疑似经过简单替换加密的文本。例如,一份 19 世纪的日记中反复出现特定符号,怀疑是 Atbash 密码(字母表反转替换)。使用本工具的 Atbash 解密功能,可以直接粘贴符号对应的字母序列,一键还原为明文,快速验证猜测,无需手动对照字母表。

🎓

密码学作业验证

大学信息安全或数学系的学生在完成密码学作业时,需要手动计算仿射密码的加密与解密过程(涉及模逆元计算)。本工具内置仿射密码算法,输入密钥 a 和 b,即可获得加解密结果。学生可以用它来验证自己的手工推导是否正确,快速定位计算错误,提高作业效率。

🧩

小说密码线索构思

推理小说作家在构思情节时,需要设计一个符合逻辑的密码线索,例如:角色收到的纸条上是一串数字,需要先按栅栏密码的栏数拆分,再通过培根密码映射为字母。本工具支持多算法组合测试,作者可以快速迭代不同密钥和算法顺序,找到最符合故事设定且不出现漏洞的加密方案。

🕹️

游戏关卡谜题生成

独立游戏开发者制作解谜游戏时,需要为关卡设计一种简单的加密交互:玩家在游戏中收集到一串字符,需要在游戏外或游戏内置工具中解密才能获得下一关的提示。本工具提供四种古典密码的即时加解密,开发者可以快速生成谜题答案,并测试不同密钥长度对游戏难度的影响。

对比矩阵本工具 vs 竞品 vs 传统方法

维度本工具竞品 A (Cryptii)传统方法
数据隐私纯浏览器,零上传上传到服务器依赖工作人员接触明文
处理速度1 秒内2-5 秒(含网络延迟)数分钟至数小时(手动计算)
离线可用完全离线需联网无需设备,但需纸笔
支持算法Atbash/培根/栅栏/仿射支持 20+ 种密码(含 AES/RSA)仅限人类可手算的古典密码
大小限制无限制(受浏览器内存限制)单次输入上限约 1MB受限于手算能力,通常仅几个单词
收费免费免费(有高级版)免费(需自备纸笔)
操作复杂度输入即出,一键切换算法需选择算法、配置参数需记忆算法规则,手动逐字转换

使用指南

上手步骤 · 输入输出 · 避坑提示

输入输出示例8 个典型场景,覆盖常规、边界与易错

输入输出说明
HELLO WORLDSVOOL DLIOW典型场景:Atbash 加密英文短句
AZ边界 case:单字符输入,对称映射
HELLOAABBB ABABA AABBB AABBB AABBB典型场景:培根密码(标准版)加密单词
AABABC边界 case:培根密码解码,5 位二进制对应单个字母
HELLO WORLDHLOOL ELWRD典型场景:栅栏密码(栏数=2)加密
HELLO WORLDHWEOLRLLOD易错 case:栏数=3 时,用户常误以为栏数=2 的结果
HELLOHKNNS典型场景:仿射密码(a=5, b=8)加密
HKNNSHELLO易错 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 互质,否则无法解密。非字母字符(空格、标点、数字)保持原样不加密。

原理图

输入明文选择算法浏览器内计算输出密文字母 / 数字 / 符号Atbash / 培根 / 栅栏 / 仿射纯前端 JS 执行加密结果输入密文选择算法浏览器内计算输出明文字母 / 数字 / 符号Atbash / 培根 / 栅栏 / 仿射纯前端 JS 执行解密结果
用户输入 本地处理 输出结果

开发者集成

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))  # rcllo
package 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 个高频疑问

栅栏密码的栏数怎么确定?我试了几个数字都不对。
栅栏密码的栏数是加密时把原文按行写入的列数,解密时栏数必须等于加密时用的栏数,否则解出来是乱码。常见栏数有 2、3、5、7,但具体取决于加密人设定——如果对方没告知栏数,只能逐个尝试 2 到原文长度一半的整数,看哪个结果有可读英文单词。本工具提供栏数输入框,可以快速试不同栏数,每次结果会实时显示,不必手动重算。
培根密码的 A/B 和 0/1 两种模式有什么区别?
培根密码本质是用 5 位二进制(A/B)代表一个字母,但不同版本对 A 和 B 的映射不同。经典版(培根原版)用 A=aaaaa、B=aaaab 等 24 个组合,跳过 I/J 和 U/V 的区分;现代版常用 0/1 表示,且包含全部 26 个字母(把 I/J、U/V 分开)。本工具支持在「经典 24 字母」和「现代 26 字母」模式间切换,如果解密结果出现奇怪字母,试试切换模式。
Atbash 密码解密出来的结果全是乱码怎么办?
Atbash 只对英文字母生效(A↔Z、B↔Y……),数字、标点、空格、中文等非字母字符会原样保留不转换。如果结果全是乱码,检查原文是否包含大量非英文字母——比如中文或数字。另外 Atbash 是对称加密,加密和解密操作完全一样:输入密文再点一次「加密」就是解密。如果输入的是中文,工具不会报错但也不会转换,需要先用其他工具把中文转成拼音或英文。
仿射密码的 a 和 b 参数怎么填?填错了会怎样?
仿射密码公式是 E(x) = (a*x + b) mod 26,其中 a 必须与 26 互质(即 gcd(a,26)=1),否则解密时找不到逆元,结果会丢失信息。合法 a 值:1、3、5、7、9、11、15、17、19、21、23、25(共 12 个)。b 可以是 0-25 任意整数。如果填了不合法的 a(如 2 或 4),工具会提示「a 与 26 不互质」并拒绝执行,不会输出乱码结果。建议先用默认值 a=5、b=8 测试,再自行调整。
同一个明文用仿射和 Atbash 加密结果一样吗?
完全不一样。Atbash 是固定映射(A→Z、B→Y……),不依赖密钥,加密结果唯一;仿射密码需要 a 和 b 两个参数,结果随参数变化。举个例子:明文「HELLO」用 Atbash 加密得「SVOOL」,用仿射(a=5,b=8)加密得「ZEBBW」。两者数学原理不同:Atbash 是仿射密码在 a=25、b=25 的特例,但实际使用中参数不同结果天差地别。如果两个工具加密结果相同,说明 a 和 b 恰好等于 25 和 25。
我手上有密文但不知道是哪种古典密码,怎么判断?
本工具一次只能处理一种算法,但可以通过特征初步判断:① 如果密文只包含 A 和 B 两个字母(或 0 和 1),且长度是 5 的倍数,大概率是培根密码;② 如果密文是字母反转(如 A→Z、B→Y),试试 Atbash 一键解密;③ 如果密文按行排列、栏数可调,可能是栅栏密码;④ 如果密文字母频率与英文大致相同但顺序打乱,可能是仿射密码(单表替换)。建议先用 Atbash 快速试一下,因为对称加密只需点一次按钮就知道是否匹配。
工具能加密中文吗?我试了输入中文没反应。
本工具所有算法(Atbash、培根、栅栏、仿射)都只处理英文字母(A-Z、a-z),中文、数字、标点、空格等字符会原样保留,不做任何转换。例如输入「你好 HELLO」,输出只会对 HELLO 部分加密,中文「你好」不变。如果需要加密中文,建议先用拼音或 Unicode 编码(如 你好)转为英文字符串,再使用本工具。
工具会记录我输入的加密内容吗?在线用安全吗?
所有加密和解密操作完全在浏览器本地执行,不向任何服务器发送数据。可以在浏览器开发者工具(F12 → Network 选项卡)中确认:输入文字后点击按钮,没有任何网络请求产生。关闭页面后所有输入数据立即从内存清除。如果需要更高安全性,可以下载页面源码离线使用(本工具是纯前端实现,无需后端支持)。
选择 打开 +新窗口 esc关闭