FPE介绍
FPE(Format Preserving Encryption) 格式保留加密是一种格式保持与明文相同的加密方式,通常用于数据脱敏。
例如对于敏感的数据信息,如电话号码(13位数字),FPE算法算法加依旧是13位数字,因此这种特性可以不用变更数据库中字段格式,有利于传播。
除了这些优点,还具有:
- 数据长度不变。加密前长度是N,加密后长度仍然是N
- 数据类型不变,加密前是数字类型,加密后仍然是数字类型。
- 加密过程可逆,加密后的数据可以通过密钥解密还原原始数据。
注:此段引用自《大数据时代下的隐私保护(三)》
更详细的介绍见:
算法实现
由于JDK(JRE)未提供的FPE实现,我们需要借助BouncyCastle
库来完成工作,首先当然是引入Hutool:
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.12</version>
</dependency>
再引入BouncyCastle
库
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15to18</artifactId>
<version>1.69</version>
</dependency>
FF1算法实现
// 映射字符表,规定了明文和密文的字符范围
BasicAlphabetMapper numberMapper = new BasicAlphabetMapper("0123456789");
// 初始化 aes 密钥(随机),长度必须是16bytes、24bytes或32bytes
byte[] keyBytes = RandomUtil.randomBytes(16);
final FPE fpe = new FPE(FPE.FPEMode.FF1, keyBytes, numberMapper,
// Tweak是为了解决因局部加密而导致结果冲突问题,通常情况下将数据的不可变部分作为Tweak,null则使用默认长度全是0的bytes
null);
String phone = "13534534567";
// 加密
String encrypt = fpe.encrypt(phone);
// 解密
String decrypt = fpe.decrypt(encrypt);
FF3算法实现
// 映射字符表,规定了明文和密文的字符范围
BasicAlphabetMapper numberMapper = new BasicAlphabetMapper("0123456789");
// 初始化 aes 密钥(随机)
byte[] keyBytes = RandomUtil.randomBytes(16);
FPE fpe = new FPE(FPE.FPEMode.FF3_1, keyBytes, numberMapper,
// 此处FF3规定tweak为56bit(即7bytes)
new byte[7]);
String phone = "13534534567";
// 加密
String encrypt = fpe.encrypt(phone);
// 解密
String decrypt = fpe.decrypt(encrypt);
相比于AES等加密算法,FPE增加BasicAlphabetMapper
,即有限字母的字典表。
Alphabet:有限字母的字典表,并规定了输出密文的范围,例如对于手机号码而言,是十进制纯数字格式的,其Alphabet包括字符’0′-‘9’。对于MAC地址而言,是十六进制数字格式,其Alphabet应该包括大写英文字母的’A’-‘E’和数字’0’-‘9’在内的十六个字母。
注:此段引用自《大数据时代下的隐私保护(三)》
与掩码屏蔽比较
除了FPE,也可以通过掩码屏蔽方式完成数据脱敏工作,如手机号13912341234 -> 139****1234,不过这种脱敏并不可逆。
掩码屏蔽同样可以借助hutool完成:
// 139****1234
DesensitizedUtil.desensitized("13912341234", DesensitizedUtil.DesensitizedType.MOBILE_PHONE)
两种方式对比如下:
- 掩码:不可逆,长度保持,字符不保持
- FPE : 可逆, 长度保持,字符保持
{{o.name}}
{{m.name}}
原创文章,作者:3628473679,如若转载,请注明出处:https://blog.ytso.com/tech/pnotes/149602.html