檔案加解密的流程及原理
1、加密方法:存儲檔案時,從輸入流中截取檔案的位元組數組,對位元組數組進行加密,至于加密的方式和算法就可以視需求而定了,然後把加密後的位元組數組寫入到檔案中,最後生成加密後的檔案;
2、解密方法:同加密方法一樣,隻不過是對位元組資料進行解密,最後生成明文檔案;
3、加密算法:android系統本身引入了javax包的Cipher類,這個類裡提供了各種各樣的通用的加密方式,如AES對稱加密等;該程式中有個CipherUtil工具類,裡面有一些簡單的使用Cipher進行AES加解密的方法;當然最好還是好好學習一下Cipher類的使用;
4、注意事項:
a、如何判斷一個檔案是加密後的檔案,最簡單的方法就是對加密後的檔案統一增加一個字尾名,
然後在解密之後将這個字尾名去除,還原回原有檔案格式;
如:密文檔案的統一字尾名為“.cipher”,明文檔案名為"測試.txt",加密後的密文檔案應該為“測試.txt.cipher”;
b、加密檔案時還有一個重要的注意事項,就是加密後的密文和明文的長度是否相同,
如果檔案時一次讀取出所有位元組數組進行加密的話不用擔心這個問題,
但是當對檔案分次讀取加密或分段加密的話,就不得不考慮這個問題了,最友善的方法就是保證明文和加密後的密文長度相同;
如果長度不同,由于是分段加密的,密文是由一段一段子密文拼接成的,
解密時會找不到每段子密文,因為不知道每段子密文的長度是多少;
主要代碼
/**自定義實作簡單的檔案加密解密工具
* Created by zhangshuo on 2016/6/28.
*/
public class CustomFileCipherUtil {
/**
* 加密後的檔案的字尾
*/
public static final String CIPHER_TEXT_SUFFIX = ".cipher";
/**
* 加解密時以32K個位元組為機關進行加解密計算
*/
private static final int CIPHER_BUFFER_LENGHT = 32 * 1024;
/**
* 加密,這裡主要是示範加密的原理,沒有用什麼實際的加密算法
*
* @param filePath 明文檔案絕對路徑
* @return
*/
public static boolean encrypt(String filePath, CipherListener listener) {
try {
long startTime = System.currentTimeMillis();
File f = new File(filePath);
RandomAccessFile raf = new RandomAccessFile(f, "rw");
long totalLenght = raf.length();
FileChannel channel = raf.getChannel();
long multiples = totalLenght / CIPHER_BUFFER_LENGHT;
long remainder = totalLenght % CIPHER_BUFFER_LENGHT;
MappedByteBuffer buffer = null;
byte tmp;
byte rawByte;
//先對整除部分加密
for(int i = 0; i < multiples; i++){
buffer = channel.map(
FileChannel.MapMode.READ_WRITE, i * CIPHER_BUFFER_LENGHT, (i + 1) * CIPHER_BUFFER_LENGHT);
//此處的加密方法很簡單,隻是簡單的異或計算
for (int j = 0; j < CIPHER_BUFFER_LENGHT; ++j) {
rawByte = buffer.get(j);
tmp = (byte) (rawByte ^ j);
buffer.put(j, tmp);
if(null != listener){
listener.onProgress(i * CIPHER_BUFFER_LENGHT + j, totalLenght);
}
}
buffer.force();
buffer.clear();
}
//對餘數部分加密
buffer = channel.map(
FileChannel.MapMode.READ_WRITE, multiples * CIPHER_BUFFER_LENGHT, multiples * CIPHER_BUFFER_LENGHT + remainder);
for (int j = 0; j < remainder; ++j) {
rawByte = buffer.get(j);
tmp = (byte) (rawByte ^ j);
buffer.put(j, tmp);
if(null != listener){
listener.onProgress(multiples * CIPHER_BUFFER_LENGHT + j, totalLenght);
}
}
buffer.force();
buffer.clear();
channel.close();
raf.close();
//對加密後的檔案重命名,增加.cipher字尾
// f.renameTo(new File(f.getPath() + CIPHER_TEXT_SUFFIX));
Log.d("加密用時:", (System.currentTimeMillis() - startTime) /1000 + "s");
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 解密,這裡主要是示範加密的原理,沒有用什麼實際的加密算法
*
* @param filePath 密文檔案絕對路徑,檔案需要以.cipher結尾才會認為其實可解密密文
* @return
*/
public static boolean decrypt(String filePath, CipherListener listener) {
try {
long startTime = System.currentTimeMillis();
File f = new File(filePath);
// if(!f.getPath().toLowerCase().endsWith(CIPHER_TEXT_SUFFIX)){
// //字尾不同,認為是不可解密的密文
// return false;
// }
RandomAccessFile raf = new RandomAccessFile(f, "rw");
long totalLenght = raf.length();
FileChannel channel = raf.getChannel();
long multiples = totalLenght / CIPHER_BUFFER_LENGHT;
long remainder = totalLenght % CIPHER_BUFFER_LENGHT;
MappedByteBuffer buffer = null;
byte tmp;
byte rawByte;
//先對整除部分解密
for(int i = 0; i < multiples; i++){
buffer = channel.map(
FileChannel.MapMode.READ_WRITE, i * CIPHER_BUFFER_LENGHT, (i + 1) * CIPHER_BUFFER_LENGHT);
//此處的解密方法很簡單,隻是簡單的異或計算
for (int j = 0; j < CIPHER_BUFFER_LENGHT; ++j) {
rawByte = buffer.get(j);
tmp = (byte) (rawByte ^ j);
buffer.put(j, tmp);
if(null != listener){
listener.onProgress(i * CIPHER_BUFFER_LENGHT + j, totalLenght);
}
}
buffer.force();
buffer.clear();
}
//對餘數部分解密
buffer = channel.map(
FileChannel.MapMode.READ_WRITE, multiples * CIPHER_BUFFER_LENGHT, multiples * CIPHER_BUFFER_LENGHT + remainder);
for (int j = 0; j < remainder; ++j) {
rawByte = buffer.get(j);
tmp = (byte) (rawByte ^ j);
buffer.put(j, tmp);
if(null != listener){
listener.onProgress(multiples * CIPHER_BUFFER_LENGHT + j, totalLenght);
}
}
buffer.force();
buffer.clear();
channel.close();
raf.close();
//對加密後的檔案重命名,增加.cipher字尾
// f.renameTo(new File(f.getPath().substring(f.getPath().toLowerCase().indexOf(CIPHER_TEXT_SUFFIX))));
Log.d("解密用時:", (System.currentTimeMillis() - startTime) / 1000 + "s");
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 用于加解密進度的監聽器
*/
public interface CipherListener{
void onProgress(long current, long total);
}
}
截圖
Demo下載下傳位址:
https://github.com/ZhangSir/TestCipher