跳转至

培根密码

培根密码(Baconian Cipher)是由弗朗西斯·培根(Francis Bacon)在1605年发明的一种隐写术加密方法。它将每个字母用5位二进制编码表示,然后通过两种不同的字体、大小写或其他二元区分方式来隐藏信息。

核心特点: - 基于二进制编码思想(A/B 或 0/1) - 每个字母固定使用5位编码 - 属于隐写术范畴,可以隐藏在正常文本中 - CTF中常见的古典密码类型


历史背景

发明者

  • 弗朗西斯·培根(Francis Bacon, 1561-1626)
  • 英国哲学家、政治家、科学家
  • 现代科学方法的奠基人之一

发明时间

  • 1605年,首次出现在培根的著作《De Augmentis Scientiarum》中

历史意义

  • 是最早的二进制编码系统之一
  • 为现代计算机二进制编码奠定了理论基础
  • 在密码学史上具有重要地位

加密原理

培根密码的核心思想是将26个英文字母映射到5位二进制编码,每一位可以用两种状态表示:

二元对立的表示方式

  • A/B 编码:用字母 A 和 B 表示
  • 0/1 编码:用数字 0 和 1 表示
  • 大小写:用大写和小写字母区分
  • 字体样式:用粗体/正常体、斜体/正常体等区分
  • 其他方式:颜色、字号、符号等

编码位数

  • 固定使用 5位二进制 编码
  • 2^5 = 32,足够表示26个字母

编码表

标准培根密码编码表(24字母版本)

在原始培根密码中,I和J共用一个编码,U和V共用一个编码:

字母 编码 字母 编码 字母 编码
A AAAAA J/I ABAAA S BAAAB
B AAAAB K ABAAB T BAABA
C AAABA L ABABA U/V BAABB
D AAABB M ABBAA W BABAA
E AABAA N ABBAB X BABAB
F AABAB O ABBBA Y BABBA
G AABBA P ABBBB Z BABBB
H AABBB Q BAAAA
I/J ABAAA R BAAAB

现代培根密码编码表(26字母完整版本)

现代版本为每个字母分配独立编码:

字母 编码 字母 编码 字母 编码
A AAAAA J ABAAA S BAABA
B AAAAB K ABAAB T BAABB
C AAABA L ABABA U BABAA
D AAABB M ABBAA V BABAB
E AABAA N ABBAB W BABBA
F AABAB O ABBBA X BABBB
G AABBA P ABBBB Y BBAAA
H AABBB Q BAAAA Z BBAAB
I ABAAA R BAAAB

使用0/1表示的编码表

字母 编码 字母 编码 字母 编码
A 00000 J 01000 S 10010
B 00001 K 01001 T 10011
C 00010 L 01010 U 10100
D 00011 M 01100 V 10101
E 00100 N 01101 W 10110
F 00101 O 01110 X 10111
G 00110 P 01111 Y 11000
H 00111 Q 10000 Z 11001
I 01000 R 10001

加密过程

步骤1:明文转换为培根编码

将明文中的每个字母转换为对应的5位培根编码。

示例: 明文 "HELLO"

H → AABBB
E → AABAA
L → ABABA
L → ABABA
O → ABBBA

完整编码:AABBB AABAA ABABA ABABA ABBBA(25位)

步骤2:选择载体文本

选择一段至少有25个字母的载体文本(carrier text)。

示例载体: "Bring me the golden apple from the tree"

步骤3:应用二元区分

根据培根编码,将载体文本的字母进行区分标记: - A → 小写字母 - B → 大写字母

密文编码:A A B B B  A A B A A  A B A B A  A B A B A  A B B B A
载体文本:B r i n g  m e t h e  g o l d e  n a p p l  e f r o m
处理结果:b r I N G  m e T H e  g O l D e  n A p P l  e F R O m

最终密文

brING meTHe gOlDe nApPl eFROm

或者不分组:brING meTHe gOlDe nApPl eFROm the tree


解密过程

步骤1:提取二元信息

从密文中提取大小写模式: - 小写字母 → A(或0) - 大写字母 → B(或1)

示例: brING meTHe gOlDe nApPl eFROm

b r I N G  m e T H e  g O l D e  n A p P l  e F R O m
A A B B B  A A B A A  A B A B A  A B A B A  A B B B A

步骤2:分组为5位

将提取的二进制序列按5位一组分割:

AABBB | AABAA | ABABA | ABABA | ABBBA

步骤3:查表解码

根据培根编码表将每组转换为对应字母:

AABBB → H
AABAA → E
ABABA → L
ABABA → L
ABBBA → O

最终明文

HELLO

CTF中的常见形式

1. 大小写混合文本

特征: 看似正常的英文文本,但大小写混乱

示例:

ThE qUicK BRown FoX JUMps oVeR thE LAZY DOg

2. 粗体/斜体混合

