zoukankan      html  css  js  c++  java
  • java工具类-对称加密算法AES 加密文件流

    文件流加密涉及到大文件加密过程,不能直接使用Cipher.doFinal(byte[] bytes)方法进行直接加密

    超大文件会导致内存溢出。

    解决方法:

    可以使用 Cipher.update(byte[] bytes) 方法进行文件流部分加密数据,
    
    当整个文件流数据都加密完后,使用 Cipher.doFinal()方法来生成填充内容,保证最后一段内容也是完整128位数据块

    所以会使用CipherInputStream 或者 CipherOutputStream进行文件加解密

    使用上面中了一个就可以了。或者也可以混着用

    说下原理:

    CipherInputStream 

    对输入流进行封装
    
    CipherInputStream.read()读取字节流时调用的cipher.update()方法进行流部分加密, 当加密到最后一段时,会调用 doFinal() 方法。
     CipherOutputStream
    对输出流进行封装,当要写入固定字节数据时,先加密,再写出
    CipherOutputStream.write() 中调用 cipher.update() 方法进行字节数组加密后写出
    再CipherOutputStream.close()中调用cipher.doFinal()方法 填充最后一段内容

    贴个示例代码

      public static void aesEncryptFile(String sourceFilePath, String destFilePath, String key) throws Exception {
            aesFile(sourceFilePath, destFilePath, key, Cipher.ENCRYPT_MODE);
        }
        public static void aesDecryptFile(String sourceFilePath, String destFilePath, String key) throws Exception {
            aesFile(sourceFilePath, destFilePath, key, Cipher.DECRYPT_MODE);
        }
    
        public static void aesEncryptFileForInput(String sourceFilePath, String destFilePath, String key) throws Exception {
            aesFileForInput(sourceFilePath, destFilePath, key, Cipher.ENCRYPT_MODE);
        }
        public static void aesDecryptFileForInput(String sourceFilePath, String destFilePath, String key) throws Exception {
            aesFileForInput(sourceFilePath, destFilePath, key, Cipher.DECRYPT_MODE);
        }
    
        /**
         * 通过文件输入流加密文件并输出到指定路径
         * CipherOutputStream进行加密数据
         */
        public static void aesFile(String sourceFilePath, String destFilePath, String key, int mode) throws Exception {
            File sourceFile = new File(sourceFilePath);
            File destFile = new File(destFilePath);
            if (sourceFile.exists() && sourceFile.isFile()) {
                throw new IllegalArgumentException("加密源文件不存在");
            }
            if (!destFile.getParentFile().exists()) {
                destFile.getParentFile().mkdirs();
            }
            destFile.createNewFile();
            InputStream in = new FileInputStream(sourceFile);
            OutputStream out = new FileOutputStream(destFile);
            SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES/ECB/PKCS5Padding");
            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
            cipher.init(mode, secretKeySpec);
            // 对输出流包装
            CipherOutputStream cout = new CipherOutputStream(out, cipher);
            byte[] cache = new byte[1024];
            int nRead = 0;
            while ((nRead = in.read(cache)) != -1) {
                cout.write(cache, 0, nRead);
                cout.flush();
            }
            cout.close();
            out.close();
            in.close();
        }
    
        /**
         * 通过文件输入流加密文件并输出到指定路径
         * CipherInputStream进行加密数据
         */
        public static void aesFileForInput(String sourceFilePath, String destFilePath, String key, int mode) throws Exception {
            File sourceFile = new File(sourceFilePath);
            File destFile = new File(destFilePath);
            if (sourceFile.exists() && sourceFile.isFile()) {
                throw new IllegalArgumentException("加密源文件不存在");
            }
            if (!destFile.getParentFile().exists()) {
                destFile.getParentFile().mkdirs();
            }
            destFile.createNewFile();
            InputStream in = new FileInputStream(sourceFile);
            OutputStream out = new FileOutputStream(destFile);
            SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES/ECB/PKCS5Padding");
            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
            cipher.init(mode, secretKeySpec);
            // 对输入流包装
            CipherInputStream cin = new CipherInputStream(in, cipher);
    
            byte[] cache = new byte[1024];
            int nRead = 0;
            while ((nRead = cin.read(cache)) != -1) {
                out.write(cache, 0, nRead);
                out.flush();
            }
            out.close();
            cin.close();
            in.close();
        }
     
     

     
    作者:海绵般汲取
    出处:https://www.cnblogs.com/gne-hwz/
    版权:本文版权归作者和博客园共有
    转载:欢迎转载,但未经作者同意,必须保留此段声明;必须在文章中给出原文连接;否则必究法律责任
  • 相关阅读:
    Java 泛型约束
    Java 单例模式
    Java中的Atomic包使用指南
    基数排序
    归并排序
    插入排序
    选择排序
    交换排序
    Java多线程 LockSupport
    Java并发控制:ReentrantLock Condition使用详解
  • 原文地址:https://www.cnblogs.com/gne-hwz/p/14736496.html
Copyright © 2011-2022 走看看