美文网首页Android技术知识Android studio gradle技巧Android Other
android studio实现raw文件自动加密(AES加密)

android studio实现raw文件自动加密(AES加密)

作者: 阿怪Sir | 来源:发表于2018-05-09 17:00 被阅读71次

    本文将介绍android studio利用gradle进行raw资源文件加密的一种方式(所有代码均写在build.gradle中):

    第一步:首先要需要了解的是gradle打包监听器BuildListener的两个方法:
    • projectsEvaluated()方法执行在生成apk前: 所以在projectsEvaluated方法进行apk资源文件copy工作和加密工作。
    • buildFinished()方法执行在apk生成之后: 在buildFinished方法中进行加密资源文件的恢复和临时文件的删除工作(临时文件用于未加密代码的临时存储,打包结束后需要放会raw文件夹中)
    • 需copy如下代码:
      gradle.addBuildListener(new BuildListener() {
          @Override
          void buildStarted(Gradle gradle) {
              println "buildStarted"
          }
      
          @Override
          void settingsEvaluated(Settings settings) {
              println "settingsEvaluated"
      
          }
      
          @Override
          void projectsLoaded(Gradle gradle) {
              println "projectsLoaded"
      
          }
      
          @Override
          void projectsEvaluated(Gradle gradle) {
              println "projectsEvaluated"
              copyFolder(rawDir,tempDir)
              encodeDir(rawDir,aesKeyCommen)
          }
          @Override
          void buildFinished(BuildResult buildResult) {
              copyFolder(tempDir,rawDir);
              deleteAllFilesOfDir(tempDir);
          }
      })
      
    第二步:在build.gradle中实现上步骤的方法copyFolder,encodeDir,deleteAllFileofDir

    gradle打包兼容java代码,下面贴出这些方法的实现:

        //加密的资源文件路径
        def rawDir ='./app/src/main/res/raw/'
        //资源文件临时存储文件夹名称
        def tempDir ='./tempDir'
        //加密的key
        def aesKey = "\"abcdefgabcdefg12\""
        
        def aesKeyCommen = "abcdefgabcdefg12"
        
        //拷贝文件夹
        void copyFolder(String oldPath, String newPath) {
            try {
                (new File(newPath)).mkdirs(); //如果文件夹不存在 则建立新文件夹
                File a = new File(oldPath);
                String[] file = a.list();
                File temp = null;
                for (int i = 0; i < file.length; i++) {
                    if (oldPath.endsWith(File.separator)) {
                        temp = new File(oldPath + file[i]);
                    } else {
                        temp = new File(oldPath + File.separator + file[i]);
                    }
                    if (temp.isFile()) {
                        FileInputStream input = new FileInputStream(temp);
                        FileOutputStream output = new FileOutputStream(newPath + "/" +
                                (temp.getName()).toString());
                        byte[] b = new byte[1024 * 5];
                        int len;
                        while ((len = input.read(b)) != -1) {
                            output.write(b, 0, len);
                        }
                        output.flush();
                        output.close();
                        input.close();
                    }
                    if (temp.isDirectory()) {//如果是子文件夹
                        copyFolder(oldPath + "/" + file[i], newPath + "/" + file[i]);
                    }
                }
            }
            catch (Exception e) {
                println("复制整个文件夹内容操作出错");
                e.printStackTrace();
            }
        }
        
        //删除文件夹
        void deleteAllFilesOfDir(String path) {
            File file=new File(path);
            if (!file.exists())
                return;
            if (file.isFile()) {
                file.delete();
                return;
            }
            File[] files = file.listFiles();
            for (int i = 0; i < files.length; i++) {
                deleteAllFilesOfDir(files[i].getAbsolutePath());
            }
            file.delete();
        }
        
        //读取文件到string
        static String file2String(File file, String encoding) {
            InputStreamReader reader = null;
            StringWriter writer = new StringWriter();
            try {
                if (encoding == null || "".equals(encoding.trim())) {
                    reader = new InputStreamReader(new FileInputStream(file), encoding);
                } else {
                    reader = new InputStreamReader(new FileInputStream(file));
                }
                //将输入流写入输出流
                char[] buffer = new char[1024];
                int n = 0;
                while (-1 != (n = reader.read(buffer))) {
                    writer.write(buffer, 0, n);
                }
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            } finally {
                if (reader != null)
                    try {
                        reader.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
            }
            //返回转换结果
            if (writer != null)
                return writer.toString();
            else return null;
        }
        //加密算法
        private static byte[] encrypt(String content, String password) {
            try {
                byte[] keyStr = getKey(password);
                SecretKeySpec key = new SecretKeySpec(keyStr, "AES");
                Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");//algorithmStr
                byte[] byteContent = content.getBytes("utf-8");
                cipher.init(Cipher.ENCRYPT_MODE, key);//   ʼ
                byte[] result = cipher.doFinal(byteContent);
                return result; //
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            } catch (NoSuchPaddingException e) {
                e.printStackTrace();
            } catch (InvalidKeyException e) {
                e.printStackTrace();
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            } catch (IllegalBlockSizeException e) {
                e.printStackTrace();
            } catch (BadPaddingException e) {
                e.printStackTrace();
            }
            return null;
        }
        //解密算法
        private static byte[] decrypt(byte[] content, String password) {
            try {
                byte[] keyStr = getKey(password);
                SecretKeySpec key = new SecretKeySpec(keyStr, "AES");
                Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");//algorithmStr
                cipher.init(Cipher.DECRYPT_MODE, key);//   ʼ
                byte[] result = cipher.doFinal(content);
                return result; //
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            } catch (NoSuchPaddingException e) {
                e.printStackTrace();
            } catch (InvalidKeyException e) {
                e.printStackTrace();
            } catch (IllegalBlockSizeException e) {
                e.printStackTrace();
            } catch (BadPaddingException e) {
                e.printStackTrace();
            }
            return null;
        }
        
        private static byte[] getKey(String password) {
            byte[] rByte = null;
            if (password!=null) {
                rByte = password.getBytes();
            }else{
                rByte = new byte[24];
            }
            return rByte;
        }
        
        //二进制转16进制
        static String parseByte2HexStr(byte[] buf) {
            StringBuffer sb = new StringBuffer();
            for (int i = 0; i < buf.length; i++) {
                String hex = Integer.toHexString(buf[i] & 0xFF);
                if (hex.length() == 1) {
                    hex = '0' + hex;
                }
                sb.append(hex.toUpperCase());
            }
            return sb.toString();
        }
        
        static byte[] parseHexStr2Byte(String hexStr) {
            if (hexStr.length() < 1)
                return null;
            byte[] result = new byte[hexStr.length() / 2];
            for (int i = 0; i < hexStr.length() / 2; i++) {
                int high = Integer.parseInt(hexStr.substring(i * 2, i * 2 + 1), 16);
                int low = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2),
                        16);
                result[i] = (byte) (high * 16 + low);
            }
            return result;
        }
        
        //加密方法
        static String encodeContent(String content, String keyBytes){
            //加密之后的字节数组,转成16进制的字符串形式输出
            return parseByte2HexStr(encrypt(content, keyBytes));
        }
        
        //解密方法
        static String decodeContent(String content, String keyBytes){
            //解密之前,先将输入的字符串按照16进制转成二进制的字节数组,作为待解密的内容输入
            byte[] b = decrypt(parseHexStr2Byte(content), keyBytes);
            return new String(b);
        }
        
        //projectsEvaluated里调用的方法  aesKey: key  rawDir:加密的文件夹
        void encodeDir(String rawDir, String aesKey){
            println "do 加密代码"
            File searchPlug = new File(rawDir);
            if (searchPlug.exists() && searchPlug.isDirectory()) {
                print "文件夹存在"
                File[] files = searchPlug.listFiles()
                for (File file : files) {
                    if(!file.name.endsWith(".glsl")){
                        continue
                    }
                    String str=file2String(file,"utf-8")
                    def content = encodeContent(str, aesKey)
        //            def result = decodeContent(content, aesKey)
        //            println(" 原始文件:content"+str)
        //            println(" 加密后文件:content"+content)
        //            println(" 解密后文件:content"+result)
                    def stream = file.newOutputStream()
                    stream.write(content.bytes)
                    stream.flush()
                }
            }
        }
    
    第三步:在gradle和android程序中实现加密key的共享
    1. 在gradle文件中增加代码
            defaultConfig {
                 buildConfigField "String", "AES_KEY",aesKey
                }
    
    1. 在android代码中利用BuildConfig.AES_KEY获取build.gradle文件中配置的key。
    2. 注:在gradle文件中使用的key用def aesKeyCommen = "abcdefgabcdefg12"
      在 buildConfigField 里需要传入的String为: ""abcdefgabcdefg12""
      因为gradle生成java类时会默认省掉“”。
    第四步:android程序里解密

    1 . 新建工具类:

    public class AESUtils {
    
    
        private static byte[] encrypt(String content, String password) {
            try {
                byte[] keyStr = getKey(password);
                SecretKeySpec key = new SecretKeySpec(keyStr, "AES");
                Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");//algorithmStr
                byte[] byteContent = content.getBytes("utf-8");
                cipher.init(Cipher.ENCRYPT_MODE, key);//   ʼ
                byte[] result = cipher.doFinal(byteContent);
                return result; //
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            } catch (NoSuchPaddingException e) {
                e.printStackTrace();
            } catch (InvalidKeyException e) {
                e.printStackTrace();
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            } catch (IllegalBlockSizeException e) {
                e.printStackTrace();
            } catch (BadPaddingException e) {
                e.printStackTrace();
            }
            return null;
        }
    
        private static byte[] decrypt(byte[] content, String password) {
            try {
                byte[] keyStr = getKey(password);
                SecretKeySpec key = new SecretKeySpec(keyStr, "AES");
                Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");//algorithmStr
                cipher.init(Cipher.DECRYPT_MODE, key);//   ʼ
                byte[] result = cipher.doFinal(content);
                return result; //
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            } catch (NoSuchPaddingException e) {
                e.printStackTrace();
            } catch (InvalidKeyException e) {
                e.printStackTrace();
            } catch (IllegalBlockSizeException e) {
                e.printStackTrace();
            } catch (BadPaddingException e) {
                e.printStackTrace();
            }
            return null;
        }
    
        private static byte[] getKey(String password) {
            byte[] rByte = null;
            if (password!=null) {
                rByte = password.getBytes();
            }else{
                rByte = new byte[24];
            }
            return rByte;
        }
    
        /**
         * 将二进制转换成16进制
         * @param buf
         * @return
         */
        public static String parseByte2HexStr(byte buf[]) {
            StringBuffer sb = new StringBuffer();
            for (int i = 0; i < buf.length; i++) {
                String hex = Integer.toHexString(buf[i] & 0xFF);
                if (hex.length() == 1) {
                    hex = '0' + hex;
                }
                sb.append(hex.toUpperCase());
            }
            return sb.toString();
        }
    
        /**
         * 将16进制转换为二进制
         * @param hexStr
         * @return
         */
        public static byte[] parseHexStr2Byte(String hexStr) {
            if (hexStr.length() < 1)
                return null;
            byte[] result = new byte[hexStr.length() / 2];
            for (int i = 0; i < hexStr.length() / 2; i++) {
                int high = Integer.parseInt(hexStr.substring(i * 2, i * 2 + 1), 16);
                int low = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2),
                        16);
                result[i] = (byte) (high * 16 + low);
            }
            return result;
        }
    
        /**
         *加密
         */
        public static String encode(String content,String keyBytes){
            //加密之后的字节数组,转成16进制的字符串形式输出
            return parseByte2HexStr(encrypt(content, keyBytes));
        }
    
        /**
         *解密
         */
        public static String decode(String content,String keyBytes){
            //解密之前,先将输入的字符串按照16进制转成二进制的字节数组,作为待解密的内容输入
            byte[] b = decrypt(parseHexStr2Byte(content), keyBytes);
            return new String(b);
        }
    
       
    
    }
    

    2 . 读取raw资源文件,并进行解密

    public static String readShaderFromRawResource(final int resourceId) {
            final InputStream inputStream = CameraApplication.getInstance().getResources().openRawResource(
                    resourceId);
            final InputStreamReader inputStreamReader;
            try {
                inputStreamReader = new InputStreamReader(inputStream, "utf-8");
                final BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
                String nextLine;
                final StringBuilder body = new StringBuilder();
    
                try {
                    while ((nextLine = bufferedReader.readLine()) != null) {
                        body.append(nextLine);
                        body.append('\n');
                    }
                } catch (IOException e) {
                    return null;
                }
                //AESUtils.decode是解密方法,BuildConfig.AES_KEY,为gradle中配置的key
                String decrypt = AESUtils.decode(body.toString(), BuildConfig.AES_KEY);
                return decrypt;
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
            return "";
    
        }
    
    
    第五步:大功告成,解压生成的apk,然后查看raw资源文件

    可看到文件内容为3134141425425 的十六进制构成,而代码中的raw文件还是原来的代码,没有发生任何变化

    相关文章

      网友评论

      本文标题:android studio实现raw文件自动加密(AES加密)

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