一种基于随机数组so库的Android数据资源硬加密方法 草稿

版权声明:本文为博主原创文章,请转载时注明出处,欢迎浏览! https://blog.csdn.net/leemboy/article/details/79037745

一种基于随机数组so库的Android数据资源硬加密方法

作者:AniO软件咨询服务,天涯来客-Leemboy


摘要:本文提供一种简洁的Android数据资源硬加密方案,利用随机数组so静态库,对Android应用的Res资源,Assets资源文件数据按顺序进行随机加密,对Android应用开发者的数据资源进行保护,增加数据资源的破解难度。

1、     算法背景

对于数据资源毫无加密的Android应用来说,要从其app下载包中获取Res和Assets资源数据相当简单。对与数据资源没有加密的APK包,直接把文件扩展名apk改成zip,让后用解压软件解压后,进入解压文件夹下,就容易轻松获取到Assets和Res目录下的文件。

2、     随机数组生成方案

随机数组元素数量自定义。我们直接给出java代码如下:

 

public class randomGenerator {

//定义数组的最大元素数目

     public final static int MAX_NUM=128;

 

     public static void main(String[] argsthrows IOException

     {

          int max=65535;//随机数最大值

          int min=1024;//随机数最小值

          int[] metrixInt=newint[128];

         Random random =new Random();   

         String content="";

          for(int i=0;i<MAX_NUM;i++){

//生成随机数

               metrixInt[i]=random.nextInt(max)%(max-min+1) + min;

               System.out.println("\""+metrixInt[i]+"\",");

               content=content+Integer.toString(metrixInt[i])+"\n";

          }

         

     }

3、批量数据资源加密方案

3.1加密步骤:

一、 把待加密批量源文件拷贝到源文件目录,具体路径见代码分析;

二、 执行加密程序

三、 加密后的文件自动存入目标目录。

3.2加密算法代码及分析:

注:以下代码在Eclipse中调试运行通过。

package net.lingw.leemboy.encription;

import java.io.*;

public class imageInc {

/**

@param args

@throws IOException

*/

//随机数组最大数量

     public  final static int MAX_RAND=128;

 

//定义目录初始路径深度,从根目录开始遍历

     private static in depth =1;

 

//代码主函数

     public static void main(String[] argsthrows IOException

     {

          //定义待加密的文件路径

          Strings fileDir=System.getProperty ("user.home") +"/eclipse/workspace/EncImage/image/";

 

          //定义加密后的文件存放路径

          String  dfileDir=System.getProperty ("user.home") +"/eclipse/workspace/EncImage/enc_image/";

 

          //执行加密函数

          find(sfileDir,dfileDir,depth);

     }

     

       

//这是个递归函数,遍历源文件路径,找出所有文件,执行加密算法

//参数1:源文件目录路径

//参数2:目标文件目录路径

//参数3:路径深度

         public static void find(String pathName,String destPathName,int depth)throwsIOException

         { 

               //设置初始文件数目

             int filecount=0; 

            

//获取pathName路径的File对象 

             File dirFile =new File(pathName); 

 

             //判断该文件或目录是否存在,不存在时在控制台输出提醒 

             if (!dirFile.exists()) { 

                 System.out.println("do not exit"); 

                 return ; 

             } 

 

             //判断如果不是一个目录,就判断是不是一个文件,是文件则输出文件路径 

             if (!dirFile.isDirectory()){ 

                 if (dirFile.isFile()) { 

//如果是文件,就输出文件及路径

                     System.out.println(dirFile.getCanonicalFile()); 

                 } 

                 return ; 

             } 

              

               //显示文件树结构

             for (int j = 0; j < depthj++) { 

                 System.out.print(" "); 

             } 

             System.out.print("|--"); 

             System.out.println(dirFile.getName()); 

 

             //获取此目录下的所有文件名与目录名 

             String[] fileList =dirFile.list(); 

 

               //当前深度更新

             int currentDepth=depth+1; 

 

               //遍历文件目录 

             for (int i = 0; i < fileList.length;i++) { 

                 String string =fileList[i]; 

                 //File("documentName","fileName")File的另一个构造器 

                 File file =new File(dirFile.getPath(),string); 

                 String name =file.getName(); 

                 //如果是一个目录,搜索深度depth++,输出目录名后,进行递归 

                 if (file.isDirectory()){ 

                     //如果是目录,继续执行递归函数 

                     find(file.getCanonicalPath(),destPathName,currentDepth); 

                 }else

                     //如果是文件,则以树形结构输出文件名,并对文件执行加密函数

                     for (int j = 0; j < currentDepthj++) {  

                         System.out.print("  "); 

                     } 

                     System.out.print("|--");  //树形线

                     System.out.println(name); //加密文件名

                     

//执行加密函数    

                     encriptionImage(name,pathName,destPathName);  

                 } 

             } 

         }

         /***********************************************/

//加密函数

 //参数1:待加密文件名;

//参数2:待加密文件路径名;

//参数3:加密后文件存储路径。

/***********************************************/

         public static void  encriptionImage(String fileName,String fromDir,String toDir)

         {

           try{

                          String  source=fromDir+fileName;

                          String dest=toDir+fileName;

 

                          //源文件对象,即指向待加密文件

                          File inFile =new File(source);

 

                          //目标文件对象,即指向加密后的文件

                          File outFile = new File(dest);

                          //源文件输入流

FileInputStream input =new FileInputStream(inFile);

                         

                          //目标文件输入流

FileOutputStream output =new FileOutputStream(outFile);

                          int content = 0;//该数据是用来存储读取到的数据,以整数形式存储

 

                          //定义加密随机数组索引初始值

                          int index=0;

                          while((content =input.read())!= -1)

                          {//如果没有到文件的末尾,那么继续读取数据

                              

                               //按模余原则顺序从随机数组中获取当前加密随机数,

                               int rand=getRandnum(index%MAX_RAND);

                              

                               //对文件中当前取到的内容执行异或运算,当然也可以执行其他运算。

                               //执行其他运算时,要在解密时执行对应的逆运算,

//加密后的数据写入输出文件。

                               output.write(content^rand);

                               index++;

                               if(index==MAX_RAND){

                                    index=0;//随机数组已达上限,复位索引值。

                               }

                          }

                          //执行完加密后,关闭资源

                          output.close();

                          input.close();

                }catch (FileNotFoundExceptione) {

                      e.printStackTrace();

                      return;

                }catch (IOExceptione) {

                      e.printStackTrace();

                      return;

                }

         }

 

          //取随机数函数,参数:随机数索引

          public static int getRandnum(int i){

           int rand=0;

           String[] randArray ={"6659",

                      "39643",

                      "29006",

                      "61162",

                //…… … … …

};

           if(i<0 || i> MAX_RAND){

                return 0;

           }

           rand=Integer.valueOf(randArray[i]);

           return rand;

         }

 

3.3 加密算法执行效果

左边列是加密随机数组部分内容,右边列是加密过程中加密文件显示过程

    

 

4、加密矩阵存储方案

     为了实现简单,这里把加密数组存储在Android工程的so静态库中,由于So静态库是采用C语言编程模式,在Android项目编译中,C语言静态库被编译成二进制文件,对于一般的编程人员来说,二进制文件破解具有一定复杂性,笔者认为,对于普通应用,这种加密方案已经能够较有效的保护数据。So静态库中加密数组存储形式如下。

Java_net_lingw_leemboy_babylearnenglish2_DetailMainActivity_rnum(
        
JNIEnv* env,
        
jobject /* this */) {
    
std::string str =
            
"6659\n"
             "39643
\n"
            "29006
\n"
            "61162
\n"
            "44305
\n"
            "10893
\n"
            "53718
\n"

//。。。。。。。。。。。。。。。。。

                       54363";
    
return 
env->NewStringUTF(str.c_str());
}

 

5、资源文件读取及解密方案

Android应用文件如下:

package net.lingw.leemboy.babylearnenglish2;
//。。。  。。。
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
//。。。   。。。
public class DetailMainActivity extends AppCompatActivity 
{
        //解密后的图片资源在ImageButton  中显示
        ImageButton  pictureButton;

    //定义随机数组大小
        public final static int MAX_RAND_NUM=128;
        //存放随机数组
        public int[] randArray=new int[MAX_RAND_NUM];

    static {
        //加载静态库
        System.loadLibrary("native-lib");
    }
/*******************************************************/
   //申明静态库中的函数
        //静态库里有很多函数,这里只列出取随机数组函数
        //随机数组以字符串形式存储
    public native String rnum();
/*******************************************************/
//取随机数函数
    private void createRandArray()
        {
        String str=rnum();
        String[] strArray=str.trim().split(separatorEnter);
 
//随机数组字符串è整数格式
        for(int i=0;i<MAX_RAND_NUM;i++)
                        {
                                     randArray[i]=Integer.valueOf(strArray[i].trim());
                 }
}

/*******************************************************/

//读取Assets图像资源,并用随机数组解密和显示

//参数:Assets图像资源名称

void showAssetsImage(String image){
        String tempFile="temp.jpg";//
存放临时文件
        try
        
{
            // 
获取资源文件内容到输入流
            
InputStreamims = getAssets().open(image);
           

//定义输出数据流,并与输出文件关联

OutputStreamoms=new ObjectOutputStream(newFileOutputStream(new File(getFilesDir(),"")+File.separator+tempFile));

//输出文件的全路径格式为:/文件路径字符串/ tempFile
   

//以整数格式存放读取到的加密数据内容

   int content =0
   
int index=
0;
   while((content = ims.read())!= 
-1)
   

//如果没有到文件的末尾,那么继续读取数据
    //
加密数据与随机数组异或运算解密,并写到输出流

oms.write(content^randArray[index%MAX_RAND_NUM]);
                index++;
                if(index==MAX_RAND_NUM){

//如果随机数组已取完,索引值复位到初始位置
                    index=
0;
                }
            }
//
解密完数据,关闭输出流

oms.close();

 

//创建显示图像的输入流

Input Streaminput=new ObjectInputStream(new FileInputStream(new File(getFilesDir(),"")+File.separator+tempFile));
//
图像文件完整名称为:/文件路径/ tempFile
//
输入流转换为Drawable资源,这里的Drawable变量名为d

Drawable d =Drawable.createFromStream(input,null);
            // 
ImageView中显示Drawable资源
            
pictureButton.setImageDrawable(d);
            

                                            //文件输出后关闭所有的流变量

        input.close();
        ims.close();
        }
        catch(IOException ex)
        {
            return;
        }
    }
}

 /**********************************************/

  //加密后的图像资源存放在下列位置

 

6、加密效果和运行效果展示

加密后文件数据格式已经打乱,无法通过官方工具显示,说明已达到加密目的。

 

通过随机数组解密后的显示结果如下。

 

 

7、总结

    本算法对普通应用开发者的资源能进行有效的保护,并且算法易实现,操作简单。对非专业人员来说,破解有一定困难。另外该算法除了可以保护图像数据,也可以保护各种文档、媒体等文件。

    此外随机数组粗放在so库中,需要在工程编译时对java代码部分做简单混淆,起到对java代码保护并防止获取so库内容。

猜你喜欢

转载自blog.csdn.net/leemboy/article/details/79037745