特征: 正常字体和粗体(或斜体)混合

示例:

The **qui**ck **bro**wn fox **jum**ps over the lazy dog

3. 字体颜色区分

特征: 两种不同颜色的字母

示例:

<span style="color:red">T</span><span style="color:blue">he</span>...

4. 0/1或A/B序列

特征: 直接给出二进制序列

示例:

00111 00100 01010 01010 01110

5. 图片隐写

特征: 文字以图片形式给出,通过颜色、字体等区分

6. 其他二元对立形式

  • 全角/半角字符
  • 不同符号(如●/○,★/☆)
  • 空格的有无
  • 特殊Unicode字符

识别特征

如何判断是培根密码?

1. 文本特征

  • 大小写混乱但有规律
  • 文本长度是5的倍数(或接近)
  • 只有26个字母,无其他字符
  • 存在明显的二元对立特征

2. 编码特征

  • 只包含两种元素(如A/B、0/1)
  • 总长度能被5整除
  • 每5位一组可能对应有意义的字母

3. 题目提示

  • 题目名称包含"bacon"、"培根"
  • 题目描述提到"大小写"、"字体"
  • 题目文件为图片,文字有明显样式差异

常见混淆

与摩斯电码的区别: - 摩斯:每个字母长度不固定(1-4个符号) - 培根:每个字母固定5位

与二进制编码的区别: - 二进制:通常每字符8位(ASCII) - 培根:每字符固定5位


解密工具与方法

在线工具

  1. CyberChef
  2. URL: https://gchq.github.io/CyberChef/
  3. 操作:选择 "Bacon Cipher Decode"
  4. 支持自定义A/B字符

  5. dCode

  6. URL: https://www.dcode.fr/bacon-cipher
  7. 支持多种变体
  8. 可自动识别编码方式

  9. Rumkin Cipher Tools

  10. URL: http://rumkin.com/tools/cipher/baconian.php
  11. 简单易用

Python脚本解密

# 标准培根密码编码表(26字母版本)
bacon_dict = {
    'AAAAA': 'A', 'AAAAB': 'B', 'AAABA': 'C', 'AAABB': 'D', 'AABAA': 'E',
    'AABAB': 'F', 'AABBA': 'G', 'AABBB': 'H', 'ABAAA': 'I', 'ABAAB': 'J',
    'ABABA': 'K', 'ABABB': 'L', 'ABBAA': 'M', 'ABBAB': 'N', 'ABBBA': 'O',
    'ABBBB': 'P', 'BAAAA': 'Q', 'BAAAB': 'R', 'BAABA': 'S', 'BAABB': 'T',
    'BABAA': 'U', 'BABAB': 'V', 'BABBA': 'W', 'BABBB': 'X', 'BBAAA': 'Y',
    'BBAAB': 'Z'
}

def bacon_decode(ciphertext, char_a='a', char_b='A'):
    """
    解密培根密码
    :param ciphertext: 密文
    :param char_a: 代表A的字符类型(默认小写)
    :param char_b: 代表B的字符类型(默认大写)
    :return: 明文
    """
    # 提取二进制序列
    binary = ''
    for char in ciphertext:
        if char.isalpha():
            if char.islower():
                binary += 'A'
            else:
                binary += 'B'

    # 分组解码
    plaintext = ''
    for i in range(0, len(binary), 5):
        group = binary[i:i+5]
        if len(group) == 5:
            plaintext += bacon_dict.get(group, '?')

    return plaintext

# 使用示例
cipher = "brING meTHe gOlDe nApPl eFROm"
plain = bacon_decode(cipher)
print(f"明文: {plain}")  # 输出: HELLO

更通用的Python解密脚本

