DES加密 包含中文 加密后再解密 中文就是乱码或者报错 怎么办?报错-问答-阿里云开发者社区-阿里云

开发者社区> 问答> 正文

DES加密 包含中文 加密后再解密 中文就是乱码或者报错 怎么办?报错

爱吃鱼的程序员 2020-06-06 16:21:23 354

代码如下:

 

public class Test {
    @org.junit.Test
    public void test(){
        //加密内容
        String source = "加密加密加12abc";
        //加密密钥
        String key = "chiscdc_fsws_@%^";

        String encrypt = EncryptUtil.encryptByKey(source,key);
        System.out.println("加密后:"+encrypt);

        String decrypt = EncryptUtil.decryptByKey(encrypt,key);
        System.out.println("解密后:"+decrypt);
    }

}

 

public class EncryptUtil {

   /**
    * 密钥算法
    */
   private static final String ALGORITHM = "DES";
   /**
    * 加解密算法/工作模式/填充方式
    */
   private static final String ALGORITHM_STR = "DES/ECB/NoPadding";

   private static final String CHARSET = "UTF-8";
   
   /**
    * 填充内容
    */
   private static final String PAD_STR = "\0";



   /**
    * <p>方法描述:根据自己的密钥实现des加密</p>
    *
    * @MethodAuthor yzd, 2018/7/23,encryptByKey
    *
    */
    public static String encryptByKey(String souce,String key) {
        try {
            return encryptByDes(pkcs5Pad(souce), pkcs5Pad(key));
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }



   /**
    * <p>方法描述:根据密钥解密</p>
    *
    * @MethodAuthor yzd, 2018/7/23,decryptByKey
    *
    */
    public static String decryptByKey(String souce,String key) {
        try {
            return decryptByDes(souce, pkcs5Pad(key)).trim();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * <p>方法描述:正式加密操作</p>
     *
     * @MethodAuthor yzd, 2018/7/23,decryptByKey
     *
     */
   private static String encryptByDes( String souce, String key)
         throws Exception {
      // DES算法要求有一个可信任的随机数源
      SecureRandom sr = new SecureRandom();
      // 从原始密匙数据创建DESKeySpec对象
      DESKeySpec dks = new DESKeySpec(key.getBytes(CHARSET));
      // 创建一个密匙工厂,然后用它把DESKeySpec转换成 一个SecretKey对象
      SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGORITHM);
      SecretKey key1 = keyFactory.generateSecret(dks);
      // Cipher对象实际完成加密操作
      Cipher cipher = Cipher.getInstance(ALGORITHM_STR);
      // 用密匙初始化Cipher对象
      cipher.init(Cipher.ENCRYPT_MODE, key1, sr);
      // 现在,获取数据并加密
      byte encryptedData[] = cipher.doFinal(souce.getBytes(CHARSET));

      return byteArr2HexStr(encryptedData);
   }



   public static String byteArr2HexStr(byte[] arrB) {
      int iLen = arrB.length;
      // 每个byte用两个字符才能表示,所以字符串的长度是数组长度的两倍
      StringBuffer sb = new StringBuffer(iLen * 2);
      for (int i = 0; i < iLen; i++) {
         int intTmp = arrB[i];
         // 把负数转换为正数
         while (intTmp < 0) {
            intTmp = intTmp + 256;
         }
         // 小于0F的数需要在前面补0
         if (intTmp < 16) {
            sb.append("0");
         }
         sb.append(Integer.toString(intTmp, 16));
      }
      return sb.toString();
   }

   
   
   private static String decryptByDes(String souce, String key)
         throws Exception {
      // DES算法要求有一个可信任的随机数源
      SecureRandom sr = new SecureRandom();
      // 从原始密匙数据创建DESKeySpec对象
      DESKeySpec dks = new DESKeySpec(key.getBytes(CHARSET));
      // 创建一个密匙工厂,然后用它把DESKeySpec转换成 一个SecretKey对象
      SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGORITHM);
      SecretKey key1 = keyFactory.generateSecret(dks);
      // Cipher对象实际完成加密操作
      Cipher cipher = Cipher.getInstance(ALGORITHM_STR);
      // 用密匙初始化Cipher对象
      cipher.init(Cipher.DECRYPT_MODE, key1, sr);

      // 将加密报文用BASE64算法转化为字节数组
      byte[] encryptedData = hexStr2ByteArr(souce);
      // 用DES算法解密报文
      byte decryptedData[] = cipher.doFinal(encryptedData);
      return new String(decryptedData, CHARSET);
   }

   public static byte[] hexStr2ByteArr(String strIn) throws Exception {
      byte[] arrB = strIn.getBytes();
      int iLen = arrB.length;

      // 两个字符表示一个字节,所以字节数组长度是字符串长度除以2
      byte[] arrOut = new byte[iLen / 2];
      for (int i = 0; i < iLen; i = i + 2) {
         String strTmp = new String(arrB, i, 2);
         arrOut[i / 2] = (byte) Integer.parseInt(strTmp, 16);
      }
      return arrOut;
   }

   /**
    * <p>方法描述:不足8的倍数,后面追加空格</p>
    *
    * @MethodAuthor yzd, 2018/7/27,pkcs5Pad
    *
    */
   private static String pkcs5Pad(final String souce) {
      // 密文和密钥的长度必须是8的倍数
      if (0 == souce.length() % 8) {
         return souce;
      }

      StringBuffer tmp = new StringBuffer(souce);

      while (0 != tmp.length() % 8) {
         tmp.append(PAD_STR);
      }
      return tmp.toString();
   }
}

运行后结果:

 

乱码报错 sha加密解密 密码加密sha 密码加密sha报错 密码加解密
分享到
取消 提交回答
全部回答(1)
  • 爱吃鱼的程序员
    2020-06-08 11:21:39
                        <p>//这是调用的测试程序:</p>
    

