• 一种保留格式的加密算法FPE


    一、背景 

          在实际应用中,对数据库中的信用卡号、身份证号等敏感数据进行加密是非要有必要的,然而使用传统的分组密码通常会扩展数据,使数据长度和类型发送变化,需要修改数据库结构或应用程序来适应这些变化,成本非常高。为了解决这类问题,期望出现加密后的密文和加密前的明文格式一致(长度和字符类型一样)的加密算法,也就是本文要提到的FPE(format-preserving encryption)算法。

          FPE算法的初衷是为了解决数据库或者应用系统中敏感数据的加密问题,随着研究的进展,其应用并不仅限于此,比如FPE可以应用于数据遮蔽(data masking)领域,通过克隆原始数据进行掩码转换,输出一个与元数据格式、关联一模一样的数据,用于解决从生产环境的数据向测试环境(或者开发环境)导入时可能产生的数据内容、数据安全问题,此外,FPE对于网络数据安全一样有用,可以使数据报在不改变格式的情况下在传输过程中受到保护。

    二、特征

    1、数据不能被扩充. 例如当加密N位的数字时,必须输出另外一个N位的数字

    2、数据类型不能被改变. 例如一个只包含数字的串加密后输出的串也只能是数字

    3、数据必须能被确定性加密.例如对于数据库中作为主键或者索引字段的数据,被加密后将保留其所在的列作为主键或者索引的特性

    三、构建方法

    学术界关于格式保留加密的研究已持续多年,2002年,Black和Rogaway提出了3种FPE构建方法:

    1、 Prefix

    2、Cycle-Walking

    3、Generalized-Feistel

    这三种方法成为构造FPE模型的基本方法,其中Generalized-Feistel方法的适用性更为广泛,其核心思路是基于Feistel网络来构建符合整数集大小的分组密码,并结合Cycle-Walking方法使最终密文输出在合理范围内,Feistel网络可以通过定义分组大小、密钥长度、轮次数、子密钥生成、轮函数等来构造一个分组密码。

    具体文献:https://www.docin.com/p-132469640.html

    四、实战代码

    @UtilityClass
    public class FPEncryptionUtils {
    
        private static final String SECRET_KEY="yoursecuritypriv";
    
        private static final byte[] A_TWEAK_SUFFIX ="yoursecuritypriv".getBytes();
    
        private static final Alphabet EXTEND_ALPHABET=new ExtendAlphabet();
    
        private static final TextToIntTransformer TEXT_TO_INT_TRANSFORMER = new GenericTransformations(EXTEND_ALPHABET.availableCharacters());
    
        private static final IntToTextTransformer INT_TO_TEXT_TRANSFORMER = new GenericTransformations(EXTEND_ALPHABET.availableCharacters());
    
        private static final ThreadLocal<FormatPreservingEncryption> SEED_POOL= ThreadLocal.withInitial(
                () -> FormatPreservingEncryptionBuilder
                        .ff1Implementation()
                        .withDomain(new GenericDomain(EXTEND_ALPHABET,TEXT_TO_INT_TRANSFORMER,INT_TO_TEXT_TRANSFORMER))
                        .withDefaultPseudoRandomFunction(SECRET_KEY.getBytes())
                        .withDefaultLengthRange()
                        .build());
    
        public static String encrypt(String plainText){
            if(StringUtils.isEmpty(plainText)){
                return null;
            }
            return SEED_POOL.get().encrypt(plainText,A_TWEAK_SUFFIX);
        }
    
        public static String decrypt(String cipherText){
            if(StringUtils.isEmpty(cipherText)){
                return null;
            }
            return SEED_POOL.get().decrypt(cipherText,A_TWEAK_SUFFIX);
        }
    
        private static class ExtendAlphabet implements Alphabet{
    
            private static final char[] NUM_AND_CHARACTER_CHARS = new char[] {
                    '1', '2', '3', '4', '5', '6', '7', '8','9','0',
                    'A','B','C','D','E','F','G','H','I','J','K','L',
                    'M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'};
    
            private static final char[] ONLY_NUM=new char[]{
                '1', '2', '3', '4', '5', '6', '7', '8','9','0'
            };        
    
            @Override
            public char[] availableCharacters() {
                return NUM_AND_CHARACTER_CHARS;
            }
    
            @Override
            public Integer radix() {
                return NUM_AND_CHARACTER_CHARS.length;
            }
        }
    }

    五、效果展示

    输入:1008611           输出:8415027
    输入:18815658640       输出:06207345474
    输入:10086CHF11LH      输出:ZJ8VAT6W7WRL
  • 相关阅读:
    JS开发框架DevExtreme v20.1.7上线
    Web开发:看如何定义Kendo UI Grid Width
    如何创建自定义DevExpress报表控件,看完你就懂了
    高性能HTML5/JavaScript开发框架DevExtreme全新发布v20.1.7|附下载
    WPF界面开发:如何将不同集合中的项目显示为同一父节点子项
    界面开发包DevExpress v20.1.7上线!即刻体验
    WPF界面开发2020:Scheduler等控件功能升级
    Winform界面开发看过来!一招教你使用属性网格自定义编辑器
    将从数据库查询出来的带有父子结构的list转换成treeList结构
    将JDBC ResultSet结果集转成List
  • 原文地址:https://www.cnblogs.com/ljhoracle/p/13038375.html
Copyright © 2020-2023  润新知