def bacon_decode_advanced(text, reverse=False):
    """
    高级培根密码解密,支持多种模式
    :param text: 输入文本
    :param reverse: 是否反转A/B映射
    :return: 可能的明文列表
    """
    # 标准编码表
    bacon_standard = {
        'AAAAA': 'A', 'AAAAB': 'B', 'AAABA': 'C', 'AAABB': 'D', 'AABAA': 'E',
        'AABAB': 'F', 'AABBA': 'G', 'AABBB': 'H', 'ABAAA': 'I', 'ABAAB': 'J',
        'ABABA': 'K', 'ABABB': 'L', 'ABBAA': 'M', 'ABBAB': 'N', 'ABBBA': 'O',
        'ABBBB': 'P', 'BAAAA': 'Q', 'BAAAB': 'R', 'BAABA': 'S', 'BAABB': 'T',
        'BABAA': 'U', 'BABAB': 'V', 'BABBA': 'W', 'BABBB': 'X', 'BBAAA': 'Y',
        'BBAAB': 'Z'
    }

    # 24字母版本(I/J共用,U/V共用)
    bacon_24 = {
        'AAAAA': 'A', 'AAAAB': 'B', 'AAABA': 'C', 'AAABB': 'D', 'AABAA': 'E',
        'AABAB': 'F', 'AABBA': 'G', 'AABBB': 'H', 'ABAAA': 'I/J', 'ABAAB': 'K',
        'ABABA': 'L', 'ABABB': 'M', 'ABBAA': 'N', 'ABBAB': 'O', 'ABBBA': 'P',
        'ABBBB': 'Q', 'BAAAA': 'R', 'BAAAB': 'S', 'BAABA': 'T', 'BAABB': 'U/V',
        'BABAA': 'W', 'BABAB': 'X', 'BABBA': 'Y', 'BABBB': 'Z'
    }

    results = []

    # 尝试不同的A/B映射方式
    mappings = [
        ('lower', 'upper'),  # 小写→A, 大写→B
        ('upper', 'lower'),  # 大写→A, 小写→B
    ]

    for a_type, b_type in mappings:
        binary = ''
        for char in text:
            if char.isalpha():
                if (a_type == 'lower' and char.islower()) or \
                   (a_type == 'upper' and char.isupper()):
                    binary += 'A'
                else:
                    binary += 'B'

        # 使用26字母表解码
        plaintext = ''
        for i in range(0, len(binary), 5):
            group = binary[i:i+5]
            if len(group) == 5:
                plaintext += bacon_standard.get(group, '?')

        if '?' not in plaintext:
            results.append(f"映射{a_type}→A: {plaintext}")

    return results

# 使用示例
cipher = "brING meTHe gOlDe nApPl eFROm"
results = bacon_decode_advanced(cipher)
for result in results:
    print(result)

命令行工具

# 使用 Python 单行命令
echo "brING meTHe gOlDe nApPl eFROm" | python3 -c "
import sys
d={'AAAAA':'A','AAAAB':'B','AAABA':'C','AAABB':'D','AABAA':'E','AABAB':'F','AABBA':'G','AABBB':'H','ABAAA':'I','ABAAB':'J','ABABA':'K','ABABB':'L','ABBAA':'M','ABBAB':'N','ABBBA':'O','ABBBB':'P','BAAAA':'Q','BAAAB':'R','BAABA':'S','BAABB':'T','BABAA':'U','BABAB':'V','BABBA':'W','BABBB':'X','BBAAA':'Y','BBAAB':'Z'}
s=''.join('A' if c.islower() else 'B' for c in sys.stdin.read() if c.isalpha())
print(''.join(d.get(s[i:i+5],'?') for i in range(0,len(s),5)))
"

实战例题

例题1:基础大小写混合

题目:

Flag is hidden: sOmETimES thINGs aRe NoT wHat TheY sEEm

解题步骤:

  1. 识别密码类型:大小写混乱 → 培根密码
  2. 提取大小写模式:
    s O m E T i m E S  t h I N G s  a R e  N o T  w H a t  T h e Y  s E E m
    A B A B B A A B B  A A B B B A  A B A  B A B  A B A A  B A A B  A B B A
    
  3. 分组(5位):
    ABABB | AABBA | ABBBA | BAABA | BABAA | BAABA | ABBA
    
    注意:最后一组不足5位,舍去
  4. 查表解码:
    ABABB → L
    AABBA → G
    ABBBA → O
    BAABA → S
    BABAA → U
    BAABA → S
    
  5. 得到明文:LGOSUS (可能需要调整或提示有误)

实际情况: 需要尝试反向映射(大写→A,小写→B)

例题2:0/1序列

题目:

01000 00100 01010 01010 01110 00001 00000 00010 01110 01101

解题步骤:

  1. 识别:长度符合,每组5位 → 培根密码
  2. 将0→A,1→B转换:
    01000 → ABAAA → I
    00100 → AABAA → E
    01010 → ABABA → K
    01010 → ABABA → K
    01110 → ABBBA → O
    00001 → AAAAB → B
    00000 → AAAAA → A
    00010 → AAABA → C
    01110 → ABBBA → O
    01101 → ABBAB → N
    

例题3:真实CTF题目示例

题目名称: "Bacon's Secret"

题目文件: message.txt

THE qUIck BRowN fox JUMPs OVER the LAZy DOG. THis SENTence CONtains A SEcret MESSage.

解题过程:

text = "THE qUIck BRowN fox JUMPs OVER the LAZy DOG. THis SENTence CONtains A SEcret MESSage."

# 提取大小写(只保留字母)
binary = ''.join('B' if c.isupper() else 'A' for c in text if c.isalpha())
print(f"二进制序列: {binary}")
# 输出: BBBAABAABBAAABABABAABBBAAABAAAAAABBBAABAABBBBBB...

# 分组
groups = [binary[i:i+5] for i in range(0, len(binary), 5)]
print(f"分组: {groups}")