    public static void test(){
            //加密内容
            String source = "加密加密加12abc";
            //加密密钥
            String key = "chiscdc_fsws_@%^";

            String encrypt = EncryptUtil.encryptByKey(source,key);
            System.out.println("加密后:"+encrypt);

            String decrypt = EncryptUtil.decryptByKey(encrypt,key);
            System.out.println("解密后:"+decrypt);
        }
        

    //这是 EncryptUtil :

    import java.io.UnsupportedEncodingException;
    import java.security.SecureRandom;

    import javax.crypto.Cipher;
    import javax.crypto.SecretKey;
    import javax.crypto.SecretKeyFactory;
    import javax.crypto.spec.DESKeySpec;
    import javax.xml.transform.Source;

    public class EncryptUtil {

       /**
        * 密钥算法
        */
       private static final String ALGORITHM = "DES";
       /**
        * 加解密算法/工作模式/填充方式
        */
       private static final String ALGORITHM_STR = "DES/ECB/NoPadding";

       private static final String CHARSET = "UTF-8";
       
       /**
        * 填充内容
        */
       private static final String PAD_STR = "\0";

       /**
        * <p>方法描述:根据自己的密钥实现des加密</p>
        *
        * @MethodAuthor yzd, 2018/7/23,encryptByKey
        *
        */
        public static String encryptByKey(String souce, String key) {
            try {
                return encryptByDes(pkcs5Pad(souce), pkcs5Pad(key));
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        }

       /**
        * <p>方法描述:根据密钥解密</p>
        *
        * @MethodAuthor yzd, 2018/7/23,decryptByKey
        *
        */
        public static String decryptByKey(String souceString,String key) {
            try {
                byte [] source = hexStringToBytes(souceString);
                return decryptByDes(source, pkcs5Pad(key)).trim();
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        }

        /**
         * <p>方法描述:正式加密操作</p>
         *
         * @MethodAuthor yzd, 2018/7/23,decryptByKey
         *
         */
       private static String encryptByDes( byte[] souce, byte[] bs)
             throws Exception {
          // DES算法要求有一个可信任的随机数源
          SecureRandom sr = new SecureRandom();
          // 从原始密匙数据创建DESKeySpec对象
          DESKeySpec dks = new DESKeySpec(bs);
          // 创建一个密匙工厂,然后用它把DESKeySpec转换成 一个SecretKey对象
          SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGORITHM);
          SecretKey key1 = keyFactory.generateSecret(dks);
          // Cipher对象实际完成加密操作
          Cipher cipher = Cipher.getInstance(ALGORITHM_STR);
          // 用密匙初始化Cipher对象
          cipher.init(Cipher.ENCRYPT_MODE, key1, sr);
          // 现在,获取数据并加密
          byte encryptedData[] = cipher.doFinal(souce);

          return byteArr2HexStr(encryptedData);
       }

       public static String byteArr2HexStr(byte[] arrB) {
          int iLen = arrB.length;
          // 每个byte用两个字符才能表示,所以字符串的长度是数组长度的两倍
          StringBuffer sb = new StringBuffer(iLen * 2);
          for (int i = 0; i < iLen; i++) {
             int intTmp = arrB[i];
             // 把负数转换为正数
             while (intTmp < 0) {
                intTmp = intTmp + 256;
             }
             // 小于0F的数需要在前面补0
             if (intTmp < 16) {
                sb.append("0");
             }
             sb.append(Integer.toString(intTmp, 16));
          }
          return sb.toString();
       }

       public static byte[] hexStringToBytes(String hexString) {
            if (hexString == null) {
                return null;
            }
           if (hexString.length() <= 0){
               return new byte[0];
           }
            hexString = hexString.toUpperCase();
            int length = hexString.length() / 2;
            char[] hexChars = hexString.toCharArray();
            byte[] result = new byte[length];
            for (int i = 0; i < length; i++) {
                int step = i * 2;
                result[i] = (byte) (charToByte(hexChars[step]) << 4 | charToByte(hexChars[step + 1]));
            }
            return result;
        }
       private static final String HEX_STRING_MAPPING = "0123456789ABCDEF";
       private static byte charToByte(char c) {
            return (byte) HEX_STRING_MAPPING.indexOf(c);
        }
       
       private static String decryptByDes(byte[] souce, byte[] bs)
             throws Exception {
          // DES算法要求有一个可信任的随机数源
          SecureRandom sr = new SecureRandom();
          // 从原始密匙数据创建DESKeySpec对象
          DESKeySpec dks = new DESKeySpec(bs);
          // 创建一个密匙工厂,然后用它把DESKeySpec转换成 一个SecretKey对象
          SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGORITHM);
          SecretKey key1 = keyFactory.generateSecret(dks);
          // Cipher对象实际完成加密操作
          Cipher cipher = Cipher.getInstance(ALGORITHM_STR);
          // 用密匙初始化Cipher对象
          cipher.init(Cipher.DECRYPT_MODE, key1, sr);

          // 将加密报文用BASE64算法转化为字节数组
          byte[] encryptedData =souce;
          // 用DES算法解密报文
          byte decryptedData[] = cipher.doFinal(encryptedData);
          return new String(decryptedData, CHARSET);
       }

