原理
什么是隐写术
隐写术(Steganography)不同于密码学(Cryptography)。密码学把信息变成密文,让攻击者读不懂;隐写术则把信息藏进普通载体,让攻击者根本看不出"有信息存在"。前者隐藏内容,后者隐藏存在本身。
历史上最早的隐写记录来自古希腊:希罗多德在《历史》中记载,Histaieus 将奴隶的头发剃光,在头皮上刺字,待头发长出后派他传递密信。近代隐写则使用隐形墨水、微缩胶片等手段。数字时代,隐写术借助多媒体文件(图片、音频、视频、文本)的二进制冗余或结构特性隐藏信息。
StegoWeb 涉及两类核心技术:零宽字符隐写(用于文字载体)和文件追加隐写(用于图片载体)。
零宽字符
零宽字符(Zero-Width Character)是 Unicode 标准中一类宽度为零、不可见的控制字符。它们原本用于排版控制(如阻止连字、标记字节顺序),但因其不可见特性,天然适合隐写。
StegoWeb 使用以下四个:
U+FEFF(BOM / ZWNBSP):字节顺序标记,此处作为四进制 0 与结束标记。
U+200B(ZWSP):零宽空格,作为四进制 1。
U+200C(ZWNJ):零宽不连字,作为四进制 2。
U+200D(ZWJ):零宽连字,作为四进制 3。
这四个字符在渲染时不占任何视觉宽度,读者看到的是原始文字,但实际上字符流中已经插入了隐藏数据。
零宽字符位置可视化
文字编码
每个零宽字符可表示 4 种状态(0/1/2/3),即一位四进制位。n 位四进制可表示 4ⁿ 种组合。相比二进制(每位 2 种),四进制用更少的字符数表示相同信息量,编码更紧凑。
文字隐写使用 8 位四进制编码:4⁸ = 65536,足以覆盖 Unicode 基本平面(BMP,0x0000–0xFFFF)。每个字符被映射为一组 8 位四进制码,共 8 个零宽字符。
这里以汉字"中"为例:
文字编码转换
文字藏文字
载体:一段普通可见文字。
编码:根据 mapping.json 将每个隐藏字符映射为 8 位四进制码,转换为 8 个零宽字符,插入到载体字符之间。
可选"和移位"模式:将零宽码插入到对应载体字符之前(默认是之后)。
和移位对比
解码:扫描整段文字,提取所有零宽字符,按 8 位一组还原为隐藏文本。两种模式均可自动识别,无需告知解码端。
图片编码基础
图片隐写依赖 Base64 将二进制数据转为 ASCII 字符。Base64 将每 3 字节(24 位)分为 4 组,每组 6 位,映射到 A-Z、a-z、0-9、+、/ 共 64 个字符。不足 3 字节时用 = 填充。
Base64 分组原理(3 字节 → 4 字符)
映射表 base64_mapping.json 记录了 64 个 Base64 字符到 6 位二进制的对应关系。图片隐写使用 6 位二进制编码(2⁶ = 64),另外两个零宽字符代表"="和结束标记,涵盖了 Base64 字符集的字符。编码时将每个 Base64 字符转为 6 个零宽字符。
图片编码转换
文字藏图片
载体:一段普通可见文字。
编码:先将图片转为 Base64 字符串,再根据 base64_mapping.json 将每个 Base64 字符映射为 6 位零宽码,追加到载体文字末尾。
解码:提取所有零宽字符,按 6 位一组还原为 Base64 字符串,再解码为图片二进制数据。
IEND 与 EOI 标记
PNG 文件由一系列 Chunk(数据块)组成,每个 Chunk 包含长度、类型、数据、CRC 四部分。文件以 8 字节签名开头,以 IEND Chunk 结尾。
PNG 文件结构
IEND Chunk 固定字节序列为 00 00 00 00 49 45 4E 44 AE 42 60 82(12 字节)。图像解码器遇到此标记即停止解析。
JPG 文件由一系列 Marker(标记段)组成,以 EOI(End Of Image)标记结尾,固定字节序列为 FF D9(2 字节)。
JPG 文件结构
这两个标记之后追加的任意数据都不会被图像解码器读取,因此成为天然的隐写载荷容器。
图片藏文字
载体:PNG 或 JPG 图片。
编码:将隐藏文字按 mapping.json 编码为零宽码(8 位四进制),追加到图片文件二进制末尾。
解码:读取图片二进制末尾的零宽字符序列,按 8 位一组还原为隐藏文字。
PNG 的 IEND 标记和 JPG 的 EOI 标记之后的数据不影响图片正常显示,浏览器解析时自动忽略。
图片藏图片
载体:PNG 或 JPG 图片。
编码:将隐藏图片转为 Base64 字符串,再按 base64_mapping.json 编码为 6 位四进制零宽码,追加到载体图片二进制末尾。
解码:提取末尾零宽字符,按 6 位一组还原 Base64,再解码为隐藏图片。
图片藏万物
载体:PNG 或 JPG 图片。
编码:将任意文件的原始二进制字节直接追加到载体图片的 IEND(PNG 结束标记)或 EOI(JPG 结束标记)之后。浏览器读取图片时会停在结束标记处,追加的数据不影响显示。
单文件:保留原扩展名(例如 .docx、.pdf),仅做二进制追加。
多文件:使用 JSZip 打包为 ZIP,扩展名暴力改为 .stegofile。二进制内容不变,仅扩展名伪装。解码时若检测到 .stegofile 后缀则还原为 .zip 并解压展示树状文件列表。
为区分隐藏文件的扩展名,追加数据采用自定义封装格式:
万物隐藏载荷封装格式
解码:扫描图片二进制,定位 IEND/EOI 标记位置,读取其后的全部数据即为隐藏文件。
ZIP 打包与扩展名伪装
多文件场景使用 JSZip 库在浏览器端生成 ZIP 文件。ZIP 是一种无损压缩归档格式,内部以中央目录(Central Directory)记录文件列表,可包含多个文件与目录层级。
多文件打包与伪装流程
.stegofile 扩展名仅用于标识"此文件原本是 ZIP",不改变文件二进制内容。这种做法称为文件签名伪装(File Signature Camouflage),让外部观察者难以直接判断真实文件类型。解码时检测到 .stegofile 后缀即还原为 .zip 并解压。
自动识别解码
当解码模式为"自动识别"时,系统按以下顺序尝试多种解码路径:
1. 文字路径:提取零宽字符,按 6 位一组尝试还原 Base64,校验是否为合法 PNG/JPG 签名。若签名合法,按图片解码;否则按文字解码。
2. 图片路径:定位 IEND/EOI 标记,读取其后数据。先尝试零宽字符解码,失败则按万物隐藏处理。
3. 若上述均失败,提示"未发现隐藏内容"。
签名校验通过检查文件开头的固定字节判断数据类型:
文件签名校验
隐写分析
隐写分析(Steganalysis)是隐写术的对抗技术,旨在检测载体中是否含有隐藏信息。常见检测手段包括:
统计分析:对比载体与自然文件的统计特征(如零宽字符出现频率、文件大小异常),偏离正常分布则可疑。
签名扫描:搜索已知的隐写工具特征码或固定标记(如 IEND 后的异常数据)。
结构检查:验证文件格式是否符合规范,如 PNG 在 IEND 后不应有额外数据。
StegoWeb 的隐写方式并非不可检测。零宽字符可通过正则表达式扫描发现;图片追加数据可通过文件大小与 IEND/EOI 位置对比发现。因此本工具不适合用于对抗专业检测的场景。
安全性说明
隐写术本身不提供加密。隐藏内容虽不可见,但任何提取到零宽字符或读取图片二进制末尾的人都可还原明文。如需保密,应先加密再隐藏(例如使用 AES 加密后再进行隐写)。
零宽字符在某些平台(如部分论坛、富文本编辑器)会被过滤;图片二进制追加在经过有损压缩或在线图片服务重编码后会丢失。请根据使用场景选择合适的载体。
载体图片仅支持 PNG 与 JPG,因为其他格式(如 WebP、GIF)的压缩重编码可能破坏追加的隐藏数据。PNG 为无损格式,JPG 的追加数据在 EOI 之后不受重编码影响。