Android加解密篇AES

AES方式加解密

高级加密标准(Advanced Encryption Standard),对称秘钥加密算法之一。
对称加密,就是加密与揭秘用相同的密钥;非对称加密,公钥用于加密,私钥用于解谜数据。
【Android加解密篇AES】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参考

    推荐阅读