最近在工作中,需要加密/解密一个数据文件,本来准备用目前的环境下的CA系统去加密/解密文件,无奈解密时厂商的Atach界面文件存在问题,通过咨询厂商也没有解决,最终只能直接解决;最后决定用普遍的DES加密解密文件;
在这里需要说一下,在开始加密时,读取一段文件流,然后通过DES标准加密,写入加密文件时,一定要紧跟着写入一个分隔符(如0x0A)。在解密的时候,根据分割符,分段读取字节流,然后解密,还原所有加密文件内容。
代码如下:
import java.security.SecureRandom;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
public class DES {
/**
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
String source = "System.out.println('加密完成')/;";
System.out.println("开始加密字符串:System.out.println('加密完成')/;");
String bytes = encrypt(source.getBytes());
System.out.println("encode bytes=" + bytes);
System.out.println("开始解密字符串:");
byte[] dbytes = decrypt(bytes.getBytes());
String dStr = new String(dbytes,"GBK");
System.out.println("dencode str=" + dStr);
}
private static final String PASSWORD_CRYPT_KEY = "xxx_xxxx";
private final static String DES = "DES";
/**
* 加密
* @param src 数据源
* @param key 密钥,长度必须是8的倍数
* @return 返回加密后的数据
* @throws Exception
*/
private static byte[] encrypt(byte[] src, byte[] key) throws Exception {
// DES算法要求有一个可信任的随机数源
SecureRandom sr = new SecureRandom();
// 从原始密匙数据创建DESKeySpec对象
DESKeySpec dks = new DESKeySpec(key);
// 创建一个密匙工厂,然后用它把DESKeySpec转换成一个SecretKey对象
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(DES);
SecretKey securekey = keyFactory.generateSecret(dks);
// Cipher对象实际完成加密操作
Cipher cipher = Cipher.getInstance(DES);
// 用密匙初始化Cipher对象
cipher.init(Cipher.ENCRYPT_MODE, securekey, sr);
// 现在,获取数据并加密正式执行加密操作
return cipher.doFinal(src);
}
/**
* 解密
* @param src 数据源
* @param key 密钥,长度必须是8的倍数
* @return 返回解密后的原始数据
* @throws Exception
*/
private static byte[] decrypt(byte[] src, byte[] key) throws Exception {
// DES算法要求有一个可信任的随机数源
SecureRandom sr = new SecureRandom();
// 从原始密匙数据创建一个DESKeySpec对象
DESKeySpec dks = new DESKeySpec(key);
// 创建一个密匙工厂,然后用它把DESKeySpec对象转换成一个SecretKey对象
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(DES);
SecretKey securekey = keyFactory.generateSecret(dks);
// Cipher对象实际完成解密操作
Cipher cipher = Cipher.getInstance(DES);
// 用密匙初始化Cipher对象
cipher.init(Cipher.DECRYPT_MODE, securekey, sr);
// 现在,获取数据并解密
// 正式执行解密操作
return cipher.doFinal(src);
}
/**
* 二进制转字符串
* @param b
* @return
*/
private static String byte2hex(byte[] b) {
String hs = "";
String stmp = "";
for (int n = 0; n < b.length; n++) {
stmp = (java.lang.Integer.toHexString(b[n] & 0xFF));
if (stmp.length() == 1)
hs = hs + "0" + stmp;
else
hs = hs + stmp;
}
return hs.toUpperCase();
}
private static byte[] hex2byte(byte[] b) {
if ((b.length % 2) != 0)
throw new IllegalArgumentException("DES解密字节长度不是偶数!");
byte[] b2 = new byte[b.length / 2];
for (int n = 0; n < b.length; n += 2) {
String item = new String(b, n, 2);
b2[n / 2] = (byte) Integer.parseInt(item, 16);
}
return b2;
}
/**
* 数据解密
* @param data
* @return
* @throws Exception
*/
public final static byte[] decrypt(byte[] bytes)throws Exception {
return decrypt(hex2byte(bytes),PASSWORD_CRYPT_KEY.getBytes());
}
/**
* 数据加密
* @param password
* @return
* @throws Exception
*/
public final static String encrypt(byte[] bytes) throws Exception{
return byte2hex(encrypt(bytes, PASSWORD_CRYPT_KEY.getBytes()));
}
}
/**
* 签名/验签名
*
* @author huangjun
*
*/
public class SignVerifyController {
public static void main(String[] args) {
String singfilepath = "C:\\2.txt";
try {
long begintimes = new Date().getTime();//
System.out.println("开始加密:");
signFile(singfilepath);
System.out.println("加密完成");
long endtimes = new Date().getTime();//
System.out.println("加密耗费:[" + (endtimes - begintimes) + "]ms");
begintimes = new Date().getTime();//
System.out.println("开始解密:");//
verifyFile(singfilepath);
System.out.println("解密完成");
endtimes = new Date().getTime();//
System.out.println("解密耗费:[" + (endtimes - begintimes) + "]ms");
} catch (CAClientException e) {
e.printStackTrace();
}
}
/**
* 临时文件后缀名
*/
public final static String sTmpFileExtend = ".tmp";
/**
* 文件后缀名
*/
public final static String sFileExtend = ".txt";
/**
* 加密文件
*
* @param signfilepath
* 原文件全路径
* @throws CAClientException
*/
public static void signFile(String signfilepath) throws CAClientException {
// CAClientUtil util = new CAClientUtil();
// String sDN = GlobalConfig.getInstance().getCadn();
// util.AttachSignEx(sDN,signfilepath,outfilepath);
try {
int beginindex = signfilepath.lastIndexOf(".");
String tempFile = signfilepath.substring(0, beginindex)
+ sTmpFileExtend;
FileInputStream fi = new FileInputStream(signfilepath);
FileOutputStream fo = new FileOutputStream(tempFile);
int nbytes = 1024 * 4;//1 cluster 4K
byte[] bytes = new byte[nbytes];
int nReads = fi.read(bytes, 0, nbytes);
while (nReads != -1) {
byte[] realBytes = new byte[nReads];
for(int i = 0;i < nReads;i++)
realBytes[i] = bytes[i];
String strEncodes = DES.encrypt(realBytes);
fo.write(strEncodes.getBytes());
fo.write(0x0A);
nReads = fi.read(bytes, 0, nbytes);
}
fo.flush();
fo.close();
fi.close();
File temp = new File(tempFile);
File realFile = new File(signfilepath);
realFile.delete();
temp.renameTo(realFile);
} catch (Exception e) {
throw new CAClientException(e.getLocalizedMessage());
}
}
/**
* 验签名文件
*
* @param signFilePath
* @throws CAClientException
* @throws CAServerException
*/
public static void verifyFile(String signFilePath) throws CAClientException {
// CAClientUtil util = new CAClientUtil();
// util.VerifyAttachedSignEx(signFilePath, outFileDir);
try {
int beginindex = signFilePath.lastIndexOf(".");
String tempFile = signFilePath.substring(0, beginindex)
+ sTmpFileExtend;
ReaderV1 reader = new ReaderV1(signFilePath);;
FileOutputStream fo = new FileOutputStream(tempFile);
reader.openStream();
byte[] bytes = null;
byte[] oribytes = null;
while ((bytes = reader.readLineBytes()) != null) {
if (reader.isBlankLine(bytes)) {
continue;
}
oribytes = DES.decrypt(bytes);
fo.write(oribytes);
}
fo.flush();
fo.close();
reader.closeStream();
File temp = new File(tempFile);
File realFile = new File(signFilePath);
realFile.delete();
temp.renameTo(realFile);
} catch (Exception e) {
throw new CAClientException(e.getLocalizedMessage());
}
}
}