美文网首页
对称加密之 - DES

对称加密之 - DES

作者: 离线中__ | 来源:发表于2019-03-08 21:21 被阅读0次

    简介

    DES(Data Encryption Standard)是一种对称加密算法,是一种用56位密钥加密64位数据的方法。一般密码长度为8个字节,其中56位加密密钥,每个第8位都用作奇偶校验。

    DES算法一般有两个关键点,第一个是加密算法,第二个是数据补位

    DES算法的几种加密模式

    加密算法常见的有ECB模式CBC模式

    ECB模式:电子密本方式,这是JAVA封装的DES算法的默认模式,就是将数据按照8个字节一段进行DES加密或解密得到一段8个字节的密文或者明文,最后一段不足8个字节,则补足8个字节(注意:这里就涉及到数据补位了)进行计算,之后按照顺序将计算所得的数据连在一起即可,各段数据之间互不影响。

    CBC模式:密文分组链接方式,这是.NET封装的DES算法的默认模式

    DES算法的填补方式

    数据补位一般有NoPaddingPKCS7Padding(JAVA中是PKCS5Padding)填充方式,PKCS7PaddingPKCS5Padding实际只是协议不一样。
    根据相关资料说明:PKCS5Padding明确定义了加密块是8字节,PKCS7Padding加密快可以是1-255之间。
    但是封装的DES算法默认都是8字节,所以可以认为他们一样。
    数据补位实际是在数据不满8字节的倍数,才补充到8字节的倍数的填充过程。

    NoPadding填充方式:算法本身不填充,比如.NETpadding提供了有NoneZeros方式,分别为不填充填充0的方式。

    PKCS7PaddingPKCS5Padding)填充方式:为.NETJAVA的默认填充方式,对加密数据字节长度对8取余为r,如r大于0,则补8-r个字节,字节为8-r的值;如果r等于0,则补8个字节8。

    比如:
    加密字符串为为AAA,则补位为AAA55555;加密字符串为BBBBBB,则补位为BBBBBB22;加密字符串为CCCCCCCC,则补位为CCCCCCCC88888888。

    小结:

    • java中,DES默认ECB加密模式,默认PKCS5Padding填充方式

    Java 实现 DES 加解密

    1. 获得 DES 密钥对象
        /**
         * 获得 DES 密钥对象
         * 
         * @param secretKeyStr 原始密钥字符串
         * @return SecretKey 密钥对象
         * @throws NoSuchAlgorithmException
         * @throws InvalidKeySpecException
         * @throws InvalidKeyException
         */
        private static SecretKey generateKey(String secretKeyStr)
                throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException {
            // 从原始密钥数据 secretKeyStr 创建 DESKeySpec 对象
            DESKeySpec keySpec = new DESKeySpec(secretKeyStr.getBytes());
            // 创建一个密钥工厂,然后用它把 DESKeySpec 转换成 SecretKey 对象
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(DES_ALGORITHM);
            SecretKey securekey = keyFactory.generateSecret(keySpec);
            return securekey;
        }
    
    1. DES加密
        /**
         * DES加密
         * 
         * @param plainData 原始字符串
         * @param secretKey 加密密钥
         * @return 加密后的字符串
         * 
         * @throws NoSuchPaddingException 
         * @throws NoSuchAlgorithmException 
         * @throws InvalidKeySpecException 
         * @throws InvalidKeyException 
         * @throws BadPaddingException 
         * @throws IllegalBlockSizeException 
         */
        public static String encryption(String plainData, String secretKey) 
                throws NoSuchAlgorithmException, NoSuchPaddingException, 
                InvalidKeyException, InvalidKeySpecException, 
                IllegalBlockSizeException, BadPaddingException  {
    
            Cipher cipher = Cipher.getInstance(DES_ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, generateKey(secretKey));
    
            byte[] buf = cipher.doFinal(plainData.getBytes());
    
            return Hex.encodeHexString(buf);
        }
    
    1. DES解密
        /**
         * DES解密
         * 
         * @param secretData 密码字符串
         * @param secretKey 解密密钥
         * @return 原始字符串
         * 
         * @throws NoSuchPaddingException 
         * @throws NoSuchAlgorithmException 
         * @throws InvalidKeySpecException 
         * @throws InvalidKeyException 
         * @throws DecoderException 
         * @throws BadPaddingException 
         * @throws IllegalBlockSizeException 
         * @throws UnsupportedEncodingException 
         */
        public static String decryption(String secretData, String secretKey) 
                throws NoSuchAlgorithmException, NoSuchPaddingException, 
                InvalidKeyException, InvalidKeySpecException, IllegalBlockSizeException, 
                BadPaddingException, DecoderException, UnsupportedEncodingException {
    
            // DES/ECB/NoPadding
            // 默认  DES/ECB/PKCS5Padding  ==> DES
            Cipher cipher = Cipher.getInstance(DES_ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, generateKey(secretKey));
    
            byte[] buf = cipher.doFinal(Hex.decodeHex(secretData.toCharArray()));
            
            return new String(buf, "utf-8");
        }
    
    1. 测试
        public static void main(String[] args) {
            String keyStr = "12345678"; 
            String strOld = "汉字+Admin@123";
            String encodeStr = "";
            String decodeStr = "";
            
            try {
                //加密
                encodeStr = encryption(strOld, keyStr);
                //解密
                decodeStr = decryption(encodeStr, keyStr);
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println(encodeStr); 
            // 373e13088cd22a5a19816fd3a5873024feb959b7d4642fcb
            System.out.println(decodeStr); 
            // 汉字+Admin@123
        }
    

    Js 实现 DES 加解密

    前端采用第三方框架 cryptoJs实现,git 地址

    1. DES 加密
       // DES加密
       function encryptByDES(message) {
           //把私钥转换成16进制的字符串
           let keyHex = CryptoJS.enc.Utf8.parse(key);
           //模式为ECB padding为Pkcs7
           let encrypted = CryptoJS.DES.encrypt(message, keyHex, {
               mode: CryptoJS.mode.ECB,
               padding: CryptoJS.pad.Pkcs7
           });
           //加密出来是一个16进制的字符串
           return encrypted.ciphertext.toString();
       }
    
    1. DES 解密
        //DES  ECB模式解密
        function decryptByDESModeEBC(ciphertext) {
            //把私钥转换成16进制的字符串
            let keyHex = CryptoJS.enc.Utf8.parse(key);
            //把需要解密的数据从16进制字符串转换成字符byte数组
            let decrypted = CryptoJS.DES.decrypt({
                ciphertext: CryptoJS.enc.Hex.parse(ciphertext)
            }, keyHex, {
                mode: CryptoJS.mode.ECB,
                padding: CryptoJS.pad.Pkcs7
            });
            //以utf-8的形式输出解密过后内容
            let result_value = decrypted.toString(CryptoJS.enc.Utf8);
            return result_value;
        }
    
    1. 测试
        //需要加密的内容
        let str1 = encryptByDES('汉字+Admin@123');
        let str2 = decryptByDESModeEBC(str1);
        console.log(str1) // 373e13088cd22a5a19816fd3a5873024feb959b7d4642fcb
        console.log(str2) // 汉字+Admin@123
    

    总结

    • Java 中,Cipher cipher = Cipher.getInstance(DES_ALGORITHM);
      默认采用的是 ESB 加密模式,PKCS5Padding 填充
    • Js 中,mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.Pkcs7;
      所以采用的是 ESB 加密模式,PKCS7Padding 填充
    • 因为 PKCS5PaddingPKCS7Padding 封装的DES算法默认都是8字节,所以可以认为他们一样。
    • 所以如上面demo所示,我们发现 Java 与 Js 采用同样的 密钥key明文 , 最终加解密得到同样的密文。
    • 这样就可以满足前端 Js 加密,后台 Java 解密后台 Java 加密,前端 Js 解密的一整个请求+返回过程的信息加密。

    相关文章

      网友评论

          本文标题:对称加密之 - DES

          本文链接:https://www.haomeiwen.com/subject/htmdpqtx.html