1. 格式保留加密(FPE)概述
1.1 什么是FPE
先问一个实际问题:你加密了一个16位的信用卡号,结果拿到一串乱码,长度变了,还带特殊符号。数据库字段装不下,老系统直接报错。这种场景,你遇到过吗?
FPE(Format-Preserving Encryption)就是解决这个问题的。说白了,它是一种密文格式跟明文一模一样的加密方式。明文是16位数字,密文也是16位数字。明文是字母+数字,密文也是字母+数字。长度不变,字符集不变。
我记得刚开始接触这个概念时,第一反应是——这怎么可能?加密不就是把数据打乱成无规则的样子吗?后来才明白,FPE是在保持格式这个约束条件下做加密。它把明文空间(比如所有16位数字的集合)映射到同样大小的密文空间。映射本身是一一对应的,而且由密钥控制。
我个人的理解方式是:FPE = 加密算法 + 格式约束。加密部分保证安全,格式部分保证兼容。
1.2 为什么需要FPE
说实话,普通AES加密已经很安全了。那为什么还要搞一个FPE?原因其实很实际——改不动老系统。
我在项目中遇到过好几次这种情况:一个跑了十年的银行核心系统,数据库里存着几亿条信用卡号。安全合规要求必须加密存储。但你要是用AES一加密,字段长度变了,存储格式变了,所有关联系统的接口都得改。这个改造成本,你想想看,几千万都打不住。
FPE的价值就在这里:
- 不改表结构——字段长度、类型完全不变
- 不改应用代码——加密后的数据可以直接存入原有字段
- 不改接口协议——下游系统拿到的还是"看起来正常"的数据
- 满足合规——PCI DSS、GDPR等要求加密存储敏感数据
1.3 核心应用场景
FPE的应用场景,说白了就是"既要加密,又要保持业务兼容"的地方。我归纳了四个最常见的:
- 数据库字段加密——身份证号、手机号、银行卡号等结构化数据加密后直接存原字段
- 支付系统令牌化——支付卡号(PAN)加密后仍为16位数字,交易链路不需改造
- 数据脱敏——测试环境、报表系统中,敏感数据需要脱敏但保持格式真实
- 合规改造——等保、PCI DSS要求敏感数据加密存储,但业务系统不能停
我曾经帮一家支付公司做过一个项目。他们的数据库里有几千万条交易记录,卡号是主键的一部分。如果用普通加密,索引全废,查询性能直接归零。FPE上场后,卡号加密后格式不变,索引照用,业务无感。这个案例让我彻底认定了FPE在金融场景里的地位。
1.4 FPE与普通加密的区别
这一点很多初学者容易混淆。我直接用一张对比表来说清楚:
| 对比维度 | 普通加密(AES等) | FPE |
|---|---|---|
| 密文格式 | 二进制 / Hex / Base64,格式改变 | 与明文完全一致(长度 + 字符集) |
| 数据长度 | 通常变长(如AES输出16字节整数倍) | 与明文长度相同 |
| 字符集 | 任意二进制,无限制 | 限定为明文字符集(数字、字母等) |
| 安全性基础 | 基于分组密码(AES等) | 基于分组密码 + 格式保持构造(FF1/FF3) |
| 兼容性 | 低,需改造系统适配 | 高,直接替换原字段值 |
| 实现复杂度 | 低,标准库丰富 | 中,需实现特定算法(FF1/FF3) |
光说理论不够,我拿一段伪代码对比一下:
// === 普通 AES 加密 ===
明文: "1234567890123456" // 16位数字
AES加密后: 0xA3B1... // 16字节二进制
转Hex: "a3b1c2d3e4f5..." // 32位hex字符串
→ 格式变了,长度变了,存不进原字段 ❌
// === FPE 加密(FF1) ===
明文: "1234567890123456" // 16位数字
radix = 10 // 数字字符集
FF1加密后: "9876543210987654" // 仍是16位数字
→ 格式不变,长度不变,直接存 ✅
另外还有一个关键点:FPE算法本身是公开的。FF1和FF3都是NIST标准(SP 800-38G)。安全不靠算法保密,只靠密钥。这一点跟AES是一个道理。
嗯,这里要注意:FPE的"格式保持"是有代价的。它对明文长度有下限要求(FF1要求至少2个字符,FF3要求至少6个字符)。太短的数据没法用FPE。这个细节我们在后面的章节会展开讲。
1.5 本章小结:一张图看懂FPE知识体系
我把这一章的核心概念整理成一张结构图。你看完应该对FPE的定位、特性和应用有个整体印象了。