You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Java流式加密大文件并支持GPG解密?

实现可被GPG AES256口令解密的Java流式加密(支持大文件)

需求说明

  • 处理大文件时采用流式加密,加密前无需预知文件总大小
  • 加密后的文件必须能通过GPG命令解密:gpg --decrypt --cipher-algo AES256 --passphrase="password"
  • 原生Java Cipher的加密结果仅兼容OpenSSL,尝试Bouncy Castle时未找到纯口令驱动的对称加密直接示例,调整官方示例后完成兼容实现

可用实现代码

加密工具类

import org.bouncycastle.crypto.generators.OpenBSDBCrypt;
import org.bouncycastle.crypto.modes.GCMBlockCipher;
import org.bouncycastle.crypto.params.AEADParameters;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.util.io.pem.PemObject;
import org.bouncycastle.util.io.pem.PemWriter;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;

public class GpgAes256Encryptor {
    private static final int KEY_SIZE = 256;
    private static final int GCM_TAG_LENGTH = 128;
    private static final int SALT_LENGTH = 16;
    private static final int ITERATIONS = 10000;

    public void encrypt(InputStream inputStream, OutputStream outputStream, String passphrase) throws IOException {
        SecureRandom secureRandom = new SecureRandom();
        byte[] salt = new byte[SALT_LENGTH];
        secureRandom.nextBytes(salt);

        // 生成兼容GPG的密钥
        byte[] key = OpenBSDBCrypt.generate(passphrase.getBytes(StandardCharsets.UTF_8), salt, ITERATIONS, KEY_SIZE / 8);

        // 生成GCM推荐的12字节IV
        byte[] iv = new byte[12];
        secureRandom.nextBytes(iv);

        // 初始化GCM加密器
        GCMBlockCipher cipher = new GCMBlockCipher(new org.bouncycastle.crypto.engines.AESFastEngine());
        cipher.init(true, new AEADParameters(new KeyParameter(key), GCM_TAG_LENGTH, iv));

        // 写入GPG可识别的头部结构
        writeGpgHeader(outputStream, salt, iv);

        // 流式加密处理
        byte[] buffer = new byte[8192];
        int read;
        while ((read = inputStream.read(buffer)) != -1) {
            byte[] outBuf = new byte[cipher.getOutputSize(read)];
            int processed = cipher.processBytes(buffer, 0, read, outBuf, 0);
            outputStream.write(outBuf, 0, processed);
        }

        // 处理收尾数据并写入加密标签
        byte[] finalBuf = new byte[cipher.getOutputSize(0)];
        int finalProcessed = cipher.doFinal(finalBuf, 0);
        outputStream.write(finalBuf, 0, finalProcessed);

        outputStream.flush();
    }

    private void writeGpgHeader(OutputStream outputStream, byte[] salt, byte[] iv) throws IOException {
        ByteArrayOutputStream headerBaos = new ByteArrayOutputStream();
        // 版本标识 + AES256算法标识
        headerBaos.write(new byte[]{0x8c, 0x03});
        // S2K参数:迭代计数 + 盐长度
        headerBaos.write(new byte[]{0x03, (byte) ITERATIONS, (byte) salt.length});
        headerBaos.write(salt);
        // IV长度 + IV内容
        headerBaos.write(new byte[]{(byte) iv.length});
        headerBaos.write(iv);

        // 封装为OpenPGP数据包格式
        byte[] headerBytes = headerBaos.toByteArray();
        outputStream.write(0xc0); // 对称加密数据包标记
        writeLength(outputStream, headerBytes.length);
        outputStream.write(headerBytes);
    }

    private void writeLength(OutputStream outputStream, int length) throws IOException {
        // GPG新格式长度编码逻辑
        if (length < 0x100) {
            outputStream.write(length);
        } else if (length < 0x10000) {
            outputStream.write(0xff);
            outputStream.write(length >> 8);
            outputStream.write(length & 0xff);
        } else {
            outputStream.write(0xff);
            outputStream.write(0xff);
            outputStream.write((length >> 24) & 0xff);
            outputStream.write((length >> 16) & 0xff);
            outputStream.write((length >> 8) & 0xff);
            outputStream.write(length & 0xff);
        }
    }
}

测试代码

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class EncryptTest {
    public static void main(String[] args) {
        String inputFilePath = "path/to/your/large-file.bin";
        String outputFilePath = "path/to/encrypted-file.gpg";
        String passphrase = "password";

        try (FileInputStream fis = new FileInputStream(inputFilePath);
             FileOutputStream fos = new FileOutputStream(outputFilePath)) {

            GpgAes256Encryptor encryptor = new GpgAes256Encryptor();
            encryptor.encrypt(fis, fos, passphrase);
            System.out.println("加密完成,可执行以下命令解密:");
            System.out.println("gpg --decrypt --cipher-algo AES256 --passphrase=\"" + passphrase + "\" " + outputFilePath);

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

当前状态与后续计划

  • 已验证:加密后的文件可通过指定GPG命令正常解密,支持流式处理大文件(无需提前知晓文件大小)
  • 下一步优化:让GpgAes256Encryptor继承OutputStream,实现底层输入/输出流的自动有序关闭,进一步简化调用逻辑

内容的提问来源于stack exchange,提问作者Darien Bowen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 20:35:26