C4认证练习

任务
从https://gitcode.net/tasking/Encrypt-decrypt-files/-/raw/master/AES.zip网址下载AES.zip,编写程序解压AES.zip,将得到若干经过先经过AES算法加密,然后经过Base64编码后的文件,秘钥为1111222233334444,加密模式为CBC,偏移量为5555666677778888,请解密文件中的内容,并且重新打包成一个压缩包。

咱写一个工具类,把上面任务都完成。创建一个工具类Util,代码如下

import sun.misc.BASE64Decoder;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

public class Util {

    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";
    /**
     * 远程下载文件并读取返回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 ECB模式解密
     *
     * @param key     加密的秘钥
     * @param encrypt 加密后的内容
     * @param iv      偏移矢量
     * @return 解密后的内容
     * @throws Exception 异常信息
     */
    public static 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);
    }

    /**
     * 检查key是否合法
     *
     * @param key {@link String}秘钥信息
     * @throws Exception 异常信息
     */
    private static 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 static void checkIV(String iv) throws Exception {
        if (iv == null || iv.length() != KEY_LENGTH_16) {
            throw new Exception("偏移矢量不正确,必须为16位");
        }
    }

    /**
     * 读取文件内容
     * @param fileName 文件路径
     * @return 文件全部内容
     */
    public static 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 static void write(String fileName, String context) throws Exception {
        File file = new File(fileName);
        if(!file.exists()){
            file.createNewFile();
        }
        if(file.isDirectory()) throw new Exception("该文件是目录!");
        BufferedWriter writer = new BufferedWriter(new FileWriter(file));
        writer.write(context);
        writer.close();

    }

    /**
     * 压缩文件
     * @param fileList 待压缩的文件
     * @param destFile 目标压缩包文件
     */
    public static void zip(List<File> fileList, File destFile) throws IOException {
        if(fileList==null||fileList.isEmpty()){
            return;
        }
        OutputStream out = new FileOutputStream(destFile);
        ZipOutputStream zipOutputStream = new ZipOutputStream(new BufferedOutputStream(out));
        //设置压缩等级,范围0-9 压缩等级越高,压缩体积越小,压缩时间越长
        zipOutputStream.setLevel(5);
        for (File file : fileList){
            compress(file,zipOutputStream);
        }
        zipOutputStream.close();
    }

    private static void compress(File file, ZipOutputStream zipOutputStream) throws IOException {
        if (file.isFile()){
            compressFile(file,file.getName(),zipOutputStream);
        }else{
            compressDir(file,file.getName(),zipOutputStream);
        }
    }

    /**
     * 压缩文件类型
     * @param file 文件对象
     * @param name  文件名称
     * @param zipOutputStream zip流
     */
    private static void compressFile(File file, String name, ZipOutputStream zipOutputStream) throws IOException {
        //zip文件条目
        ZipEntry zipEntry = new ZipEntry(name);
        zipOutputStream.putNextEntry(zipEntry);
        FileInputStream fileInputStream = new FileInputStream(file);
        byte[] bytes = new byte[1024];
        int len = 0;
        while((len=fileInputStream.read(bytes))!=-1){
            zipOutputStream.write(bytes,0,len);
        }
        zipOutputStream.closeEntry();
        fileInputStream.close();
    }

    /**
     * 压缩文件夹
     * @param file  文件夹对象
     * @param name  文件夹名称
     * @param zipOutputStream   zip流
     */
    private static void compressDir(File file, String name, ZipOutputStream zipOutputStream) throws IOException {
        if(file.isDirectory()){
            File[] files = file.listFiles();
            zipOutputStream.putNextEntry(new ZipEntry(name+"/"));
            zipOutputStream.closeEntry();
            if(files!=null){
                for(File f:files){
                    if(f.isFile()){
                        compressFile(f,name+"/"+f.getName(),zipOutputStream);
                    }else {
                        compressDir(f,name+"/"+f.getName(),zipOutputStream);
                    }
                }
            }
        }
    }
}

写一个测试类,代码如下

import java.io.File;
import java.util.ArrayList;
import java.util.List;

public class Test {
    public static void main(String[] args) throws Exception {
        //网址下载AES.zip
        Util.DownAndReadFile("https://gitcode.net/tasking/Encrypt-decrypt-files/-/raw/master/AES.zip","down");
        //解压AES.zip
        Util.unzip(new File("down/AES.zip"),new File("downzip"));
        //解密文件中的内容
        String context = Util.readContext("downzip/1.txt");
        String s = Util.decryptByCBC("1111222233334444", context, "5555666677778888");
        System.out.println(s);
        //解密文件中的内容
        String context2 = Util.readContext("downzip/2.txt");
        String s2 = Util.decryptByCBC("1111222233334444", context2, "5555666677778888");
        System.out.println(s2);
        //把解密内容写入到文件中
        Util.write("1.txt",s);
        Util.write("2.txt",s2);

        //重新打包成一个压缩包
        List<File> list = new ArrayList<>();
        list.add(new File("1.txt"));
        list.add(new File("2.txt"));
        Util.zip(list,new File("newZIP.zip"));
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

郑洁文

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值