java工具類-對稱加密算法AES 加密文件流


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

超大文件會導致內存溢出。

解決方法:

可以使用 Cipher.update(byte[] bytes) 方法進行文件流部分加密數據,

當整個文件流數據都加密完后,使用 Cipher.doFinal()方法來生成填充內容,保證最后一段內容也是完整128位數據塊

所以會使用CipherInputStream 或者 CipherOutputStream進行文件加解密

 

文件流加密時,會使用CipherOutputStream來包裝輸出流,當調用outputStream.close()方法時,會執行cipher.doFinal()方法生成最后一個byte[] 數據,並寫出到輸出流,flush()才算加密完成。

文件解密時,會使用 CipherInputStream 來包裝輸入流, 當讀取到inputStream.read()最后內容時,會執行cipher.doFinal()方法生成的byte[] 也要寫出到輸出流才可以。

 

說下原理:

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");
        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");
        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();
    }

 

 
 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM