jdk 自带文件加解密(包含xlsx上传fastdfs后文件损坏处理方案)
为了文件在服务器中的存放安全,需要对文件进行加密,(此处不讨论系统安全、应用安全问题),原理很简单,就不赘述。简单实现方案如:github fileCode
package com.***.util;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
/**
* 文件加/解密
*
* @see https://my.oschina.net/iyinghui/blog/1805949
* @author wang.xinyu
*/
public class FileSercet {
private static String key = "$5wI6=";
public static final String postfix = ".crypt";
/**
* 根据参数生成KEY
*/
public static Key getKey() {
try {
KeyGenerator _generator = KeyGenerator.getInstance("DES");
// _generator.init(new SecureRandom(strKey.getBytes()));这种方式,在windows可以,可是在linux每次生成的key不一样
SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
secureRandom.setSeed(key.getBytes());
_generator.init(secureRandom);
Key key = _generator.generateKey();
_generator = null;
// System.out.println(key);
return key;
} catch (Exception e) {
throw new RuntimeException("Error initializing SqlMap class. Cause: " + e);
}
}
/**
* 流数据加密
*
* @author wang.xinyu
* @param is
* @return CipherInputStream
* @throws Exception
*/
public static InputStream EncFile(InputStream is) throws Exception {
Cipher cipher = Cipher.getInstance("DES");
cipher.init(Cipher.ENCRYPT_MODE, getKey());
return new CipherInputStream(is, cipher);
}
/**
* 流数据解密
*
* @param is
* @return CipherInputStream
* @throws NoSuchPaddingException
* @throws NoSuchAlgorithmException
* @throws InvalidKeyException
* @throws IOException
* @throws Exception
*/
public static void DecFile(InputStream is, OutputStream out) throws Exception {
Cipher cipher = Cipher.getInstance("DES");
cipher.init(Cipher.DECRYPT_MODE, getKey());
try (CipherOutputStream cos = new CipherOutputStream(out, cipher);) {
byte[] buffer = new byte[1024];
int r;
while ((r = is.read(buffer)) >= 0) {
cos.write(buffer, 0, r);
}
cos.flush();
}
}
/**
* 加密
*
* @param srcFile
* 要加密的文件
* @param encFile
* 加密后的文件
* @param key
* 密钥
* @throws Exception
* 异常
*/
public static void EncFile(File srcFile, File encFile) throws Exception {
// 检查是否存在
if (!srcFile.exists()) {
System.out.println("source file not exixt");
return;
}
if (!encFile.exists()) {
System.out.println("encrypt file created");
encFile.createNewFile();
}
Cipher cipher = Cipher.getInstance("DES");
// cipher.init(Cipher.ENCRYPT_MODE, getKey());
cipher.init(Cipher.ENCRYPT_MODE, getKey());
InputStream is = new FileInputStream(srcFile);
OutputStream out = new FileOutputStream(encFile);
CipherInputStream cis = new CipherInputStream(is, cipher);
byte[] buffer = new byte[1024];
int r;
while ((r = cis.read(buffer)) > 0) {
out.write(buffer, 0, r);
}
cis.close();
is.close();
out.close();
}
/**
* 解密
*
* @param encFile
* 加密了的文件
* @param decFile
* 要解密生成的文件
* @param key
* 密钥
* @throws Exception
* 异常
*/
public static void DecFile(File encFile, File decFile) throws Exception {
if (!encFile.exists()) {
System.out.println("encrypt file not exixt");
return;
}
if (!decFile.exists()) {
System.out.println("decrypt file created");
decFile.createNewFile();
}
Cipher cipher = Cipher.getInstance("DES");
cipher.init(Cipher.DECRYPT_MODE, getKey());
InputStream is = new FileInputStream(encFile);
OutputStream out = new FileOutputStream(decFile);
CipherOutputStream cos = new CipherOutputStream(out, cipher);
byte[] buffer = new byte[1024];
int r;
while ((r = is.read(buffer)) >= 0) {
cos.write(buffer, 0, r);
}
cos.close();
out.close();
is.close();
}
/**
* 测试类
*
* @param args
* 参数
*/
public static void main(String[] args) {
File srcFile = new File("E:\\fas\\FileCode.java"); // 初始文件
File encFile = new File("E:\\fas\\FileCode_enc" + postfix); // 加密文件
File decFile = new File("E:\\fas\\FileCode_dec.java"); // 解密文件
try {
// EncFile(srcFile, encFile); // 加密操作
// DecFile(encFile, decFile);
// =====================
if (!encFile.exists()) {
System.out.println("encrypt file created");
encFile.createNewFile();
}
InputStream is = new FileInputStream(srcFile);
InputStream ercIn = EncFile(is);
OutputStream out = new FileOutputStream(encFile);
byte[] buffer = new byte[1024];
int r;
while ((r = ercIn.read(buffer)) > 0) {
out.write(buffer, 0, r);
}
is.close();
out.close();
// =====================
if (!decFile.exists()) {
System.out.println("decrypt file created");
decFile.createNewFile();
}
InputStream encFileInput = new FileInputStream(encFile);
FileOutputStream decFileInput = new FileOutputStream(decFile);
DecFile(encFileInput, decFileInput);
} catch (Exception e) {
e.printStackTrace();
}
}
}
xlsx文件上传fastdfs再下载打开会提示文件已损坏,而其它文件不会出现这个情况。尝试过多种方案都无法解决,无奈之下只能改变文件类型来避过。
有知道原因的请留言,谢谢!
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.5.8</version>
</dependency>
<dependency>
<groupId>com.github.tobato</groupId>
<artifactId>fastdfs-client</artifactId>
<version>1.26.5</version>
</dependency>
/**
* 上传附件
*
* @param inputStream
* @param fileSize
* @param fileExtName
* @param metaDataSet
* @return
* @throws Exception
*/
public StorePath upload(InputStream inputStream, String fileExtName, Set<MetaData> metaDataSet)
throws Exception {
if (StringUtils.isBlank(fileExtName)
|| !Arrays.asList(accessoryAllowFileType.split(",")).contains(fileExtName)) {
// 非法文件
throw new ServiceException("非法文件");
}
InputStream encInput = null;
try (InputStream _temp = FileSercet.EncFile(inputStream);) {
byte[] bytes = null;
/* xlsx 加密后上传到fastdfs,再下载xlsx文件提示文件已损坏 */
if ("xlsx".equals(fileExtName.toLowerCase())) {
// 文件加密后压缩zip包
bytes = ZipUtil.gzip(_temp); // 压缩
logger.debug("文件加密并压缩");
} else {
bytes = IOUtils.toByteArray(_temp);
}
// 文件上传到文件服务器
encInput = new ByteArrayInputStream(bytes);
return storageClient.uploadFile(encInput, bytes.length, "crypt", metaDataSet);
} finally {
if (inputStream != null) {
inputStream.close();
}
if (encInput != null) {
encInput.close();
}
}
}
/**
* 下载附件
*
* @param amsAccessory
* @param outputStream
* @throws Exception
*/
public void downLoad(AmsAccessory amsAccessory, OutputStream outputStream) throws Exception {
StorePath storePath = StorePath.parseFromUrl(amsAccessory.getUploadFilePath());
InputStream input = null;
try (InputStream encInput = new ByteArrayInputStream(
storageClient.downloadFile(storePath.getGroup(), storePath.getPath(), new DownloadByteArray()));) {
// xlsx需要解压原因请看上传方法说明
if ("xlsx".equals(amsAccessory.getFileType().toLowerCase())) {
byte[] _byte = ZipUtil.unGzip(encInput); // 解压
input = new ByteArrayInputStream(_byte);
} else {
input = encInput;
}
FileSercet.DecFile(input, outputStream); // 文件解密
byte[] readLine = new byte[2048];
while (input.read(readLine) != -1) {
outputStream.write(readLine);
}
outputStream.flush();
} catch (Exception e) {
throw e;
} finally {
if (input != null) {
input.close();
}
}
}