美文网首页
Android DES 加密的各种坑

Android DES 加密的各种坑

作者: xq9527 | 来源:发表于2022-11-07 14:38 被阅读0次

    前言

    各位同学大家好,最近工作中用到了DES 对称加密 遇到了一些问题所以就总结出来 希望能帮助到各位同学工作和学习,那么废话不多说 DES是比较常见的堆成加密方式

    对称加密

    对称加密就是公钥好私钥是同一把 加密解密都用这个 与之对应的就是res非堆成加密 我们这边就讲一下对称加密的

    具体实现

    设置好偏移量 算法 和工作模式 编码

         /**
         * 偏移变量,固定占8位字节
         */
        private final static String IV_PARAMETER = "12345678";
        /**
         * 密钥算法
         */
        private static final String ALGORITHM = "DES";
        /**
         * 加密/解密算法-工作模式-填充模式
         */
        private static final String CIPHER_ALGORITHM = "DES/CBC/PKCS5Padding";
        /**
         * 默认编码
         */
        private static final String CHARSET = "utf-8";
        
    

    生成key

      /**
         * 生成key
         *
         * @param password
         * @return
         * @throws Exception
         */
        private static Key generateKey(String password) throws Exception {
            DESKeySpec dks = new DESKeySpec(password.getBytes(CHARSET));
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGORITHM);
            return keyFactory.generateSecret(dks);
        }
    

    加密

     /**
         * DES加密字符串
         *
         * @param password 加密密码,长度不能够小于8位
         * @param data 待加密字符串
         * @return 加密后内容
         */
    
    
        public static String encrypt(String password, String data) {
            if (password== null || password.length() < 8) {
                throw new RuntimeException("加密失败,key不能小于8位");
            }
            if (data == null)
                return null;
            try {
                Key secretKey = generateKey(password);
                Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
                IvParameterSpec iv = new IvParameterSpec(IV_PARAMETER.getBytes(CHARSET));
                cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv);
                byte[] bytes = cipher.doFinal(data.getBytes(CHARSET));
     
                //JDK1.8及以上可直接使用Base64,JDK1.7及以下可以使用BASE64Encoder
                //Android平台可以使用android.util.Base64
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                    return new String(Base64.getEncoder().encode(bytes));
                }else{
                    return  Base64Utils.encode(bytes);
                }
            } catch (Exception e) {
                e.printStackTrace();
                return data;
            }
        }
      
    
    image.png

    我们加密之后要进行base64编码处理一下但是Android SDK 里面提供的api 只能在android 8.0 api26以上才能使用的 .所以我们要在这里兼容下低版本

    低版本android api 26以下 base 64 工具类

    package com.example.desdemo;
    import java.io.UnsupportedEncodingException;
    
    public class Base64Utils {
       private static char[] base64EncodeChars = new char[]
               { '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', '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', '0', '1', '2', '3', '4', '5',
                       '6', '7', '8', '9', '+', '/' };
       private static byte[] base64DecodeChars = new byte[]
               { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
                       -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53,
                       54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
                       12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29,
                       30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1,
                       -1, -1, -1 };
    
       /**
        * 加密
        *
        * @param data
        * @return
        */
       public static String encode(byte[] data) {
          StringBuffer sb = new StringBuffer();
          int len = data.length;
          int i = 0;
          int b1, b2, b3;
          while (i < len) {
             b1 = data[i++] & 0xff;
             if (i == len){
                sb.append(base64EncodeChars[b1 >>> 2]);
                sb.append(base64EncodeChars[(b1 & 0x3) << 4]);
                sb.append("==");
                break;
             }
             b2 = data[i++] & 0xff;
             if (i == len) {
                sb.append(base64EncodeChars[b1 >>> 2]);
                sb.append(base64EncodeChars[((b1 & 0x03) << 4) | ((b2 & 0xf0) >>> 4)]);
                sb.append(base64EncodeChars[(b2 & 0x0f) << 2]);
                sb.append("=");
                break;
             }
             b3 = data[i++] & 0xff;
             sb.append(base64EncodeChars[b1 >>> 2]);
             sb.append(base64EncodeChars[((b1 & 0x03) << 4) | ((b2 & 0xf0) >>> 4)]);
             sb.append(base64EncodeChars[((b2 & 0x0f) << 2) | ((b3 & 0xc0) >>> 6)]);
             sb.append(base64EncodeChars[b3 & 0x3f]);
          }
          return sb.toString();
       }
    
       /**
        * 解密
        *
        * @param str
        * @return
        */
       public static byte[] decode(String str) {
          try{
             return decodePrivate(str);
          } catch (UnsupportedEncodingException e) {
             e.printStackTrace();
          }
          return new byte[]
                  {};
       }
       private static byte[] decodePrivate(String str) throws UnsupportedEncodingException {
          StringBuffer sb = new StringBuffer();
          byte[] data = null;
          data = str.getBytes("US-ASCII");
          int len = data.length;
          int i = 0;
          int b1, b2, b3, b4;
          while (i < len){
             do {
                b1 = base64DecodeChars[data[i++]];
             } while (i < len && b1 == -1);
             if (b1 == -1)
                break;
             do {
                b2 = base64DecodeChars[data[i++]];
             } while (i < len && b2 == -1);
             if (b2 == -1)
                break;
             sb.append((char) ((b1 << 2) | ((b2 & 0x30) >>> 4)));
             do{
                b3 = data[i++];
                if (b3 == 61)
                   return sb.toString().getBytes("iso8859-1");
                b3 = base64DecodeChars[b3];
             } while (i < len && b3 == -1);
             if (b3 == -1)
                break;
             sb.append((char) (((b2 & 0x0f) << 4) | ((b3 & 0x3c) >>> 2)));
             do {
                b4 = data[i++];
                if (b4 == 61)
                   return sb.toString().getBytes("iso8859-1");
                b4 = base64DecodeChars[b4];
             } while (i < len && b4 == -1);
             if (b4 == -1)
                break;
             sb.append((char) (((b3 & 0x03) << 6) | b4));
          }
          return sb.toString().getBytes("iso8859-1");
       }
    }
    
    

    解密

        /**
         * DES解密字符串
         *
         * @param password 解密密码,长度不能够小于8位
         * @param data 待解密字符串
         * @return 解密后内容
         */
    
    
    
        public static String decrypt(String password, String data) {
            if (password== null || password.length() < 8) {
                throw new RuntimeException("加密失败,key不能小于8位");
            }
            if (data == null)
                return null;
            try {
                Key secretKey = generateKey(password);
                Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
                IvParameterSpec iv = new IvParameterSpec(IV_PARAMETER.getBytes(CHARSET));
                cipher.init(Cipher.DECRYPT_MODE, secretKey, iv);
    
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                    return new String(cipher.doFinal(Base64.getMimeDecoder().decode(data.getBytes(CHARSET))), CHARSET);
                }else {
                    return new String(cipher.doFinal(Base64Utils.decode(data)), CHARSET);
                }
            } catch (Exception e) {
                e.printStackTrace();
                return data;
            }
        }
     
    

    解密中遇到的坑

       if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                    return new String(cipher.doFinal(Base64.getDecoder().decode(data.getBytes(CHARSET))), CHARSET);
                }
    

    这是原来写写法
    会报出类似这种错误

      java.lang.IllegalArgumentException: Input byte array has incorrect ending byte at 40
    

    这是网友的回答


    image.png
    • 正确的写法 就能正常解开其他语言加密后的字符串

            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                    return new String(cipher.doFinal(Base64.getMimeDecoder().decode(data.getBytes(CHARSET))), CHARSET);
                }else {
                    return new String(cipher.doFinal(Base64Utils.decode(data)), CHARSET);
              }
    

    加密文件

        /**
         * DES加密文件
         *
         * @param srcFile  待加密的文件
         * @param destFile 加密后存放的文件路径
         * @return 加密后的文件路径
         */
        public static String encryptFile(String password, String srcFile, String destFile) {
     
            if (password== null || password.length() < 8) {
                throw new RuntimeException("加密失败,key不能小于8位");
            }
            try {
                IvParameterSpec iv = new IvParameterSpec(IV_PARAMETER.getBytes(CHARSET));
                Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
                cipher.init(Cipher.ENCRYPT_MODE, generateKey(password), iv);
                InputStream is = new FileInputStream(srcFile);
                OutputStream out = new FileOutputStream(destFile);
                CipherInputStream cis = new CipherInputStream(is, cipher);
                byte[] buffer = new byte[1024];
                int r;
                while ((r = cis.read(buffer)) > 0) {
                    out.write(buffer, 0, r);
                }
                cis.close();
                is.close();
                out.close();
                return destFile;
            } catch (Exception ex) {
                ex.printStackTrace();
            }
            return null;
        }
    
    

    解密文件

        /**
         * DES解密文件
         *
         * @param srcFile  已加密的文件
         * @param destFile 解密后存放的文件路径
         * @return 解密后的文件路径
         */
        public static String decryptFile(String password, String srcFile, String destFile) {
            if (password== null || password.length() < 8) {
                throw new RuntimeException("加密失败,key不能小于8位");
            }
            try {
                File file = new File(destFile);
                if (!file.exists()) {
                    file.getParentFile().mkdirs();
                    file.createNewFile();
                }
                IvParameterSpec iv = new IvParameterSpec(IV_PARAMETER.getBytes(CHARSET));
                Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
                cipher.init(Cipher.DECRYPT_MODE, generateKey(password), iv);
                InputStream is = new FileInputStream(srcFile);
                OutputStream out = new FileOutputStream(destFile);
                CipherOutputStream cos = new CipherOutputStream(out, cipher);
                byte[] buffer = new byte[1024];
                int r;
                while ((r = is.read(buffer)) >= 0) {
                    cos.write(buffer, 0, r);
                }
                cos.close();
                is.close();
                out.close();
                return destFile;
            } catch (Exception ex) {
                ex.printStackTrace();
            }
            return null;
        }
    

    测试

       private void initview() {
            String s = "你好,HelloWorld!";
            // 加密
            String s2 = null;
            s2 = DESUtil.encrypt("环保NB1233", s);
            Log.e(TAG, "环保NB1233:s ---  >加密 s2  -- >   "+s2);
    
            System.out.println("s2===="+s2);
            //解密
            String s3 = null;
            s3 = DESUtil.decrypt("环保NB1233  -- >解密  ", s2);
            Log.e(TAG, "环保NB1233:s ---  >加密 s3  --- >   "+s3);
            System.out.println("s3===="+s3);
    
        }
    

    我们看到日志输出加密解密是可以的

    image.png

    完整代码

    package com.example.desdemo;
    import android.os.Build;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.security.Key;
    import java.util.Base64;
    import javax.crypto.Cipher;
    import javax.crypto.CipherInputStream;
    import javax.crypto.CipherOutputStream;
    import javax.crypto.SecretKeyFactory;
    import javax.crypto.spec.DESKeySpec;
    import javax.crypto.spec.IvParameterSpec;
    
    public class DESUtil {
     
        /**
         * 偏移变量,固定占8位字节
         */
        private final static String IV_PARAMETER = "12345678";
        /**
         * 密钥算法
         */
        private static final String ALGORITHM = "DES";
        /**
         * 加密/解密算法-工作模式-填充模式
         */
        private static final String CIPHER_ALGORITHM = "DES/CBC/PKCS5Padding";
        /**
         * 默认编码
         */
        private static final String CHARSET = "utf-8";
    
    
    
    
    
    
        public static void main(String[] args) {
            String s = "你好,HelloWorld!";
    
            // 加密
            String s2 = null;
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                s2 = encrypt("环保NB1233", s);
            }
    
            System.out.println("s2===="+s2);
    
            //解密
            String s3 = null;
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                s3 = decrypt("环保NB1233", s2);
            }
    
            System.out.println("s3===="+s3);
    
        }
    
     
        /**
         * 生成key
         *
         * @param password
         * @return
         * @throws Exception
         */
        private static Key generateKey(String password) throws Exception {
            DESKeySpec dks = new DESKeySpec(password.getBytes(CHARSET));
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGORITHM);
            return keyFactory.generateSecret(dks);
        }
     
     
        /**
         * DES加密字符串
         *
         * @param password 加密密码,长度不能够小于8位
         * @param data 待加密字符串
         * @return 加密后内容
         */
    
    
        public static String encrypt(String password, String data) {
            if (password== null || password.length() < 8) {
                throw new RuntimeException("加密失败,key不能小于8位");
            }
            if (data == null)
                return null;
            try {
                Key secretKey = generateKey(password);
                Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
                IvParameterSpec iv = new IvParameterSpec(IV_PARAMETER.getBytes(CHARSET));
                cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv);
                byte[] bytes = cipher.doFinal(data.getBytes(CHARSET));
     
                //JDK1.8及以上可直接使用Base64,JDK1.7及以下可以使用BASE64Encoder
                //Android平台可以使用android.util.Base64
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                    return new String(Base64.getEncoder().encode(bytes));
                }else{
                    return  Base64Utils.encode(bytes);
                }
            } catch (Exception e) {
                e.printStackTrace();
                return data;
            }
        }
     
        /**
         * DES解密字符串
         *
         * @param password 解密密码,长度不能够小于8位
         * @param data 待解密字符串
         * @return 解密后内容
         */
    
    
    
        public static String decrypt(String password, String data) {
            if (password== null || password.length() < 8) {
                throw new RuntimeException("加密失败,key不能小于8位");
            }
            if (data == null)
                return null;
            try {
                Key secretKey = generateKey(password);
                Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
                IvParameterSpec iv = new IvParameterSpec(IV_PARAMETER.getBytes(CHARSET));
                cipher.init(Cipher.DECRYPT_MODE, secretKey, iv);
    
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                    return new String(cipher.doFinal(Base64.getMimeDecoder().decode(data.getBytes(CHARSET))), CHARSET);
                }else {
                    return new String(cipher.doFinal(Base64Utils.decode(data)), CHARSET);
                }
            } catch (Exception e) {
                e.printStackTrace();
                return data;
            }
        }
     
        /**
         * DES加密文件
         *
         * @param srcFile  待加密的文件
         * @param destFile 加密后存放的文件路径
         * @return 加密后的文件路径
         */
        public static String encryptFile(String password, String srcFile, String destFile) {
     
            if (password== null || password.length() < 8) {
                throw new RuntimeException("加密失败,key不能小于8位");
            }
            try {
                IvParameterSpec iv = new IvParameterSpec(IV_PARAMETER.getBytes(CHARSET));
                Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
                cipher.init(Cipher.ENCRYPT_MODE, generateKey(password), iv);
                InputStream is = new FileInputStream(srcFile);
                OutputStream out = new FileOutputStream(destFile);
                CipherInputStream cis = new CipherInputStream(is, cipher);
                byte[] buffer = new byte[1024];
                int r;
                while ((r = cis.read(buffer)) > 0) {
                    out.write(buffer, 0, r);
                }
                cis.close();
                is.close();
                out.close();
                return destFile;
            } catch (Exception ex) {
                ex.printStackTrace();
            }
            return null;
        }
     
        /**
         * DES解密文件
         *
         * @param srcFile  已加密的文件
         * @param destFile 解密后存放的文件路径
         * @return 解密后的文件路径
         */
        public static String decryptFile(String password, String srcFile, String destFile) {
            if (password== null || password.length() < 8) {
                throw new RuntimeException("加密失败,key不能小于8位");
            }
            try {
                File file = new File(destFile);
                if (!file.exists()) {
                    file.getParentFile().mkdirs();
                    file.createNewFile();
                }
                IvParameterSpec iv = new IvParameterSpec(IV_PARAMETER.getBytes(CHARSET));
                Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
                cipher.init(Cipher.DECRYPT_MODE, generateKey(password), iv);
                InputStream is = new FileInputStream(srcFile);
                OutputStream out = new FileOutputStream(destFile);
                CipherOutputStream cos = new CipherOutputStream(out, cipher);
                byte[] buffer = new byte[1024];
                int r;
                while ((r = is.read(buffer)) >= 0) {
                    cos.write(buffer, 0, r);
                }
                cos.close();
                is.close();
                out.close();
                return destFile;
            } catch (Exception ex) {
                ex.printStackTrace();
            }
            return null;
        }
    }
    
    

    最后总结:

    这种DES对称加密在我们实战中用也是比较多的 在这里我就记录一下 文章参考了其他博主 但是那些博客是有缺陷的 在android 8.0下是不能使用的 我这边处理掉了,希望能帮助各位同学工作和学习 。如果觉得文章还不错希望能给我一个star 和转发

    相关文章

      网友评论

          本文标题:Android DES 加密的各种坑

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