zoukankan      html  css  js  c++  java
  • 5.Java 加解密技术系列之 DES

    Java 加解密技术系列之 DES

    • 背景
    • 概念
    • 基本原理
    • 主要流程
    • 分组模式
    • 代码实现
    • 结束语


    前 几篇文章讲的都是单向加密算法,其中涉及到了 BASE64、MD5、SHA、HMAC 等几个比较常见的加解密算法。这篇文章,以及后面几篇,打算介绍几个对称加密算法,比如:DES、3DES(TripleDES)、AES 等。那么,这篇文章主要是对 DES 大概讲一下。


    背景

    在 讨论 DES 之前,首先了解一下什么是对称加密算法吧。对于对称加密算法,他应用的时间比较早,技术相对来说比较成熟,在对称加密算法中,数据发信方将明文(原始数 据)和加密密钥一起经过特殊加密算法处理后,使其变成复杂的加密密文发送出去。收信方收到密文后,若想解读原文,则需要使用加密用过的密钥及相同算法的逆 算法对密文进行解密,才能使其恢复成可读明文。



    在对称加密算法中,使用的密钥只有一个,发收信双方都使用这个密钥对数据进行加密和解密,这就要求解密方事先必须知道加密密钥。对称加密算法的特点是算法公开、计算量小。不足之处是,交易双方都使用同样钥匙,安全性得不到保证。


    概念

    那么,什么是 DES?他是怎么来的?相信很多人都很感兴趣,因为以前在开发的时候,对进度的要求比较严,很多时候根本就没有时间来了解这些东西。因此,今天专门来研究研究这个东西。

    DES, 全称为“Data Encryption Standard”,中文名为“数据加密标准”,是一种使用密钥加密的块算法。DES 算法为密码体制中的对称密码体制,又被称为美国数据加密标准,是 1972 年美国 IBM 公司研制的对称密码体制加密算法。 明文按 64 位进行分组,密钥长 64 位,密钥事实上是 56 位参与 DES 运算(第8、16、24、32、40、48、56、64 位是校验位, 使得每个密钥都有奇数个 1)分组后的明文组和 56 位的密钥按位替代或交换的方法形成密文组的加密方法。


    基本原理

    入口参数有三个:key、data、mode。key 为加密解密使用的密钥,data 为加密 解密的数据,mode 为其工作模式。当模式为加密模式时,明文按照 64 位进行分组,形成明文组,key 用于对数据加密,当模式为解密模式时,key 用于对数据解密。实际运用中,密钥只用到了 64 位中的 56 位,这样才具有高的安全性。




    主要流程

    DES 算法把 64 位的明文输入块变为 64 位的密文输出块,它所使用的密钥也是 64 位,其算法主要分为两步:

    • 初始置换
    其功能是把输入的 64 位数据块按位重新组合,并把输出分为 L0、R0 两部分,每部分各长 32 位,其置换规则为将输入的第 58 位换到第一位,第 50 位换到第 2 位 …… 依此类推,最后一位是原来的第 7 位。L0、R0 则是换位输出后的两部分,L0 是输出的左 32 位,R0 是右  32 位,例:设置换前的输入值为 D1 D2 D3 …… D64,则经过初始置换后的结果为:L0 = D58 D50 …… D8;R0 = D57 D49 …… D7。

    • 整个算法 的主流程图如下:




    分组模式



    • CTR,中文名“计数模式”,是对一系列输入数据块(称为计数)进行加密,产生一系列的输出块,输出块与明文异或得到密文。对于最后的数据块,可能是长 u 位的局部数据块,这 u 位就将用于异或操作,而剩下的 b-u 位将被丢弃(b表示块的长度)。




    代码实现
    import com.google.common.base.Strings;  
    import sun.misc.BASE64Decoder;  
    import sun.misc.BASE64Encoder;  
      
    import javax.crypto.Cipher;  
    import javax.crypto.KeyGenerator;  
    import javax.crypto.SecretKey;  
    import javax.crypto.SecretKeyFactory;  
    import javax.crypto.spec.DESKeySpec;  
    import java.security.InvalidKeyException;  
    import java.security.Key;  
    import java.security.NoSuchAlgorithmException;  
    import java.security.SecureRandom;  
    import java.security.spec.InvalidKeySpecException;  
      
    /** 
     * Created by xiang.li on 2015/2/28. 
     * DES 加解密工具类 
     * 
     * <pre> 
     * 支持 DES、DESede(TripleDES,就是3DES)、AES、Blowfish、RC2、RC4(ARCFOUR) 
     * DES                  key size must be equal to 56 
     * DESede(TripleDES)    key size must be equal to 112 or 168 
     * AES                  key size must be equal to 128, 192 or 256,but 192 and 256 bits may not be available 
     * Blowfish             key size must be multiple of 8, and can only range from 32 to 448 (inclusive) 
     * RC2                  key size must be between 40 and 1024 bits 
     * RC4(ARCFOUR)         key size must be between 40 and 1024 bits 
     * 具体内容 需要关注 JDK Document http://.../docs/technotes/guides/security/SunProviders.html 
     * </pre> 
     */  
    public class DES {  
        /** 
         * 定义加密方式 
         */  
        private final static String KEY_DES = "DES";  
        private final static String KEY_AES = "AES";    // 测试  
      
        /** 
         * 全局数组 
         */  
        private final static String[] hexDigits = { "0", "1", "2", "3", "4", "5",  
                "6", "7", "8", "9", "a", "b", "c", "d", "e", "f" };  
      
        /** 
         * 初始化密钥 
         * @return 
         */  
        public static String init() {  
            return init(null);  
        }  
      
        /** 
         * 初始化密钥 
         * @param seed 初始化参数 
         * @return 
         */  
        public static String init(String seed) {  
            SecureRandom secure = null;  
            String str = "";  
            try {  
                if (null != secure) {  
                    // 带参数的初始化  
                    secure = new SecureRandom(decryptBase64(seed));  
                } else {  
                    // 不带参数的初始化  
                    secure = new SecureRandom();  
                }  
      
                KeyGenerator generator = KeyGenerator.getInstance(KEY_DES);  
                generator.init(secure);  
      
                SecretKey key = generator.generateKey();  
                str = encryptBase64(key.getEncoded());  
            } catch (Exception e) {  
                e.printStackTrace();  
            }  
            return str;  
        }  
      
        /** 
         * 转换密钥 
         * @param key 密钥的字节数组 
         * @return 
         */  
        private static Key byteToKey(byte[] key) {  
            SecretKey secretKey = null;  
            try {  
                DESKeySpec dks = new DESKeySpec(key);  
                SecretKeyFactory factory = SecretKeyFactory.getInstance(KEY_DES);  
                secretKey = factory.generateSecret(dks);  
      
                // 当使用其他对称加密算法时,如AES、Blowfish等算法时,用下述代码替换上述三行代码  
    //            secretKey = new SecretKeySpec(key, KEY_DES);  
            } catch (InvalidKeyException e) {  
                e.printStackTrace();  
            } catch (NoSuchAlgorithmException e) {  
                e.printStackTrace();  
            } catch (InvalidKeySpecException e) {  
                e.printStackTrace();  
            }  
            return secretKey;  
        }  
      
        /** 
         * DES 解密 
         * @param data 需要解密的字符串 
         * @param key 密钥 
         * @return 
         */  
        public static String decryptDES(String data, String key) {  
            // 验证传入的字符串  
            if (Strings.isNullOrEmpty(data)) {  
                return "";  
            }  
            // 调用解密方法完成解密  
            byte[] bytes = decryptDES(hexString2Bytes(data), key);  
            // 将得到的字节数组变成字符串返回  
            return new String(bytes);  
        }  
      
        /** 
         * DES 解密 
         * @param data 需要解密的字节数组 
         * @param key 密钥 
         * @return 
         */  
        public static byte[] decryptDES(byte[] data, String key) {  
            byte[] bytes = null;  
            try {  
                Key k = byteToKey(decryptBase64(key));  
                Cipher cipher = Cipher.getInstance(KEY_DES);  
                cipher.init(Cipher.DECRYPT_MODE, k);  
                bytes = cipher.doFinal(data);  
            } catch (Exception e) {  
                e.printStackTrace();  
            }  
            return bytes;  
        }  
      
        /** 
         * DES 加密 
         * @param data 需要加密的字符串 
         * @param key 密钥 
         * @return 
         */  
        public static String encryptDES(String data, String key) {  
            // 验证传入的字符串  
            if (Strings.isNullOrEmpty(data)) {  
                return "";  
            }  
            // 调用加密方法完成加密  
            byte[] bytes = encryptDES(data.getBytes(), key);  
            // 将得到的字节数组变成字符串返回  
            return byteArrayToHexString(bytes);  
        }  
      
        /** 
         * DES 加密 
         * @param data 需要加密的字节数组 
         * @param key 密钥 
         * @return 
         */  
        public static byte[] encryptDES(byte[] data, String key) {  
            byte[] bytes = null;  
            try {  
                Key k = byteToKey(decryptBase64(key));  
                Cipher cipher = Cipher.getInstance(KEY_DES);  
                cipher.init(Cipher.ENCRYPT_MODE, k);  
                bytes = cipher.doFinal(data);  
            } catch (Exception e) {  
                e.printStackTrace();  
            }  
            return bytes;  
        }  
      
      
        /** 
         * BASE64 解密 
         * @param key 需要解密的字符串 
         * @return 字节数组 
         * @throws Exception 
         */  
        public static byte[] decryptBase64(String key) throws Exception {  
            return (new BASE64Decoder()).decodeBuffer(key);  
        }  
      
        /** 
         * BASE64 加密 
         * @param key 需要加密的字节数组 
         * @return 字符串 
         * @throws Exception 
         */  
        public static String encryptBase64(byte[] key) throws Exception {  
            return (new BASE64Encoder()).encodeBuffer(key);  
        }  
      
        /** 
         * 将一个字节转化成十六进制形式的字符串 
         * @param b 字节数组 
         * @return 字符串 
         */  
        private static String byteToHexString(byte b) {  
            int ret = b;  
            //System.out.println("ret = " + ret);  
            if (ret < 0) {  
                ret += 256;  
            }  
            int m = ret / 16;  
            int n = ret % 16;  
            return hexDigits[m] + hexDigits[n];  
        }  
      
        /** 
         * 转换字节数组为十六进制字符串 
         * @param bytes 字节数组 
         * @return 十六进制字符串 
         */  
        private static String byteArrayToHexString(byte[] bytes) {  
            StringBuffer sb = new StringBuffer();  
            for (int i = 0; i < bytes.length; i++) {  
                sb.append(byteToHexString(bytes[i]));  
            }  
            return sb.toString();  
        }  
      
      
        /** 
         * 转换十六进制字符串为字节数组 
         * @param hexstr 十六进制字符串 
         * @return 
         */  
        public static byte[] hexString2Bytes(String hexstr) {  
            byte[] b = new byte[hexstr.length() / 2];  
            int j = 0;  
            for (int i = 0; i < b.length; i++) {  
                char c0 = hexstr.charAt(j++);  
                char c1 = hexstr.charAt(j++);  
                b[i] = (byte) ((parse(c0) << 4) | parse(c1));  
            }  
            return b;  
        }  
      
        /** 
         * 转换字符类型数据为整型数据 
         * @param c 字符 
         * @return 
         */  
        private static int parse(char c) {  
            if (c >= 'a')  
                return (c - 'a' + 10) & 0x0f;  
            if (c >= 'A')  
                return (c - 'A' + 10) & 0x0f;  
            return (c - '0') & 0x0f;  
        }  
      
        /** 
         * 测试方法 
         * @param args 
         */  
        public static void main(String[] args) {  
            String key = DES.init();  
            System.out.println("DES密钥:
    " + key);  
      
            String word = "123";  
              
      
            String encWord = encryptDES(word, key);  
      
            System.out.println(word + "
    加密后:
    " + encWord);  
            System.out.println(word + "
    解密后:
    " + decryptDES(encWord, key));  
        }  
    }

    结束语


    到 这里,这篇文章也就差不多要结束了,希望以上的内容对各位看官有稍许的帮助,哪怕一点也好。其实,在日常的开发中,如果不是进度控制的特别严格,对于这些 原理性的东西,我们还是需要知道的,对于那些细节的东西,可以不用死记硬背,有网的话,随用随查就可以了。但这个前提是,原理性的东西必须要懂,知道了原 理,就会有解决思路,有了思路,解决问题是迟早的事,细节嘛,不用那么纠结,做的时候考虑到就行了,毕竟时间是有限的。


  • 相关阅读:
    Confluence 6 连接一个目录
    卸载 PrestaShop 1.7
    一“脚”到位-淋漓尽致的自动化部署
    从细节处谈Android冷启动优化
    视觉设计师的进化
    网易对象存储NOS图床神器
    移动端互动直播(入门篇)
    SpringBoot入门(五)——自定义配置
    SpringBoot入门(四)——自动配置
    SpringBoot入门(三)——入口类解析
  • 原文地址:https://www.cnblogs.com/crazylqy/p/5178142.html
Copyright © 2011-2022 走看看