       public static byte[] hexStr2ByteArr(byte[] byIn) throws Exception {
          byte[] arrB = byIn;
          int iLen = arrB.length;

          // 两个字符表示一个字节,所以字节数组长度是字符串长度除以2
          byte[] arrOut = new byte[iLen / 2];
          for (int i = 0; i < iLen; i = i + 2) {
             String strTmp = new String(arrB, i, 2);
             arrOut[i / 2] = (byte) Integer.parseInt(strTmp, 16);
          }
          return arrOut;
       }

       /**
        * <p>方法描述:不足8的倍数,后面追加空格</p>
        *
        * @MethodAuthor yzd, 2018/7/27,pkcs5Pad
        *
        */
       private static byte[] pkcs5Pad(final String inSouce) {
            byte[] bySource = new byte[0];
            try {
                bySource = inSouce.getBytes(CHARSET);

                // 密文和密钥的长度必须是8的倍数
                if (0 == bySource.length % 8) {
                    return bySource;
                }
            } catch (UnsupportedEncodingException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

            int length = bySource.length;
            int nPaddedLength = (length / 8 + 1) * 8;
            byte[] byReturn = new byte[nPaddedLength];
            System.arraycopy(bySource, 0, byReturn, 0, length);
            int i = length;
            while (i < nPaddedLength) {
                byReturn[i] = (byte) (nPaddedLength - length);
                i++;
            }
            return byReturn;
        }
    }

     

    原因在于: 输入的原文必须是BYTE数据,汉字的话,使用UTF-8获取其BYTE值。

    DES加密时,是需要按分组长度为8字节补齐的。

     

                            大神 小弟不才  请问   result[i] = (byte) (charToByte(hexChars[step]) << 4 | charToByte(hexChars[step + 1]));  这段是做什么的?
                        
    
                            卧槽 可以的 大神大神 膜拜一下  谢了~
                        
    
                        <p>UTF-8</p>
    
                    
    
