PGP 加密输入流与 BouncyCastle/Java

问题描述

摘要我正在寻找一些 PGP 加密的 InputStream 实现,而不是 BouncyCastle 的 OutputStream 实现。

我目前正在重构文件上传 servlet 的一些代码,该代码上传的数据进行 PGP 加密并将其转发到 REST 服务进行存储。我尝试以流式方式执行此操作,而无需在内存或磁盘中缓冲整个文件

在对数据进行加密的 servlet 中,我在 org.apache.commons.fileupload.servlet.ServletFileUpload 的帮助下读取数据,它提供对作为 InputStream 的数据的访问。 IE。我的 servlet 必须主动从浏览器读取数据(“拉”它)。

要访问 REST 接口,我使用 org.apache.http.client.methods.HttpPost在这里,我也必须以 InputStream 的形式提供数据,远程 REST 服务负责从我的 servlet 中“拉取”数据。

问题:BouncyCastle 使用 PGPEncryptedDataGenerator 创建一个加密的 OutputStream,它需要我的 servlet write 数据(线程“推送”数据)。要将两端的 OutputStream 与 InputStreams 连接,我需要 InputStream.transferTo(OutputStream) 将来自 Servlet 上传的数据复制到加密输出流中(为此我需要一个额外的线程),以及附加的 PipedStream 操作以从中复制加密数据再次将 OutputStream 转换为 InputStream。

在这真的很复杂,如果我可以使用加密的 InputStream 来代替它会容易得多。有了这个,我可以从 servlet 包装 InputStream 并将它传递给 REST 接口处的 HttpPost,消除对额外线程的需要,因为来自消费 REST 服务的“拉”操作将通过我的 servlet 代码直接连接到提供原始数据的浏览器上的“拉”。

我的问题:有人知道/有一些 BouncyCastle 的 EncryptingInputStream 实现吗?

这是我基于使用加密输出流的工作代码示例。要运行它,您必须在类路径上有一个“keyBox”格式的公钥环,并在 CLI 上提供密钥 userId。

public class Main {

public static void main(String...args) throws NoSuchAlgorithmException,NoSuchProviderException,InvalidAlgorithmParameterException,PGPException,IOException,ExecutionException,InterruptedException {
    Security.addProvider(new BouncyCastleProvider());

    final PGPPublicKey publicKey = readPublicKeyRing(args[0]);

    ByteArrayOutputStream output = new ByteArrayOutputStream(); // Simulates the REST-service as data sink.

    // Setup encryption
    final JcePGPDataEncryptorBuilder encryptorBuilder = new JcePGPDataEncryptorBuilder(SymmetricKeyAlgorithmTags.AES_256)
            .setWithIntegrityPacket(true)
            .setSecureRandom(new SecureRandom()).setProvider("BC");
    final JcePublicKeyKeyEncryptionMethodGenerator methodGenerator = new JcePublicKeyKeyEncryptionMethodGenerator(publicKey)
            .setProvider("BC");
    final PGPEncryptedDataGenerator encGen = new PGPEncryptedDataGenerator(encryptorBuilder);
    encGen.addMethod(methodGenerator);
    PGPLiteralDataGenerator dataGenerator = new PGPLiteralDataGenerator();

    // Setup the streams.
    try (PipedInputStream recEncInput = new PipedInputStream()) {
        // The thread to process the encrypted data has to be started first.
        final CompletableFuture<Void> receiveData = CompletableFuture.runAsync(() -> {
            System.out.println("Pulling encrypted data from PipedInputStream");
            try {
                recEncInput.transferTo(output);
                System.out.println("Finished receiving encrypted data from pipe");
            } catch (IOException e) {
                e.printstacktrace();
            }
        });

        try (PipedOutputStream pipedOutput = new PipedOutputStream(recEncInput);
             OutputStream encOut = encGen.open(pipedOutput,new byte[4096]);
             OutputStream effectiveOut = dataGenerator.open(encOut,PGPLiteralData.BINARY,"Message",new Date(),new byte[4096]))
        {
             // copy the data from servlet input stream to encrypting output stream.
             try (InputStream inputStream = new ByteArrayInputStream(Strings.toByteArray("Hello,world!"))) { // Simulates the servlet input stream with uploaded data.
                 inputStream.transferTo(effectiveOut);
                 System.out.println("Finished transfering data to encrypting OutputStream");
             } catch (IOException e) {
                 e.printstacktrace();
             }
        }
        receiveData.get(); // wait until copy thread has finished (after the encrypting streams are closed!)
    }

    byte[] encData = output.toByteArray();
    Files.write(Paths.get("pgp-encrypted-string.pgp"),encData);
}

/**
 * Read the public key for given userId from "pubring.kbx" on classpath.
 * @param userId
 */
static PGPPublicKey readPublicKeyRing(String userId) throws IOException,NoSuchAlgorithmException,NoSuchProviderException {

    try (final InputStream pubringString = Main.class.getClassLoader().getResourceAsstream("pubring.kbx")) {

        final JcaKeyBox keyBox = new JcaKeyBoxBuilder().build(pubringString);

        final List<KeyBlob> blobs = keyBox.getKeyBlobs();
        final Optional<KeyBlob> keyBlob = blobs.stream().filter(blob -> {
            boolean matches = blob.getUserIds().stream()
                    .map(uid -> uid.getUserIDAsstring())
                    .anyMatch(uidStr -> uidStr.toLowerCase(Locale.ROOT).contains(userId.toLowerCase(Locale.ROOT)));
            return matches;
        }).findAny();

        if (keyBlob.isPresent()) {
            PublicKeyRingBlob pgkr = (PublicKeyRingBlob)keyBlob.get();
            PGPPublicKeyRing ring = pgkr.getPGPPublicKeyRing();
            return ring.getPublicKey();
        } else {
            return null;
        }
    }
}
}

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)