# 解码
bacon_dict = {...}  # 完整编码表
plaintext = ''.join(bacon_dict.get(g, '?') for g in groups)
print(f"明文: {plaintext}")

变种与扩展

1. 反向培根密码

  • 大写字母 → A
  • 小写字母 → B

解密时需要注意尝试两种映射方式

2. 多层加密

培根密码 + Base64 + ROT13等组合

示例:

明文 → 培根加密 → Base64编码 → 最终密文

3. 自定义编码表

某些CTF题目会修改标准编码表,需要根据题目提示或尝试破解。

4. 使用特殊字符

  • 用●/○代替A/B
  • 用不同表情符号
  • 用全角/半角字符

示例:

●●●●● ●●●●○ ●●●○● ●●●○● ●○○○●

5. 培根栅栏密码组合

先培根加密,再栅栏密码加密,增加破解难度。

6. 培根隐写

将培根密码隐藏在图片的LSB(最低有效位)中。

Python完整工具脚本

#!/usr/bin/env python3
"""
培根密码完整工具集
支持加密、解密、多种变体
"""

class BaconCipher:
    # 26字母完整编码表
    BACON_26 = {
        'A': 'AAAAA', 'B': 'AAAAB', 'C': 'AAABA', 'D': 'AAABB', 'E': 'AABAA',
        'F': 'AABAB', 'G': 'AABBA', 'H': 'AABBB', 'I': 'ABAAA', 'J': 'ABAAB',
        'K': 'ABABA', 'L': 'ABABB', 'M': 'ABBAA', 'N': 'ABBAB', 'O': 'ABBBA',
        'P': 'ABBBB', 'Q': 'BAAAA', 'R': 'BAAAB', 'S': 'BAABA', 'T': 'BAABB',
        'U': 'BABAA', 'V': 'BABAB', 'W': 'BABBA', 'X': 'BABBB', 'Y': 'BBAAA',
        'Z': 'BBAAB'
    }

    # 反向字典(解密用)
    BACON_26_REV = {v: k for k, v in BACON_26.items()}

    @staticmethod
    def encode(plaintext, carrier="", use_case=True):
        """
        加密
        :param plaintext: 明文
        :param carrier: 载体文本(可选)
        :param use_case: 是否使用大小写区分(True=大小写,False=A/B)
        :return: 密文
        """
        plaintext = plaintext.upper().replace(' ', '')
        bacon_code = ''.join(BaconCipher.BACON_26.get(c, '') for c in plaintext)

        if not use_case:
            return bacon_code

        if not carrier:
            # 生成随机载体
            import random
            import string
            carrier = ''.join(random.choice(string.ascii_lowercase) 
                            for _ in range(len(bacon_code)))

        # 应用大小写
        result = []
        carrier_alpha = [c for c in carrier if c.isalpha()]

        for i, bit in enumerate(bacon_code):
            if i < len(carrier_alpha):
                char = carrier_alpha[i]
                result.append(char.upper() if bit == 'B' else char.lower())

        return ''.join(result)

    @staticmethod
    def decode(ciphertext, reverse=False):
        """
        解密
        :param ciphertext: 密文
        :param reverse: 是否反向映射(大写→A)
        :return: 明文
        """
        # 提取二进制
        binary = ''
        for char in ciphertext:
            if char.isalpha():
                if reverse:
                    binary += 'A' if char.isupper() else 'B'
                else:
                    binary += 'A' if char.islower() else 'B'
            elif char in 'AB':
                binary += char
            elif char in '01':
                binary += 'A' if char == '0' else 'B'

        # 解码
        plaintext = ''
        for i in range(0, len(binary), 5):
            group = binary[i:i+5]
            if len(group) == 5:
                plaintext += BaconCipher.BACON_26_REV.get(group, '?')

        return plaintext

    @staticmethod
    def auto_decode(ciphertext):
        """
        自动尝试多种解密方式
        :param ciphertext: 密文
        :return: 可能的明文列表
        """
        results = []

        # 尝试正向和反向
        for reverse in [False, True]:
            plaintext = BaconCipher.decode(ciphertext, reverse)
            if '?' not in plaintext:
                mode = "大写→B" if not reverse else "大写→A"
                results.append((mode, plaintext))

        return results

# 使用示例
if __name__ == "__main__":
    # 测试加密
    plain = "HELLO"
    cipher = BaconCipher.encode(plain, carrier="the quick brown fox jumps")
    print(f"明文: {plain}")
    print(f"密文: {cipher}")

    # 测试解密
    decoded = BaconCipher.decode(cipher)
    print(f"解密: {decoded}")

    # 自动解密
    test_cipher = "brING meTHe gOlDe nApPl eFROm"
    results = BaconCipher.auto_decode(test_cipher)
    print(f"\n自动解密结果:")
    for mode, text in results:
        print(f"  {mode}: {text}")