赞
踩
任务概述
制作一个服务器端工具链。
任务说明
一、文件地址
https://csdn-task.oss-cn-hangzhou.aliyuncs.com/demo/studyNginx.zip
二、完成内容
三、编码要求
每个文件的AES加密的key(32位)与偏移量都不同。
根据任务要求,远程下载压缩包,解压该压缩包。编写工具类Util,代码如下
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
public class ZipFile {
/**
* 远程下载文件并读取返回p
* @param filePath 文件网络地址 如http://www.baidu.com/1.txt
* @return String
*/
public static void DownAndReadFile(String filePath,String dirPath){
String date = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
String dir;
//使用默认项目路径
if(dirPath==null||dirPath.length()==0){
dir=""+date;
}else {
//指定路径下载
dir=dirPath;
}
File savePath = new File(dir);//创建新文件
if (!savePath.exists()) {
savePath.mkdir();
}
String[] urlname = filePath.split("/");
int len = urlname.length-1;
String uname = urlname[len];//获取文件名
try {
File file = new File(savePath+"//"+uname);//创建新文件
if(file!=null && !file.exists()){
file.createNewFile();
}
OutputStream oputstream = new FileOutputStream(file);
URL url = new URL(filePath);
HttpURLConnection uc = (HttpURLConnection) url.openConnection();
uc.setDoInput(true);//设置是否要从 URL 连接读取数据,默认为true
uc.connect();
InputStream iputstream = uc.getInputStream();
System.out.println("file size is:"+uc.getContentLength());//打印文件长度
byte[] buffer = new byte[4*1024];
int byteRead = -1;
while((byteRead=(iputstream.read(buffer)))!= -1){
oputstream.write(buffer, 0, byteRead);
}
oputstream.flush();
iputstream.close();
oputstream.close();
} catch (Exception e) {
System.out.println("读取失败!");
e.printStackTrace();
}
}
/**
* 解压缩包
* @param zipFile 源压缩文件
* @param destFile 压缩目录
*/
public static void unzip(File zipFile,File destFile) throws IOException {
if(zipFile == null)return;
if (destFile.isFile())return;
//destFile目录不存在,创建该目录
if(!destFile.exists()){
destFile.mkdirs();
}
ZipInputStream zipInputStream = new ZipInputStream(new FileInputStream(zipFile));
ZipEntry zipEntry;
while ((zipEntry=zipInputStream.getNextEntry())!=null){
String name = zipEntry.getName();
File file = new File(destFile,name);
if(zipEntry.isDirectory()){
file.mkdirs();
continue;
}
FileOutputStream fileOutputStream = new FileOutputStream(file);
int len = 0;
byte[] bytes = new byte[1024];
while ((len=zipInputStream.read(bytes))!=-1){
fileOutputStream.write(bytes,0,len);
}
zipInputStream.closeEntry();
fileOutputStream.close();
}
zipInputStream.close();
}
}
现在来使用AES加密算法单独加密每个文件,并覆盖原文件内容;创建AESCBCDemo类,代码如下
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.Random;
public class AESCBCDemo {
private static final int KEY_LENGTH_16 = 16;
private static final int KEY_LENGTH_32 = 32;
private static final String AES = "AES";
private static final String AES_CBC_NO_PADDING = "AES/CBC/NoPadding";
/**
* 生成密钥(盐)
* @param n 密钥长度
* @return
*/
public String getCKey(int n) {
String val = "";
Random random = new Random();
for (int i = 0; i < n; i++) {
String str = random.nextInt(2) % 2 == 0 ? "num" : "char";
if ("char".equalsIgnoreCase(str)) { // 产生字母
int nextInt = random.nextInt(2) % 2 == 0 ? 65 : 97;
val += (char) (nextInt + random.nextInt(26));
} else if ("num".equalsIgnoreCase(str)) { // 产生数字
val += String.valueOf(random.nextInt(10));
}
}
return val;
}
/**
* 读取文件内容
* @param fileName 文件路径
* @return 文件全部内容
*/
public String readContext(String fileName) throws Exception {
String context="";
if(fileName==null||fileName.length()==0){
throw new Exception("文件路径不能为空!");
}
File file = new File(fileName);
if (file.isDirectory()){
throw new Exception("该文件是目录!");
}
BufferedReader reader = new BufferedReader(new FileReader(file));
int length;
char[] chars = new char[1024];
while ((length=reader.read(chars))!=-1){
context+=new String(chars,0,length);
}
reader.close();
return context;
}
/**
* 将内容写入到指定文件中
* @param fileName 文件路径名
* @param context 写入内容
*/
public void write(String fileName,String context) throws Exception {
File file = new File(fileName);
if(!file.exists()){
file.mkdirs();
}
if(file.isDirectory()) throw new Exception("该文件是目录!");
BufferedWriter writer = new BufferedWriter(new FileWriter(file));
writer.write(context);
writer.close();
}
/**
* AES ECB模式加密
*
* @param key 加密的秘钥
* @param content 待加密内容
* @param iv 偏移矢量
* @return 加密后的内容
* @throws Exception 异常信息
*/
public String encryptByCBC(String key, String content, String iv) throws Exception {
checkKey(key);
checkIV(iv);
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), AES);
//AES/ECB/PKCS5Padding 格式为 "算法/模式/补码方式"
Cipher cipher = Cipher.getInstance(AES_CBC_NO_PADDING);
//加密内容长度必须要为blockSize的整数倍
int blockSize = cipher.getBlockSize();
int contentLength = content.getBytes().length;
if (contentLength % blockSize != 0) {
contentLength = contentLength + (blockSize - (contentLength % blockSize));
}
byte[] newBytes = new byte[contentLength];
System.arraycopy(content.getBytes(), 0, newBytes, 0, content.getBytes().length);
//偏移矢量
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv.getBytes());
//设置加密模式,加密的key,偏移矢量
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
//加密
byte[] bytes = cipher.doFinal(newBytes);
//base64编码进行二次加密
return new BASE64Encoder().encode(bytes);
}
/**
* 检查key是否合法
*
* @param key {@link String}秘钥信息
* @throws Exception 异常信息
*/
private void checkKey(String key) throws Exception {
if (key == null || key.length() != KEY_LENGTH_16 && key.length() != KEY_LENGTH_32) {
throw new Exception("加密秘钥不正确");
}
}
/**
* 检查偏移矢量是否合法
*
* @param iv {@link String} 偏移矢量
* @throws Exception 异常信息
*/
private void checkIV(String iv) throws Exception {
if (iv == null || iv.length() != KEY_LENGTH_16) {
throw new Exception("偏移矢量不正确,必须为16位");
}
}
/**
* AES ECB模式解密
*
* @param key 加密的秘钥
* @param encrypt 加密后的内容
* @param iv 偏移矢量
* @return 解密后的内容
* @throws Exception 异常信息
*/
public String decryptByCBC(String key, String encrypt, String iv) throws Exception {
checkKey(key);
checkIV(iv);
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), AES);
//AES/ECB/PKCS5Padding 格式为 "算法/模式/补码方式"
Cipher cipher = Cipher.getInstance(AES_CBC_NO_PADDING);
//偏移矢量
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv.getBytes());
//设置为解密模式,解密的key,偏移矢量
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
//base64解密
byte[] decodeBuffer = new BASE64Decoder().decodeBuffer(encrypt);
//aes解密
byte[] bytes = cipher.doFinal(decodeBuffer);
return new String(bytes);
}
}
测试代码如下
import www.csdn.util.AESCBCDemo;
import www.csdn.util.ZipFile;
import java.io.File;
public class Main {
public static void main(String[] args) throws Exception {
/**
* 1.使用`Java`程序将远程文件(zip压缩包)存储到本地指定的目录
*/
String url="https://csdn-task.oss-cn-hangzhou.aliyuncs.com/demo/studyNginx.zip";
ZipFile.DownAndReadFile(url,"downFile"); //dirPath 指定下载目录
/**
* 2.使用Java程序解压本地的zip文件
*/
ZipFile.unzip(new File("downFile\\studyNginx.zip"),new File("./unzip"));
//3.接下来加密4个文件
AESCBCDemo aescbcDemo = new AESCBCDemo();
//加密key长度需要为16位或32位
String key = aescbcDemo.getCKey(32);
//偏移矢量,必须为16位
String iv = aescbcDemo.getCKey(16);
//待加密内容
String content = aescbcDemo.readContext("unzip\\001.txt");
//加密
String s = aescbcDemo.decryptByCBC(key, content, iv);
//将加密后的内容写入原文件
aescbcDemo.write("unzip\\001.txt",s);
}
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。