mirror of
https://github.com/pgpainless/pgpainless.git
synced 2024-11-16 09:22:05 +01:00
Add StreamGeneratorWrapper which uses new PGPCanonicalizedDataGenerator if required
This commit is contained in:
parent
888073b604
commit
03f13ee4a7
3 changed files with 103 additions and 11 deletions
|
@ -15,7 +15,6 @@ import org.bouncycastle.bcpg.BCPGOutputStream;
|
||||||
import org.bouncycastle.openpgp.PGPCompressedDataGenerator;
|
import org.bouncycastle.openpgp.PGPCompressedDataGenerator;
|
||||||
import org.bouncycastle.openpgp.PGPEncryptedDataGenerator;
|
import org.bouncycastle.openpgp.PGPEncryptedDataGenerator;
|
||||||
import org.bouncycastle.openpgp.PGPException;
|
import org.bouncycastle.openpgp.PGPException;
|
||||||
import org.bouncycastle.openpgp.PGPLiteralDataGenerator;
|
|
||||||
import org.bouncycastle.openpgp.PGPSignature;
|
import org.bouncycastle.openpgp.PGPSignature;
|
||||||
import org.bouncycastle.openpgp.PGPSignatureGenerator;
|
import org.bouncycastle.openpgp.PGPSignatureGenerator;
|
||||||
import org.bouncycastle.openpgp.operator.PGPDataEncryptorBuilder;
|
import org.bouncycastle.openpgp.operator.PGPDataEncryptorBuilder;
|
||||||
|
@ -25,6 +24,7 @@ import org.pgpainless.algorithm.SymmetricKeyAlgorithm;
|
||||||
import org.pgpainless.implementation.ImplementationFactory;
|
import org.pgpainless.implementation.ImplementationFactory;
|
||||||
import org.pgpainless.key.SubkeyIdentifier;
|
import org.pgpainless.key.SubkeyIdentifier;
|
||||||
import org.pgpainless.util.ArmoredOutputStreamFactory;
|
import org.pgpainless.util.ArmoredOutputStreamFactory;
|
||||||
|
import org.pgpainless.util.StreamGeneratorWrapper;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ public final class EncryptionStream extends OutputStream {
|
||||||
private OutputStream publicKeyEncryptedStream = null;
|
private OutputStream publicKeyEncryptedStream = null;
|
||||||
private PGPCompressedDataGenerator compressedDataGenerator;
|
private PGPCompressedDataGenerator compressedDataGenerator;
|
||||||
private BCPGOutputStream basicCompressionStream;
|
private BCPGOutputStream basicCompressionStream;
|
||||||
private PGPLiteralDataGenerator literalDataGenerator;
|
private StreamGeneratorWrapper streamGeneratorWrapper;
|
||||||
private OutputStream literalDataStream;
|
private OutputStream literalDataStream;
|
||||||
|
|
||||||
EncryptionStream(@Nonnull OutputStream targetOutputStream,
|
EncryptionStream(@Nonnull OutputStream targetOutputStream,
|
||||||
|
@ -147,12 +147,10 @@ public final class EncryptionStream extends OutputStream {
|
||||||
armorOutputStream.beginClearText(firstMethod.getHashAlgorithm().getAlgorithmId());
|
armorOutputStream.beginClearText(firstMethod.getHashAlgorithm().getAlgorithmId());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
literalDataGenerator = new PGPLiteralDataGenerator();
|
|
||||||
literalDataStream = literalDataGenerator.open(outermostStream,
|
streamGeneratorWrapper = StreamGeneratorWrapper.forStreamEncoding(options.getEncoding());
|
||||||
options.getEncoding().getCode(),
|
literalDataStream = streamGeneratorWrapper.open(outermostStream,
|
||||||
options.getFileName(),
|
options.getFileName(), options.getModificationDate(), new byte[BUFFER_SIZE]);
|
||||||
options.getModificationDate(),
|
|
||||||
new byte[BUFFER_SIZE]);
|
|
||||||
outermostStream = literalDataStream;
|
outermostStream = literalDataStream;
|
||||||
|
|
||||||
resultBuilder.setFileName(options.getFileName())
|
resultBuilder.setFileName(options.getFileName())
|
||||||
|
@ -212,8 +210,8 @@ public final class EncryptionStream extends OutputStream {
|
||||||
literalDataStream.flush();
|
literalDataStream.flush();
|
||||||
literalDataStream.close();
|
literalDataStream.close();
|
||||||
}
|
}
|
||||||
if (literalDataGenerator != null) {
|
if (streamGeneratorWrapper != null) {
|
||||||
literalDataGenerator.close();
|
streamGeneratorWrapper.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.isCleartextSigned()) {
|
if (options.isCleartextSigned()) {
|
||||||
|
|
|
@ -0,0 +1,94 @@
|
||||||
|
// SPDX-FileCopyrightText: 2021 Paul Schaub <vanitasvitae@fsfe.org>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package org.pgpainless.util;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
|
import org.bouncycastle.openpgp.PGPCanonicalizedDataGenerator;
|
||||||
|
import org.bouncycastle.openpgp.PGPLiteralDataGenerator;
|
||||||
|
import org.pgpainless.algorithm.StreamEncoding;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Literal Data can be encoded in different ways.
|
||||||
|
* BINARY encoding leaves the data as is and is generated through the {@link PGPLiteralDataGenerator}.
|
||||||
|
* However, if the data is encoded in TEXT or UTF8 encoding, we need to use the {@link PGPCanonicalizedDataGenerator}
|
||||||
|
* instead.
|
||||||
|
*
|
||||||
|
* This wrapper class acts as a handle for both options and provides a unified interface for them.
|
||||||
|
*/
|
||||||
|
public final class StreamGeneratorWrapper {
|
||||||
|
|
||||||
|
private final StreamEncoding encoding;
|
||||||
|
private final PGPLiteralDataGenerator literalDataGenerator;
|
||||||
|
private final PGPCanonicalizedDataGenerator canonicalizedDataGenerator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new instance for the given encoding.
|
||||||
|
*
|
||||||
|
* @param encoding stream encoding
|
||||||
|
* @return wrapper
|
||||||
|
*/
|
||||||
|
public static StreamGeneratorWrapper forStreamEncoding(@Nonnull StreamEncoding encoding) {
|
||||||
|
if (encoding == StreamEncoding.BINARY) {
|
||||||
|
return new StreamGeneratorWrapper(encoding, new PGPLiteralDataGenerator());
|
||||||
|
} else {
|
||||||
|
return new StreamGeneratorWrapper(encoding, new PGPCanonicalizedDataGenerator());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private StreamGeneratorWrapper(@Nonnull StreamEncoding encoding, @Nonnull PGPLiteralDataGenerator literalDataGenerator) {
|
||||||
|
if (encoding != StreamEncoding.BINARY) {
|
||||||
|
throw new IllegalArgumentException("PGPLiteralDataGenerator can only be used with BINARY encoding.");
|
||||||
|
}
|
||||||
|
this.encoding = encoding;
|
||||||
|
this.literalDataGenerator = literalDataGenerator;
|
||||||
|
this.canonicalizedDataGenerator = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private StreamGeneratorWrapper(@Nonnull StreamEncoding encoding, @Nonnull PGPCanonicalizedDataGenerator canonicalizedDataGenerator) {
|
||||||
|
if (encoding != StreamEncoding.TEXT && encoding != StreamEncoding.UTF8) {
|
||||||
|
throw new IllegalArgumentException("PGPCanonicalizedDataGenerator can only be used with TEXT or UTF8 encoding.");
|
||||||
|
}
|
||||||
|
this.encoding = encoding;
|
||||||
|
this.canonicalizedDataGenerator = canonicalizedDataGenerator;
|
||||||
|
this.literalDataGenerator = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open a new encoding stream.
|
||||||
|
*
|
||||||
|
* @param outputStream wrapped output stream
|
||||||
|
* @param filename file name
|
||||||
|
* @param modificationDate modification date
|
||||||
|
* @param buffer buffer
|
||||||
|
* @return encoding stream
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public OutputStream open(OutputStream outputStream, String filename, Date modificationDate, byte[] buffer) throws IOException {
|
||||||
|
if (literalDataGenerator != null) {
|
||||||
|
return literalDataGenerator.open(outputStream, encoding.getCode(), filename, modificationDate, buffer);
|
||||||
|
} else {
|
||||||
|
return canonicalizedDataGenerator.open(outputStream, encoding.getCode(), filename, modificationDate, buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close all encoding streams opened by this generator wrapper.
|
||||||
|
*
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public void close() throws IOException {
|
||||||
|
if (literalDataGenerator != null) {
|
||||||
|
literalDataGenerator.close();
|
||||||
|
}
|
||||||
|
if (canonicalizedDataGenerator != null) {
|
||||||
|
canonicalizedDataGenerator.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -23,7 +23,7 @@ public class LiteralDataCRLFEncodingTest {
|
||||||
public void testCanonicalization() throws IOException {
|
public void testCanonicalization() throws IOException {
|
||||||
PGPCanonicalizedDataGenerator generator = new PGPCanonicalizedDataGenerator();
|
PGPCanonicalizedDataGenerator generator = new PGPCanonicalizedDataGenerator();
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
OutputStream canonicalizer = generator.open(out, PGPCanonicalizedDataGenerator.UTF8, "", new Date(), new byte[1<<9]);
|
OutputStream canonicalizer = generator.open(out, PGPCanonicalizedDataGenerator.UTF8, "", new Date(), new byte[1 << 9]);
|
||||||
|
|
||||||
ByteArrayInputStream in = new ByteArrayInputStream("Foo\nBar\n".getBytes(StandardCharsets.UTF_8));
|
ByteArrayInputStream in = new ByteArrayInputStream("Foo\nBar\n".getBytes(StandardCharsets.UTF_8));
|
||||||
Streams.pipeAll(in, canonicalizer);
|
Streams.pipeAll(in, canonicalizer);
|
||||||
|
|
Loading…
Reference in a new issue