android中對文件加密解密的實現(xiàn)
現(xiàn)在項目里面有一個需求,本項目里面下載的視頻和文檔都不允許通過其他的播放器播放,在培訓(xùn)機構(gòu)里面這樣的需求很多。防止有人交一份錢,把所有的課件就拷給了別人。這樣的事情培訓(xùn)機構(gòu)肯定是不愿意的。現(xiàn)在我項目里面也出了這么個需求。下面介紹一下我的實現(xiàn)。
文件加解密的流程及原理
1、加密方法:存儲文件時,從輸入流中截取文件的字節(jié)數(shù)組,對字節(jié)數(shù)組進行加密,至于加密的方式和算法就可以視需求而定了,然后把加密后的字節(jié)數(shù)組寫入到文件中,最后生成加密后的文件;
2、解密方法:同加密方法一樣,只不過是對字節(jié)數(shù)據(jù)進行解密,最后生成明文文件;
3、加密算法:Android系統(tǒng)本身引入了javax包的Cipher類,這個類里提供了各種各樣的通用的加密方式,如AES對稱加密等;該程序中有個CipherUtil工具類,里面有一些簡單的使用Cipher進行AES加解密的方法;當(dāng)然最好還是好好學(xué)習(xí)一下Cipher類的使用;
4、注意事項:
- 如何判斷一個文件是加密后的文件,最簡單的方法就是對加密后的文件統(tǒng)一增加一個后綴名,然后在解密之后將這個后綴名去除,還原回原有文件格式;如:密文文件的統(tǒng)一后綴名為“.cipher”,明文文件名為"測試.txt",加密后的密文文件應(yīng)該為“測試.txt.cipher”;
- 加密文件時還有一個重要的注意事項,就是加密后的密文和明文的長度是否相同,如果文件時一次讀取出所有字節(jié)數(shù)組進行加密的話不用擔(dān)心這個問題,但是當(dāng)對文件分次讀取加密或分段加密的話,就不得不考慮這個問題了,最方便的方法就是保證明文和加密后的密文長度相同;如果長度不同,由于是分段加密的,密文是由一段一段子密文拼接成的,解密時會找不到每段子密文,因為不知道每段子密文的長度是多少;
主要代碼
/**自定義實現(xiàn)簡單的文件加密解密工具
* Created by zhangshuo on 2016/6/28.
*/
public class CustomFileCipherUtil {
/**
* 加密后的文件的后綴
*/
public static final String CIPHER_TEXT_SUFFIX = ".cipher";
/**
* 加解密時以32K個字節(jié)為單位進行加解密計算
*/
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();
}
//對余數(shù)部分加密
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結(jié)尾才會認(rèn)為其實可解密密文
* @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)){
// //后綴不同,認(rèn)為是不可解密的密文
// 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();
}
//對余數(shù)部分解密
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;
}
}
/**
* 用于加解密進度的監(jiān)聽器
*/
public interface CipherListener{
void onProgress(long current, long total);
}
}
效果如圖:

代碼就是這么多,都有注釋。以后再有這種需求可以直接用。以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android?webView加載數(shù)據(jù)時內(nèi)存溢出問題及解決
這篇文章主要介紹了Android?webView加載數(shù)據(jù)時內(nèi)存溢出問題及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-12-12
Pagerslidingtabstrip菜單標(biāo)題欄制作方法
這篇文章主要為大家詳細(xì)介紹了Pagerslidingtabstrip菜單標(biāo)題欄的制作方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-10-10
Android TreeView實現(xiàn)帶復(fù)選框樹形組織結(jié)構(gòu)
這篇文章主要為大家詳細(xì)介紹了Android TreeView實現(xiàn)帶復(fù)選框樹形組織結(jié)構(gòu),文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2019-07-07
android studio編譯jar包或者aar包的方法教程詳解
這篇文章主要介紹了android studio編譯jar包或者aar包的方法教程,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-03-03
讓Android應(yīng)用不被殺死(killer)的方法
這篇文章主要介紹了讓Android應(yīng)用不被殺死(killer)的方法,本文講解了實現(xiàn)方法和原理分析,需要的朋友可以參考下2015-04-04
詳解Android XML中引用自定義內(nèi)部類view的四個why
本篇文章主要介紹了詳解Android XML中引用自定義內(nèi)部類view,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。2016-12-12
Android 動畫之RotateAnimation應(yīng)用詳解
本節(jié)講解旋轉(zhuǎn)動畫效果RotateAnimation方法的應(yīng)用,有需要的朋友可以參考下2012-12-12
Flexbox+ReclyclerView實現(xiàn)流式布局
這篇文章主要為大家詳細(xì)介紹了Flexbox+ReclyclerView實現(xiàn)流式布局,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-11-11

