是時候回到文件加密與解密的具體實現這個主題上來了。后續的舉例均采用圖片(包括GIF動畫)類型,而其他類型資源的實現原理相同,就不一一給出了。首先來看對一幅JPG類型圖片進行異或加密的Java實現,由於是第一次給出代碼,所以貼上了Java文件“FileEncAndDec.java”的所有內容。
1 import java.io.File; 2 import java.io.InputStream; 3 import java.io.OutputStream; 4 import java.io.FileInputStream; 5 import java.io.FileOutputStream; 6 7 public class FileEncAndDec { 8 private static final int numOfEncAndDec = 0x99; //加密解密秘鑰 9 private static int dataOfFile = 0; //文件字節內容 10 public static void main(String[] args) { 11 12 File srcFile = new File("桌面.jpg"); //初始文件 13 File encFile = new File("encFile.tif"); //加密文件 14 File decFile = new File("decFile.bmp"); //解密文件 15 16 try { 17 EncFile(srcFile, encFile); //加密操作 18 } catch (Exception e) { 19 e.printStackTrace(); 20 } 21 } 22 23 private static void EncFile(File srcFile, File encFile) throws Exception { 24 if(!srcFile.exists()){ 25 System.out.println("source file not exixt"); 26 return; 27 } 28 29 if(!encFile.exists()){ 30 System.out.println("encrypt file created"); 31 encFile.createNewFile(); 32 } 33 InputStream fis = new FileInputStream(srcFile); 34 OutputStream fos = new FileOutputStream(encFile); 35 36 while ((dataOfFile = fis.read()) > -1) { 37 fos.write(dataOfFile^numOfEncAndDec); 38 } 39 40 fis.close(); 41 fos.flush(); 42 fos.close(); 43 } 44 }
從代碼可以看出,給定的加密秘鑰(異或數據,可以在合法范圍內隨便定義)為十六進制數0x99。圖片資源為以中文命名的“桌面.jpg”,加密文件為“encFile.png”,還有值為“decFile.bmp”的String類對象作為解密文件名稱。
相對應地,解密的實現幾乎和加密相同,只是輸入與輸出文件不同,看下面代碼。
1 private static void DecFile(File encFile, File decFile) throws Exception { 2 if(!encFile.exists()){ 3 System.out.println("encrypt file not exixt"); 4 return; 5 } 6 7 if(!decFile.exists()){ 8 System.out.println("decrypt file created"); 9 decFile.createNewFile(); 10 } 11 12 InputStream fis = new FileInputStream(encFile); 13 OutputStream fos = new FileOutputStream(decFile); 14 15 while ((dataOfFile = fis.read()) > -1) { 16 fos.write(dataOfFile^numOfEncAndDec); 17 } 18 19 fis.close(); 20 fos.flush(); 21 fos.close(); 22 }
由於加密后的圖片文件(保存為PNG類型)是不能直接在圖片查看器中打開的,因為其內容已經改變,所以其縮略圖標會顯示為兩朵不同顏色的花。對於其他類型的加密或損壞文件的縮略圖標:JPG為山水畫,BMP和TIF為畫刷塗鴉,GIF為三個不同顏色的幾何圖形。當然,這些默認的圖標應該會因系統而異。
下面給出初始、加密及解密后的圖標截圖:
和預想的一致,經測試發現以上方法對GIF動畫(不是GIF圖片,而是可以播放的動畫資源)的加密與解密同樣適用,代碼和截圖也就沒有區別了,不過還是貼上來:
1 File srcFile = new File("srcFile.gif"); //初始文件 2 File encFile = new File("encFile.gif"); //加密文件 3 File decFile = new File("decFile.gif"); //解密文件
有兩點需要注意:
1、在調用加密與解密方法時,必須加上異常處理塊(try{...}catch{...},否則編譯不通過)。
2、對用來加密或解密的源文件進行打開(讀取)操作之前,最好判斷其是否存在,免得造成意想不到的錯誤和時間的浪費。因為若文件不存在,后續的操作都是沒有意義的。
今天就先寫到這,總結一下吧。文件加密簡單地說就是對數據進行變換,雖然一千種方法可能會有一千種一種結果,但是思想是通用的。關鍵是加密所采用的算法的難易,有時間會對文中提到的算法用Java進行
---------------------------------------------------------------------------------------------------------
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.RandomAccessFile;
public class FileEncryptAndDecrypt {
public static void main(String[] args) throws Exception {
String filename = "奔馬.avi";
String flag = readFileLastByte("c:\\" + filename, 6);
if (flag.indexOf("hello") > 0) {
// 加密過了;
} else {
// 沒有加密
new FileEncryptAndDecrypt().encrypt("c:\\" + filename, "hello");
}
System.out.println(new FileEncryptAndDecrypt().decrypt("c:\\"
+ filename, "c:\\" + filename, 6));
// System.out.println(readFileLastByte("c:\\3.jpg", 6));
}
/**
* 文件file進行加密
*
* @param fileUrl
* 文件路徑
* @param key
* 密碼
* @throws Exception
*/
public static void encrypt(String fileUrl, String key) throws Exception {
File file = new File(fileUrl);
String path = file.getPath();
if (!file.exists()) {
return;
}
int index = path.lastIndexOf("\\");
String destFile = path.substring(0, index) + "\\" + "abc";
System.out.println(destFile);
File dest = new File(destFile);
InputStream in = new FileInputStream(fileUrl);
OutputStream out = new FileOutputStream(destFile);
byte[] buffer = new byte[1024];
int r;
byte[] buffer2 = new byte[1024];
while ((r = in.read(buffer)) > 0) {
for (int i = 0; i < r; i++) {
byte b = buffer[i];
buffer2[i] = b == 255 ? 0 : ++b;
}
out.write(buffer2, 0, r);
out.flush();
}
in.close();
out.close();
file.delete();
dest.renameTo(new File(fileUrl));
appendMethodA(fileUrl, key);
System.out.println("加密成功");
}
/**
*
* @param fileName
* @param content
* 密鑰
*/
public static void appendMethodA(String fileName, String content) {
try {
// 打開一個隨機訪問文件流,按讀寫方式
RandomAccessFile randomFile = new RandomAccessFile(fileName, "rw");
// 文件長度,字節數
long fileLength = randomFile.length();
// 將寫文件指針移到文件尾。
randomFile.seek(fileLength);
randomFile.writeBytes(content);
randomFile.close();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 解密
*
* @param fileUrl
* 源文件
* @param tempUrl
* 臨時文件
* @param ketLength
* 密碼長度
* @return
* @throws Exception
*/
public static String decrypt(String fileUrl, String tempUrl, int keyLength)
throws Exception {
File file = new File(fileUrl);
if (!file.exists()) {
return null;
}
File dest = new File(tempUrl);
if (!dest.getParentFile().exists()) {
dest.getParentFile().mkdirs();
}
InputStream is = new FileInputStream(fileUrl);
OutputStream out = new FileOutputStream(tempUrl);
byte[] buffer = new byte[1024];
byte[] buffer2 = new byte[1024];
byte bMax = (byte) 255;
long size = file.length() - keyLength;
int mod = (int) (size % 1024);
int div = (int) (size >> 10);
int count = mod == 0 ? div : (div + 1);
int k = 1, r;
while ((k <= count && (r = is.read(buffer)) > 0)) {
if (mod != 0 && k == count) {
r = mod;
}
for (int i = 0; i < r; i++) {
byte b = buffer[i];
buffer2[i] = b == 0 ? bMax : --b;
}
out.write(buffer2, 0, r);
k++;
}
out.close();
is.close();
return tempUrl;
}
/**
* 判斷文件是否加密
*
* @param fileName
* @return
*/
public static String readFileLastByte(String fileName, int keyLength) {
File file = new File(fileName);
if (!file.exists())
return null;
StringBuffer str = new StringBuffer();
try {
// 打開一個隨機訪問文件流,按讀寫方式
RandomAccessFile randomFile = new RandomAccessFile(fileName, "r");
// 文件長度,字節數
long fileLength = randomFile.length();
// 將寫文件指針移到文件尾。
for (int i = keyLength; i >= 1; i--) {
randomFile.seek(fileLength - i);
str.append((char) randomFile.read());
}
randomFile.close();
return str.toString();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}