                        <p>另外, 原代码中的pkcs5Pad的补码方式是不对的。 请参考 https://blog.csdn.net/stewart/article/details/52462273</p>
    
                    
    
                        <p>不用楼上说的那么麻烦直接将这行代码</p> 
    
    private static final String ALGORITHM_STR = "DES/ECB/NoPadding"

    改为

    public static final String CIPHER_ALGORITHM = "DES/ECB/PKCS5Padding ";

    即可

    错误原因:

    DES、AES 或者 3DES 属于块加密算法,一般来说原文必须是 8 的整数倍,所以块加密算法除子加密模式之外,还涉及到一个填充模式。 如果一定要用 NoPadding 的话,那么必须保证原文字节是 8 的倍数,否则的话需要使用其他的填充模式。 在 Sun JCE 中默认的填充模式除了 NoPadding 之外,还有: PKCS5Padding 和 ISO10126Padding PKCS5Padding 的填充规则是: 填充至符合块大小的整数倍,填充值为填充数量数。例如: 原始:FF FF FF FF FF FF FF FF FF 填充:FF FF FF FF FF FF FF FF FF 07 07 07 07 07 07 07 ISO10126Padding 的填充规则是: 填充至符合块大小的整数倍,填充值最后一个字节为填充的数量数,其他字节随机处理。例如: 原始:FF FF FF FF FF FF FF FF FF 填充:FF FF FF FF FF FF FF FF FF 3F 7A B4 09 14 36 07 使用填充模式后原文字节并不需要是 8 的整数倍,采用填充模式之后,块加密的密文长度为: (N / 8 * 8) + 8 如上,假如原文长度为 15 个字节,密文长度就是 16 个字节。假如原文长度为 16 个字节,密文长度就为 24 个字节。也就是说,采用填充模式后必须进行填充,哪怕是 8 的整数倍。

                            厉害了 都是大神啊
                        
    
                        <div class='ref'><h4>引用来自“melon_jj”的评论</h4><p>不用楼上说的那么麻烦直接将这行代码</p> 
    
    private static final String ALGORITHM_STR = "DES/ECB/NoPadding"

    改为

    public static final String CIPHER_ALGORITHM = "DES/ECB/PKCS5Padding ";

    即可

    错误原因:

    DES、AES 或者 3DES 属于块加密算法,一般来说原文必须是 8 的整数倍,所以块加密算法除子加密模式之外,还涉及到一个填充模式。 如果一定要用 NoPadding 的话,那么必须保证原文字节是 8 的倍数,否则的话需要使用其他的填充模式。 在 Sun JCE 中默认的填充模式除了 NoPadding 之外,还有: PKCS5Padding 和 ISO10126Padding PKCS5Padding 的填充规则是: 填充至符合块大小的整数倍,填充值为填充数量数。例如: 原始:FF FF FF FF FF FF FF FF FF 填充:FF FF FF FF FF FF FF FF FF 07 07 07 07 07 07 07 ISO10126Padding 的填充规则是: 填充至符合块大小的整数倍,填充值最后一个字节为填充的数量数,其他字节随机处理。例如: 原始:FF FF FF FF FF FF FF FF FF 填充:FF FF FF FF FF FF FF FF FF 3F 7A B4 09 14 36 07 使用填充模式后原文字节并不需要是 8 的整数倍,采用填充模式之后,块加密的密文长度为: (N / 8 * 8) + 8 如上,假如原文长度为 15 个字节,密文长度就是 16 个字节。假如原文长度为 16 个字节,密文长度就为 24 个字节。也就是说,采用填充模式后必须进行填充,哪怕是 8 的整数倍。

                                回复 <a class="referer" target="_blank">@Jordan裔</a>  : 需要交流学习的话可以加群826183079 
                        
    
                                回复 <a class="referer" target="_blank">@Jordan裔</a>  : 好吧
                        
    
                            实在不好意思 
                        
    
                            我也想给你采纳 可是在你回答之前 我已经给楼上的哥们采纳过了 不能重复采纳了
    
    0 0
人工智能
使用钉钉扫一扫加入圈子
+ 订阅

了解行业+人工智能最先进的技术和实践,参与行业+人工智能实践项目

相似问题
最新问题