Android加解密篇AES

AES方式加解密

高级加密标准(Advanced Encryption Standard),对称秘钥加密算法之一。
对称加密,就是加密与揭秘用相同的密钥;非对称加密,公钥用于加密,私钥用于解谜数据。

1.需要用到密钥,密钥位数(默认256位).
2.秘钥的存储,如果秘钥存储在本地,通过反编译有可能被其他人获取.
解决办法:
1.用时从server端获取。
2.对秘钥加密后存储在本地,使用时再次的解密(还是会被破解,只是增加了破解的难度)。
3.加解密效率,如果对大文件整个文件加密,花费比较长的时间.
对于小于64KB的文件进行全加密,大于64KB的文件假面文件的前64KB内容,这样提高加密效率。
4.判断文件加密
为了能区分哪些文件加过密,避免二次加密造成的混乱,加密过的文件头部会写入八 个字符”^%!_$#@*”(已加密标示字符串)加以区分,该字符可自行定义.

下面代码使用第二种方法存储密钥,避免从server获取。

/**
*返回Cipher对象,文件加密解密使用到的对象
*ketCode:秘钥
*paramMode:加解密模式标识
*/
private Cipher getEncryptModeCipher(String keyCode, int paramMode) throws Exception {
      //该对象用于解密秘钥
        PackUtil packUtil = new PackUtil();
       //这里其实就是字符串“AES”,故弄玄虚增加破解解密的难度
        String algorithm = packUtil.decrypt(ALGORITHM);
        //创建一个秘钥规范对象,第一个参数为秘钥,第二个参数为算法,我们选用的是AES算法
        SecretKeySpec skeySpec = new SecretKeySpec(packUtil.decrypt(keyCode).getBytes(), algorithm);//
        // 创建密钥空间
        Cipher cipher = Cipher.getInstance(algorithm);
      //以下调用初始化方法指定操作模式,加密 or 解密
        switch (paramMode) {
            case ENCRY_FLAG:
                cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
                break;
            case DECRY_FALG:
                cipher.init(Cipher.DECRYPT_MODE, skeySpec);
                break;
            default:
                break;
        }
        return cipher;
    }

小于64K的文件,全部加密,加密后文件头部分内容为“^%!_$#@*”

FileInputStream input = new FileInputStream(fileIn);
FileOutputStream fos = new FileOutputStream(fileOut);
//文件可读字节数,总大小
int availableSize = input.available();
if (availableSize < 64 * 1024) {
          byte[] inBytes = new byte[availableSize]
         //向文件写入已加密的标示内容,可自行定义内容,与判断时一致即可
          fos.write("^%!_$#@*");
          int inLength = 0;
          //一次性读取文件的全部内容
          if ((inLength = input.read(inBytes)) != -1){
               //调用加密的接口传入内容参数
                byte[] outBytes = cipher.doFinal(inBytes, 0, inLength);
              //加密后的内容写入文件中
                fos.write(outBytes);
          }
        
}
fos.flush();
fos.close();
input.close();

大于64KB的文件,加密文件前64KB内容,加密后文件头部分内容为“^%!_$#@*”

int blockSize = 64 * 1024; 
byte[] inBytes = new byte[blockSize];
//读取文件前64KB大小
int inLength = input.read(inBytes);
fos.write("^%!_$#@*");
//调用加密接口,传入文件内容参数
byte[] outBytes = cipher.doFinal(inBytes); 
//加密后的内容写入到文件中
fos.write(outBytes, 0, outBytes.length);
//剩余的未加密的内容依次写入到文件中
byte[] bytes = new byte[100 * 1024];
while ((inLength = input.read(bytes)) != -1) {    
       fos.write(bytes, 0, inLength);
}
fos.flush();
fos.close();
input.close();

判断文件是否已加密

/**
*判断文件是否加密
*@param filePath 文件路径
*@return true 已加密 false 未加密
*@throws Exception
*/
public boolean isFileEncryption(String filePath) throws Exception {
        boolean bool = false;
        File file = new File(filePath);
        if (file.isFile()) {
            InputStream is = new FileInputStream(file);
            byte[] byt = new byte[8];
            //读取文件头部的已加密标示
            is.read(byt);
            is.close();
            String k = new String(byt);
            //这里的已加密标示"^%!_$#@*"与之前写入的要保持一致
            bool = ("^%!_$#@*".compareTo(k) == 0);
        }
        return bool;
}

小于64KB文件解密,需要完全解密

FileInputStream input = new FileInputStream(fileIn);
FileOutputStream fos = new FileOutputStream(fileOut);
int availableSize = input.available();
if (availableSize < 64 * 1024) {    
      //跳过文件头部的已加密标示字符串“^%!_$#@*”
      input.skip(8);
      //重新获取input大小
      availableSize = input.available();
     //读取的内容大小
      byte[] inBytes = new byte[availableSize];
      int inLength = 0;
      if ((inLength = input.read(inBytes)) != -1){
          //调用解密接口,与加密接口一样,cipher初始化的时候指定了操作模式
          byte[] outBytes = cipher.doFinal(inBytes, 0, inLength);
          //解密后的内容写入到文件中
          fos.write(outBytes);
      }
     
 }
fos.flush();
fos.close();
input.close();

大于64KB文件的解密,解密文件前64KB,为加密的依次读取出来。

//跳过文件头部的已加密标示字符串“^%!_$#@*”
input.skip(8);
//重新获取input大小
int availableSize = input.available();
//解密的内容大小
byte[] inBytes = new byte[availableSize];
//读取加密的内容
int inLength = input.read(inBytes);
if (inLength <= 64*1024) {    
     //调用解密的接口传入加密的内容
     byte[] outBytes = cipher.doFinal(inBytes);   
      //解密的内容写入到文件中
      fos.write(outBytes, 0, outBytes.length);
}
//把未加密的内容依次写入文件中
while ((inLength = input.read(bytes)) != -1) { 
     fos.write(bytes, 0, inLength);
}
fos.flush();
fos.close();
input.close();

加密解密接口的说明:

/**
*处理 input 缓冲区中从 inputOffset 开始(包含)的前 inputLen 个字节
*/
public final byte[]  doFinal (byte[] input, int inputOffset, int inputLen) throws 
IllegalBlockSizeException, BadPaddingException
/**
*处理 input 缓冲区中的字节
*/
public final byte[] doFinal (byte[] input) throws 
IllegalBlockSizeException, BadPaddingException

Cipher类API参考

    原文作者:IT枫
    原文地址: https://www.jianshu.com/p/bfa655bf172d
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