第2章 格式保留加密的核心思想
说实话,刚接触FPE时我也觉得它挺绕的——加密就加密,为什么还要“保留格式”?但等你真正把一个16位的信用卡号塞进AES,出来一串乱七八糟的二进制,再回头看看业务方的表情……你就懂了。格式保留加密,说白了就是:加密后的密文长得和明文一模一样——数字还是数字,字母还是字母,长度不变、字符集不变。这不是花哨,这是生产环境的硬需求。
2.1 为什么要死磕“格式不变”?
我参与过一个银行测试数据脱敏项目。生产库里有几千万条银行卡号,需要加密后放到测试环境。一开始用的标准AES,结果加密完的字段变成64位十六进制串,数据库字段装不下,应用端直接报错。业务方追着我喊:“这玩意儿我连导入都导不进去!”
你想想看,如果加密后的数据格式变了,那系统就要改表结构、改校验逻辑、改接口协议——成本翻倍,还容易出bug。FPE的核心价值就是:加密前后,数据的类型、长度、校验规则完全一致。可以直接替换原字段,应用层零改动。
举个最常用的场景:
- 信用卡号:16位数字,包含Luhn校验位。FPE加密后仍是16位数字,且校验位依然合法。
- 身份证号:18位,数字+字母X。加密后保持18位,字符集不变。
- 电话号码:11位数字。加密后还是11位数字。
嗯,这里要注意一个陷阱:格式保留 ≠ 长度不变。比如对于包含字母和数字的字段,FPE可以只保留字母部分大小写?不是的,FPE的“格式”是指整个明文字符集和长度都固定,不是你想保留哪部分就保留哪部分。我一同事在项目中试图只保留数字部分而改变字母部分——结果解密的时候彻底乱套。
2.2 和标准加密硬碰硬:一张表说清楚
为什么不能用AES直接干?咱们直接对比看看:
| 对比维度 | 标准加密(如AES) | 格式保留加密(FPE) |
|---|---|---|
| 输出长度 | 通常是固定块大小(16/32字节) | 与输入长度严格相等 |
| 输出字符集 | 二进制或十六进制串 | 与输入字符集一致(数字、字母等) |
| 数据类型适应性 | 只能处理二进制块 | 可适配任意有限字符集(数字、字母、ASCII) |
| 应用改造代价 | 需要修改字段定义、接口、校验逻辑 | 直接替换,零改动 |
| 典型场景 | 文件加密、通信加密 | 数据库字段脱敏、令牌化、格式敏感数据保护 |
我刚开始学习FPE时,老纠结一个问题:既然AES这么安全,为什么不能加密完再把二进制转成数字?但转念一想——你怎么保证转换后的数字长度刚好是16位?而且每次转换可能引入概率冲突,解密时还得逆向映射回来,这本质上就是FPE要做的事情,只不过FPE给出了一个数学上可证明的、一步到位的解法。
2.3 FPE的三大支柱:格式、可逆、安全
做工程的人最怕“三缺一”。FPE要落地,三个条件必须同时满足:
1. 格式保留 —— 密文与明文同长度、同字符集、同结构。
2. 可逆性 —— 解密可以完整还原出原始明文。
3. 安全性 —— 达到与底层分组密码(如AES)等效的安全强度。
格式:这是FPE的安身立命之本。没有格式保留,那跟AES就没区别了。具体实现时,FPE算法(比如FF3)会先把明文映射到数字域(比如把字母串编码为0~25的整数序列),然后在数字域上做一个保持区间长度不变的置换,再映射回字符。这个映射过程必须是一一对应的,否则解密时无法还原。
可逆:听起来是废话,但我在实际调FF3时踩过一个坑——密钥和tweak必须严格一致。在项目里,有人把tweak记错了,加密时用"ABC",解密时用"abc",结果解密出来的数据全是乱的。所以可逆不仅算法要可逆,参数管理也必须确保一致性。
安全:FPE的安全性通常建立在底层分组密码(如AES)的安全之上。FF3模式本身被证明是安全PRP(伪随机置换),但要注意,FPE的安全性不能超过其底层密码。当初FF1/FF2曾被发现有边界攻击,需要额外防护。而FF3-1是目前NIST推荐的标准,相对成熟。
知识结构图:FPE核心思想与对比
下面这张图帮你把这一章的主要逻辑串起来。左边是标准加密的困境,右边是FPE的解决方案,中间是三大要素形成支撑。
看明白了吧?左边那种加密产物,系统根本没法直接存。右边FPE出来的东西,你直接往数据库旧字段里塞,旧代码完全不用改。而底下那三个要素——格式、可逆、安全——就是支撑FPE这个桥梁的三根柱子。少一根,桥就塌了。
这一章我们把FPE的核心思想讲透了:格式保留是出发点,可逆性是底线,安全性是保障。后面几章我们会钻进FF3的算法细节里,看看那套“数字域置换”到底是怎么做到的。但在这之前,我强烈建议你动手跑一下FF3的示例代码,哪怕只是加密一个"1234567890123456",看看输出是不是真的也是16位数字——亲眼看到比什么都管用。