FPE算法概述
各位好,我是这次课程的主讲。在金融、通信这些行业里摸爬滚打十几年,处理过大量敏感数据保护的项目。今天咱们聊聊一个挺有意思的加密技术——格式保留加密,简称FPE。
你可能好奇:什么叫“格式保留”?说白了,就是加密后的结果跟原始数据长得一模一样。比如一个16位信用卡号,加密后还是16位数字;一个手机号,加密后还是11位数字。这在很多业务场景里特别有用——你想想看,数据库字段长度不用改,业务代码不用调,甚至用户都感觉不到数据被加密了。
什么是格式保留加密
传统加密算法,比如AES,加密后输出的是二进制数据。你拿它去加密一个“1234 5678 9012 3456”这样的卡号,得到的密文是一堆乱码,格式完全变了。存储、传输都得重新编码,业务系统根本没法直接处理。
FPE(Format-Preserving Encryption)不一样。它接收一个明文空间(比如“所有16位数字”),加密后输出属于同一个空间的密文。加密前后的格式、长度、字符集全都一模一样。
核心定义:FPE是一种对称加密算法,其加密函数E(K, X)将明文X映射到同一格式空间中的密文Y,且Y与X具有相同的长度和字符集。
举个具体的例子。我之前在银行做信用卡号脱敏项目时,业务方要求:测试环境必须用真实卡号格式,但不能暴露真实卡号。用AES?密文存不进数据库的19位varchar字段。后来改用FPE,卡号加密后还是19位数字,前面6位BIN保留不变,后面用FPE加密——完美解决。这事让我对FPE刮目相看。
为什么需要FPE
你可能会想:保留格式有什么用?我直接改数据库字段长度不行吗?嗯,这里要注意——很多场景下改不动。
- 历史系统改造:老系统的表结构、接口协议早就固化了,改一个字段可能影响上下游几十个系统。我见过一个核心银行系统,光改卡号字段长度就评估了三个月,最后还是没敢动。
- 合规要求:PCI-DSS要求信用卡号必须加密存储,但业务系统需要保持卡号格式用于交易路由。FPE正好符合这种既要安全又要兼容的矛盾需求。
- 隐私保护:数据脱敏、测试数据生成、数据分析场景,常需要保留原始数据的统计特征(比如电话号段分布)。FPE能做到这一点。
| 对比项 | 标准加密(AES) | FPE |
|---|---|---|
| 输出格式 | 二进制/Base64乱码 | 与明文相同的字符集和长度 |
| 字段修改 | 需要扩字段长度或改应用 | 无需修改任何业务代码 |
| 典型场景 | 通用数据加密 | PAN、SSN、电话号等结构化字段加密 |
| 安全性 | 高(取决于实现) | 可达到同等安全强度(依赖底层分组密码) |
发展历史与NIST标准
FPE的概念其实很早就有了。我最早读到相关是在2002年左右,当时密码学界在讨论“如何在保持数据格式的前提下实现加密”。但真正推动标准化的是NIST。
2007年,NIST发布了SP 800-38G,规范了两种FPE模式:FF1和FF3。后来在2016年又修订了FF1,并增加了FF3-1(因为原版FF3被发现存在安全弱点)。这就是目前业界最主流的两个FPE标准。
我的建议:新项目直接用FF1。FF3-1在短字段(比如小于6位)上性能更好,但安全性需要更谨慎的评估。我曾在一次内部讨论中看到同事因为参数配错导致FF3-1输出碰撞——虽然概率极低,但金融场景不允许任何“极低”。
下面是FPE与标准加密的核心流程对比示意图。你可以看到,FPE多了一个“格式空间映射”步骤,确保输出落在允许的格式内。
FPE的核心思想
FPE本质上是一种保留格式的伪随机排列。也就是说,给定一个密钥和格式空间,FPE在空间内构造一个可逆的、与随机置换不可区分的映射。
怎么做到的?NIST标准里用的是“Feistel网络”结构。把明文分成左右两半,通过多轮迭代,结合轮函数(内部调AES)来打乱数据。最后把左右合并,得到密文。
注意!FPE的安全性完全依赖于底层分组密码(通常是AES)和合理的轮数。NIST规定FF1最少10轮,FF3-1最少8轮。我曾经看到一个开源项目为了性能把轮数减到4轮——这相当于把锁的弹子减少一半,千万别这么干。
对于PAN(主账号)保护来说,FPE可以做到:
- 保留卡号的长度和数字字符集
- 保留BIN(发卡行识别码)前6位不变(业务需要)
- 对后几位或整个卡号加密
- 解密后恢复原始卡号