All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cn.hutool.crypto.symmetric.fpe.FPE Maven / Gradle / Ivy

package cn.hutool.crypto.symmetric.fpe;

import cn.hutool.crypto.KeyUtil;
import cn.hutool.crypto.Padding;
import cn.hutool.crypto.symmetric.AES;
import org.bouncycastle.crypto.AlphabetMapper;
import org.bouncycastle.jcajce.spec.FPEParameterSpec;

import java.io.Serializable;

/**
 * FPE(Format Preserving Encryption)实现,支持FF1和FF3-1模式。
* 相关介绍见:https://anquan.baidu.com/article/193 * *

* FPE是一种格式保持与明文相同的加密方式,通常用于数据脱敏中,因为它需要保持明密文的格式相同, * 例如社保号经过加密之后并不是固定长度的杂文,而是相同格式、打乱的号码,依然是社保号的格式。 *

*

* FPE算法可以保证: * *

    *
  • 数据长度不变。加密前长度是N,加密后长度仍然是N
  • *
  • 数据类型不变,加密前是数字类型,加密后仍然是数字类型
  • *
  • 加密过程可逆,加密后的数据可以通过密钥解密还原原始数据
  • *
* * 此类基于BouncyCastle实现。 * * @author looly * @since 5.7.12 */ public class FPE implements Serializable { private static final long serialVersionUID = 1L; // 映射字符表,规定了明文和密文的字符范围 private final AES aes; private final AlphabetMapper mapper; /** * 构造,使用空的Tweak * * @param mode FPE模式枚举,可选FF1或FF3-1 * @param key 密钥,{@code null}表示随机密钥,长度必须是16bit、24bit或32bit * @param mapper Alphabet字典映射,被加密的字符范围和这个映射必须一致,例如手机号、银行卡号等字段可以采用数字字母字典表 */ public FPE(FPEMode mode, byte[] key, AlphabetMapper mapper) { this(mode, key, mapper, null); } /** * 构造 * * @param mode FPE模式枚举,可选FF1或FF3-1 * @param key 密钥,{@code null}表示随机密钥,长度必须是16bit、24bit或32bit * @param mapper Alphabet字典映射,被加密的字符范围和这个映射必须一致,例如手机号、银行卡号等字段可以采用数字字母字典表 * @param tweak Tweak是为了解决因局部加密而导致结果冲突问题,通常情况下将数据的不可变部分作为Tweak,{@code null}使用默认长度全是0的bytes */ public FPE(FPEMode mode, byte[] key, AlphabetMapper mapper, byte[] tweak) { if (null == mode) { mode = FPEMode.FF1; } if (null == tweak) { switch (mode) { case FF1: tweak = new byte[0]; break; case FF3_1: // FF3-1要求必须为56 bits tweak = new byte[7]; } } this.aes = new AES(mode.value, Padding.NoPadding.name(), KeyUtil.generateKey(mode.value, key), new FPEParameterSpec(mapper.getRadix(), tweak)); this.mapper = mapper; } /** * 加密 * * @param data 数据,数据必须在构造传入的{@link AlphabetMapper}中定义的范围 * @return 密文结果 */ public String encrypt(String data) { if (null == data) { return null; } return new String(encrypt(data.toCharArray())); } /** * 加密 * * @param data 数据,数据必须在构造传入的{@link AlphabetMapper}中定义的范围 * @return 密文结果 */ public char[] encrypt(char[] data) { if (null == data) { return null; } // 通过 mapper 将密文输出处理为原始格式 return mapper.convertToChars(aes.encrypt(mapper.convertToIndexes(data))); } /** * 解密 * * @param data 密文数据,数据必须在构造传入的{@link AlphabetMapper}中定义的范围 * @return 明文结果 */ public String decrypt(String data) { if (null == data) { return null; } return new String(decrypt(data.toCharArray())); } /** * 加密 * * @param data 密文数据,数据必须在构造传入的{@link AlphabetMapper}中定义的范围 * @return 明文结果 */ public char[] decrypt(char[] data) { if (null == data) { return null; } // 通过 mapper 将密文输出处理为原始格式 return mapper.convertToChars(aes.decrypt(mapper.convertToIndexes(data))); } /** * FPE模式
* FPE包括两种模式:FF1和FF3(FF2弃用),核心均为Feistel网络结构。 * * @author looly */ public enum FPEMode { /** * FF1模式 */ FF1("FF1"), /** * FF3-1 模式 */ FF3_1("FF3-1"); private final String value; FPEMode(String name) { this.value = name; } /** * 获取模式名 * * @return 模式名 */ public String getValue() { return value; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy