是时候回到文件加密与解密的具体实现这个主题上来了。后续的举例均采用图片(包括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;
}
}