mirror of
https://github.com/pgpainless/pgpainless.git
synced 2024-12-22 19:08:00 +01:00
Kotlin conversion: Cleartext Signature Framework
This commit is contained in:
parent
8d67820f50
commit
48af91efbf
10 changed files with 297 additions and 337 deletions
|
@ -1,169 +0,0 @@
|
|||
// SPDX-FileCopyrightText: 2021 Paul Schaub <vanitasvitae@fsfe.org>
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package org.pgpainless.decryption_verification.cleartext_signatures;
|
||||
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import org.bouncycastle.bcpg.ArmoredInputStream;
|
||||
import org.bouncycastle.openpgp.PGPObjectFactory;
|
||||
import org.bouncycastle.openpgp.PGPSignatureList;
|
||||
import org.bouncycastle.util.Strings;
|
||||
import org.pgpainless.exception.WrongConsumingMethodException;
|
||||
import org.pgpainless.implementation.ImplementationFactory;
|
||||
import org.pgpainless.util.ArmoredInputStreamFactory;
|
||||
|
||||
/**
|
||||
* Utility class to deal with cleartext-signed messages.
|
||||
* Based on Bouncycastle's {@link org.bouncycastle.openpgp.examples.ClearSignedFileProcessor}.
|
||||
*/
|
||||
public final class ClearsignedMessageUtil {
|
||||
|
||||
private ClearsignedMessageUtil() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Dearmor a clearsigned message, detach the inband signatures and write the plaintext message to the provided
|
||||
* messageOutputStream.
|
||||
*
|
||||
* @param clearsignedInputStream input stream containing a clearsigned message
|
||||
* @param messageOutputStream output stream to which the dearmored message shall be written
|
||||
* @return signatures
|
||||
*
|
||||
* @throws IOException if the message is not clearsigned or some other IO error happens
|
||||
* @throws WrongConsumingMethodException in case the armored message is not cleartext signed
|
||||
*/
|
||||
public static PGPSignatureList detachSignaturesFromInbandClearsignedMessage(InputStream clearsignedInputStream,
|
||||
OutputStream messageOutputStream)
|
||||
throws IOException, WrongConsumingMethodException {
|
||||
ArmoredInputStream in;
|
||||
if (clearsignedInputStream instanceof ArmoredInputStream) {
|
||||
in = (ArmoredInputStream) clearsignedInputStream;
|
||||
} else {
|
||||
in = ArmoredInputStreamFactory.get(clearsignedInputStream);
|
||||
}
|
||||
|
||||
if (!in.isClearText()) {
|
||||
throw new WrongConsumingMethodException("Message is not using the Cleartext Signature Framework.");
|
||||
}
|
||||
|
||||
OutputStream out = new BufferedOutputStream(messageOutputStream);
|
||||
try {
|
||||
ByteArrayOutputStream lineOut = new ByteArrayOutputStream();
|
||||
int lookAhead = readInputLine(lineOut, in);
|
||||
byte[] lineSep = getLineSeparator();
|
||||
|
||||
if (lookAhead != -1 && in.isClearText()) {
|
||||
byte[] line = lineOut.toByteArray();
|
||||
out.write(line, 0, getLengthWithoutSeparatorOrTrailingWhitespace(line));
|
||||
|
||||
while (lookAhead != -1 && in.isClearText()) {
|
||||
lookAhead = readInputLine(lineOut, lookAhead, in);
|
||||
line = lineOut.toByteArray();
|
||||
out.write(lineSep);
|
||||
out.write(line, 0, getLengthWithoutSeparatorOrTrailingWhitespace(line));
|
||||
}
|
||||
} else {
|
||||
if (lookAhead != -1) {
|
||||
byte[] line = lineOut.toByteArray();
|
||||
out.write(line, 0, getLengthWithoutSeparatorOrTrailingWhitespace(line));
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
out.close();
|
||||
}
|
||||
|
||||
PGPObjectFactory objectFactory = ImplementationFactory.getInstance().getPGPObjectFactory(in);
|
||||
PGPSignatureList signatures = (PGPSignatureList) objectFactory.nextObject();
|
||||
|
||||
return signatures;
|
||||
}
|
||||
|
||||
public static int readInputLine(ByteArrayOutputStream bOut, InputStream fIn)
|
||||
throws IOException {
|
||||
bOut.reset();
|
||||
|
||||
int lookAhead = -1;
|
||||
int ch;
|
||||
|
||||
while ((ch = fIn.read()) >= 0) {
|
||||
bOut.write(ch);
|
||||
if (ch == '\r' || ch == '\n') {
|
||||
lookAhead = readPassedEOL(bOut, ch, fIn);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return lookAhead;
|
||||
}
|
||||
|
||||
public static int readInputLine(ByteArrayOutputStream bOut, int lookAhead, InputStream fIn)
|
||||
throws IOException {
|
||||
bOut.reset();
|
||||
|
||||
int ch = lookAhead;
|
||||
|
||||
do {
|
||||
bOut.write(ch);
|
||||
if (ch == '\r' || ch == '\n') {
|
||||
lookAhead = readPassedEOL(bOut, ch, fIn);
|
||||
break;
|
||||
}
|
||||
}
|
||||
while ((ch = fIn.read()) >= 0);
|
||||
|
||||
if (ch < 0) {
|
||||
lookAhead = -1;
|
||||
}
|
||||
|
||||
return lookAhead;
|
||||
}
|
||||
|
||||
private static int readPassedEOL(ByteArrayOutputStream bOut, int lastCh, InputStream fIn)
|
||||
throws IOException {
|
||||
int lookAhead = fIn.read();
|
||||
|
||||
if (lastCh == '\r' && lookAhead == '\n') {
|
||||
bOut.write(lookAhead);
|
||||
lookAhead = fIn.read();
|
||||
}
|
||||
|
||||
return lookAhead;
|
||||
}
|
||||
|
||||
|
||||
private static byte[] getLineSeparator() {
|
||||
String nl = Strings.lineSeparator();
|
||||
byte[] nlBytes = new byte[nl.length()];
|
||||
|
||||
for (int i = 0; i != nlBytes.length; i++) {
|
||||
nlBytes[i] = (byte) nl.charAt(i);
|
||||
}
|
||||
|
||||
return nlBytes;
|
||||
}
|
||||
|
||||
private static int getLengthWithoutSeparatorOrTrailingWhitespace(byte[] line) {
|
||||
int end = line.length - 1;
|
||||
|
||||
while (end >= 0 && isWhiteSpace(line[end])) {
|
||||
end--;
|
||||
}
|
||||
|
||||
return end + 1;
|
||||
}
|
||||
|
||||
private static boolean isLineEnding(byte b) {
|
||||
return b == '\r' || b == '\n';
|
||||
}
|
||||
|
||||
private static boolean isWhiteSpace(byte b) {
|
||||
return isLineEnding(b) || b == '\t' || b == ' ';
|
||||
}
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
// SPDX-FileCopyrightText: 2021 Paul Schaub <vanitasvitae@fsfe.org>
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package org.pgpainless.decryption_verification.cleartext_signatures;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
|
||||
/**
|
||||
* Implementation of the {@link MultiPassStrategy}.
|
||||
* This class keeps the read data in memory by caching the data inside a {@link ByteArrayOutputStream}.
|
||||
*
|
||||
* Note, that this class is suitable and efficient for processing small amounts of data.
|
||||
* For larger data like encrypted files, use of the {@link WriteToFileMultiPassStrategy} is recommended to
|
||||
* prevent {@link OutOfMemoryError OutOfMemoryErrors} and other issues.
|
||||
*/
|
||||
public class InMemoryMultiPassStrategy implements MultiPassStrategy {
|
||||
|
||||
private final ByteArrayOutputStream cache = new ByteArrayOutputStream();
|
||||
|
||||
@Override
|
||||
public ByteArrayOutputStream getMessageOutputStream() {
|
||||
return cache;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteArrayInputStream getMessageInputStream() {
|
||||
return new ByteArrayInputStream(getBytes());
|
||||
}
|
||||
|
||||
public byte[] getBytes() {
|
||||
return getMessageOutputStream().toByteArray();
|
||||
}
|
||||
}
|
|
@ -1,70 +0,0 @@
|
|||
// SPDX-FileCopyrightText: 2021 Paul Schaub <vanitasvitae@fsfe.org>
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package org.pgpainless.decryption_verification.cleartext_signatures;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* Since for verification of cleartext signed messages, we need to read the whole data twice in order to verify signatures,
|
||||
* a strategy for how to cache the read data is required.
|
||||
* Otherwise, large data kept in memory could cause {@link OutOfMemoryError OutOfMemoryErrors} or other issues.
|
||||
*
|
||||
* This is an Interface that describes a strategy to deal with the fact that detached signatures require multiple passes
|
||||
* to do verification.
|
||||
*
|
||||
* This interface can be used to write the signed data stream out via {@link #getMessageOutputStream()} and later
|
||||
* get access to the data again via {@link #getMessageInputStream()}.
|
||||
* Thereby the detail where the data is being stored (memory, file, etc.) can be abstracted away.
|
||||
*/
|
||||
public interface MultiPassStrategy {
|
||||
|
||||
/**
|
||||
* Provide an {@link OutputStream} into which the signed data can be read into.
|
||||
*
|
||||
* @return output stream
|
||||
* @throws IOException io error
|
||||
*/
|
||||
OutputStream getMessageOutputStream() throws IOException;
|
||||
|
||||
/**
|
||||
* Provide an {@link InputStream} which contains the data that was previously written away in
|
||||
* {@link #getMessageOutputStream()}.
|
||||
*
|
||||
* As there may be multiple signatures that need to be processed, each call of this method MUST return
|
||||
* a new {@link InputStream}.
|
||||
*
|
||||
* @return input stream
|
||||
* @throws IOException io error
|
||||
*/
|
||||
InputStream getMessageInputStream() throws IOException;
|
||||
|
||||
/**
|
||||
* Write the message content out to a file and re-read it to verify signatures.
|
||||
* This strategy is best suited for larger messages (e.g. plaintext signed files) which might not fit into memory.
|
||||
* After the message has been processed completely, the messages content are available at the provided file.
|
||||
*
|
||||
* @param file target file
|
||||
* @return strategy
|
||||
*/
|
||||
static MultiPassStrategy writeMessageToFile(File file) {
|
||||
return new WriteToFileMultiPassStrategy(file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the message content into memory.
|
||||
* This strategy is best suited for small messages which fit into memory.
|
||||
* After the message has been processed completely, the message content can be accessed by calling
|
||||
* {@link ByteArrayOutputStream#toByteArray()} on {@link #getMessageOutputStream()}.
|
||||
*
|
||||
* @return strategy
|
||||
*/
|
||||
static InMemoryMultiPassStrategy keepMessageInMemory() {
|
||||
return new InMemoryMultiPassStrategy();
|
||||
}
|
||||
}
|
|
@ -1,54 +0,0 @@
|
|||
// SPDX-FileCopyrightText: 2021 Paul Schaub <vanitasvitae@fsfe.org>
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package org.pgpainless.decryption_verification.cleartext_signatures;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* Implementation of the {@link MultiPassStrategy}.
|
||||
* When processing signed data the first time, the data is being written out into a file.
|
||||
* For the second pass, that file is being read again.
|
||||
*
|
||||
* This strategy is recommended when larger amounts of data need to be processed.
|
||||
* For smaller files, {@link InMemoryMultiPassStrategy} yields higher efficiency.
|
||||
*/
|
||||
public class WriteToFileMultiPassStrategy implements MultiPassStrategy {
|
||||
|
||||
private final File file;
|
||||
|
||||
/**
|
||||
* Create a {@link MultiPassStrategy} which writes data to a file.
|
||||
* Note that {@link #getMessageOutputStream()} will create the file if necessary.
|
||||
*
|
||||
* @param file file to write the data to and read from
|
||||
*/
|
||||
public WriteToFileMultiPassStrategy(File file) {
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OutputStream getMessageOutputStream() throws IOException {
|
||||
if (!file.exists()) {
|
||||
boolean created = file.createNewFile();
|
||||
if (!created) {
|
||||
throw new IOException("New file '" + file.getAbsolutePath() + "' was not created.");
|
||||
}
|
||||
}
|
||||
return new FileOutputStream(file);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getMessageInputStream() throws IOException {
|
||||
if (!file.exists()) {
|
||||
throw new IOException("File '" + file.getAbsolutePath() + "' does no longer exist.");
|
||||
}
|
||||
return new FileInputStream(file);
|
||||
}
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
// SPDX-FileCopyrightText: 2021 Paul Schaub <vanitasvitae@fsfe.org>
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
/**
|
||||
* Classes related to cleartext signature verification.
|
||||
*/
|
||||
package org.pgpainless.decryption_verification.cleartext_signatures;
|
|
@ -0,0 +1,153 @@
|
|||
// SPDX-FileCopyrightText: 2023 Paul Schaub <vanitasvitae@fsfe.org>
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package org.pgpainless.decryption_verification.cleartext_signatures
|
||||
|
||||
import org.bouncycastle.bcpg.ArmoredInputStream
|
||||
import org.bouncycastle.openpgp.PGPSignatureList
|
||||
import org.bouncycastle.util.Strings
|
||||
import org.pgpainless.exception.WrongConsumingMethodException
|
||||
import org.pgpainless.implementation.ImplementationFactory
|
||||
import org.pgpainless.util.ArmoredInputStreamFactory
|
||||
import java.io.*
|
||||
import kotlin.jvm.Throws
|
||||
|
||||
/**
|
||||
* Utility class to deal with cleartext-signed messages.
|
||||
* Based on Bouncycastle's [org.bouncycastle.openpgp.examples.ClearSignedFileProcessor].
|
||||
*/
|
||||
class ClearsignedMessageUtil {
|
||||
|
||||
companion object {
|
||||
|
||||
/**
|
||||
* Dearmor a clearsigned message, detach the inband signatures and write the plaintext message to the provided
|
||||
* messageOutputStream.
|
||||
*
|
||||
* @param clearsignedInputStream input stream containing a clearsigned message
|
||||
* @param messageOutputStream output stream to which the dearmored message shall be written
|
||||
* @return signatures
|
||||
*
|
||||
* @throws IOException if the message is not clearsigned or some other IO error happens
|
||||
* @throws WrongConsumingMethodException in case the armored message is not cleartext signed
|
||||
*/
|
||||
@JvmStatic
|
||||
@Throws(WrongConsumingMethodException::class, IOException::class)
|
||||
fun detachSignaturesFromInbandClearsignedMessage(
|
||||
clearsignedInputStream: InputStream,
|
||||
messageOutputStream: OutputStream): PGPSignatureList {
|
||||
val input: ArmoredInputStream = if (clearsignedInputStream is ArmoredInputStream) {
|
||||
clearsignedInputStream
|
||||
} else {
|
||||
ArmoredInputStreamFactory.get(clearsignedInputStream)
|
||||
}
|
||||
|
||||
if (!input.isClearText) {
|
||||
throw WrongConsumingMethodException("Message isn't using the Cleartext Signature Framework.")
|
||||
}
|
||||
|
||||
BufferedOutputStream(messageOutputStream).use { output ->
|
||||
val lineOut = ByteArrayOutputStream()
|
||||
var lookAhead = readInputLine(lineOut, input)
|
||||
val lineSep = getLineSeparator()
|
||||
|
||||
if (lookAhead != -1 && input.isClearText) {
|
||||
var line = lineOut.toByteArray()
|
||||
output.write(line, 0, getLengthWithoutSeparatorOrTrailingWhitespace(line))
|
||||
|
||||
while (lookAhead != -1 && input.isClearText) {
|
||||
lookAhead = readInputLine(lineOut, lookAhead, input)
|
||||
line = lineOut.toByteArray()
|
||||
output.write(lineSep)
|
||||
output.write(line, 0, getLengthWithoutSeparatorOrTrailingWhitespace(line))
|
||||
}
|
||||
} else {
|
||||
if (lookAhead != -1) {
|
||||
val line = lineOut.toByteArray()
|
||||
output.write(line, 0, getLengthWithoutSeparatorOrTrailingWhitespace(line))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val objectFactory = ImplementationFactory.getInstance().getPGPObjectFactory(input)
|
||||
val next = objectFactory.nextObject() ?: PGPSignatureList(arrayOf())
|
||||
return next as PGPSignatureList
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
private fun readInputLine(bOut: ByteArrayOutputStream, fIn: InputStream): Int {
|
||||
bOut.reset()
|
||||
|
||||
var lookAhead = -1
|
||||
var ch: Int
|
||||
|
||||
while (fIn.read().also { ch = it } >= 0) {
|
||||
bOut.write(ch)
|
||||
if (ch == '\r'.code || ch == '\n'.code) {
|
||||
lookAhead = readPassedEOL(bOut, ch, fIn)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return lookAhead
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
private fun readInputLine(bOut: ByteArrayOutputStream, lookAhead: Int, fIn: InputStream): Int {
|
||||
var mLookAhead = lookAhead
|
||||
bOut.reset()
|
||||
var ch = mLookAhead
|
||||
do {
|
||||
bOut.write(ch)
|
||||
if (ch == '\r'.code || ch == '\n'.code) {
|
||||
mLookAhead = readPassedEOL(bOut, ch, fIn)
|
||||
break
|
||||
}
|
||||
} while (fIn.read().also { ch = it } >= 0)
|
||||
if (ch < 0) {
|
||||
mLookAhead = -1
|
||||
}
|
||||
return mLookAhead
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
private fun readPassedEOL(bOut: ByteArrayOutputStream, lastCh: Int, fIn: InputStream): Int {
|
||||
var lookAhead = fIn.read()
|
||||
if (lastCh == '\r'.code && lookAhead == '\n'.code) {
|
||||
bOut.write(lookAhead)
|
||||
lookAhead = fIn.read()
|
||||
}
|
||||
return lookAhead
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
private fun getLineSeparator(): ByteArray {
|
||||
val nl = Strings.lineSeparator()
|
||||
val nlBytes = ByteArray(nl.length)
|
||||
for (i in nlBytes.indices) {
|
||||
nlBytes[i] = nl[i].code.toByte()
|
||||
}
|
||||
return nlBytes
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
private fun getLengthWithoutSeparatorOrTrailingWhitespace(line: ByteArray): Int {
|
||||
var end = line.size - 1
|
||||
while (end >= 0 && isWhiteSpace(line[end])) {
|
||||
end--
|
||||
}
|
||||
return end + 1
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
private fun isLineEnding(b: Byte): Boolean {
|
||||
return b == '\r'.code.toByte() || b == '\n'.code.toByte()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
private fun isWhiteSpace(b: Byte): Boolean {
|
||||
return isLineEnding(b) || b == '\t'.code.toByte() || b == ' '.code.toByte()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
// SPDX-FileCopyrightText: 2023 Paul Schaub <vanitasvitae@fsfe.org>
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package org.pgpainless.decryption_verification.cleartext_signatures
|
||||
|
||||
import java.io.ByteArrayInputStream
|
||||
import java.io.ByteArrayOutputStream
|
||||
|
||||
/**
|
||||
* Implementation of the [MultiPassStrategy].
|
||||
* This class keeps the read data in memory by caching the data inside a [ByteArrayOutputStream].
|
||||
*
|
||||
* Note, that this class is suitable and efficient for processing small amounts of data.
|
||||
* For larger data like encrypted files, use of the [WriteToFileMultiPassStrategy] is recommended to
|
||||
* prevent [OutOfMemoryError] and other issues.
|
||||
*/
|
||||
class InMemoryMultiPassStrategy : MultiPassStrategy {
|
||||
|
||||
private val cache = ByteArrayOutputStream()
|
||||
|
||||
override val messageOutputStream: ByteArrayOutputStream
|
||||
get() = cache
|
||||
|
||||
override val messageInputStream: ByteArrayInputStream
|
||||
get() = ByteArrayInputStream(getBytes())
|
||||
|
||||
fun getBytes(): ByteArray = messageOutputStream.toByteArray()
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
// SPDX-FileCopyrightText: 2023 Paul Schaub <vanitasvitae@fsfe.org>
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package org.pgpainless.decryption_verification.cleartext_signatures
|
||||
|
||||
import java.io.*
|
||||
|
||||
/**
|
||||
* Since for verification of cleartext signed messages, we need to read the whole data twice in order to verify signatures,
|
||||
* a strategy for how to cache the read data is required.
|
||||
* Otherwise, large data kept in memory could cause an [OutOfMemoryError] or other issues.
|
||||
*
|
||||
* This is an Interface that describes a strategy to deal with the fact that detached signatures require multiple passes
|
||||
* to do verification.
|
||||
*
|
||||
* This interface can be used to write the signed data stream out via [messageOutputStream] and later
|
||||
* get access to the data again via [messageInputStream].
|
||||
* Thereby the detail where the data is being stored (memory, file, etc.) can be abstracted away.
|
||||
*/
|
||||
interface MultiPassStrategy {
|
||||
|
||||
/**
|
||||
* Provide an [OutputStream] into which the signed data can be read into.
|
||||
*
|
||||
* @return output stream
|
||||
* @throws IOException io error
|
||||
*/
|
||||
val messageOutputStream: OutputStream
|
||||
|
||||
/**
|
||||
* Provide an [InputStream] which contains the data that was previously written away in
|
||||
* [messageOutputStream].
|
||||
*
|
||||
* As there may be multiple signatures that need to be processed, each call of this method MUST return
|
||||
* a new [InputStream].
|
||||
*
|
||||
* @return input stream
|
||||
* @throws IOException io error
|
||||
*/
|
||||
val messageInputStream: InputStream
|
||||
|
||||
companion object {
|
||||
|
||||
/**
|
||||
* Write the message content out to a file and re-read it to verify signatures.
|
||||
* This strategy is best suited for larger messages (e.g. plaintext signed files) which might not fit into memory.
|
||||
* After the message has been processed completely, the messages content are available at the provided file.
|
||||
*
|
||||
* @param file target file
|
||||
* @return strategy
|
||||
*/
|
||||
@JvmStatic
|
||||
fun writeMessageToFile(file: File): MultiPassStrategy {
|
||||
return WriteToFileMultiPassStrategy(file)
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the message content into memory.
|
||||
* This strategy is best suited for small messages which fit into memory.
|
||||
* After the message has been processed completely, the message content can be accessed by calling
|
||||
* [ByteArrayOutputStream.toByteArray] on [messageOutputStream].
|
||||
*
|
||||
* @return strategy
|
||||
*/
|
||||
@JvmStatic
|
||||
fun keepMessageInMemory(): InMemoryMultiPassStrategy {
|
||||
return InMemoryMultiPassStrategy()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
// SPDX-FileCopyrightText: 2023 Paul Schaub <vanitasvitae@fsfe.org>
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package org.pgpainless.decryption_verification.cleartext_signatures
|
||||
|
||||
import java.io.*
|
||||
|
||||
/**
|
||||
* Implementation of the [MultiPassStrategy].
|
||||
* When processing signed data the first time, the data is being written out into a file.
|
||||
* For the second pass, that file is being read again.
|
||||
*
|
||||
* This strategy is recommended when larger amounts of data need to be processed.
|
||||
* For smaller files, [InMemoryMultiPassStrategy] yields higher efficiency.
|
||||
*
|
||||
* @param file file to write the data to and read from
|
||||
*/
|
||||
class WriteToFileMultiPassStrategy(
|
||||
private val file: File
|
||||
) : MultiPassStrategy {
|
||||
|
||||
override val messageOutputStream: OutputStream
|
||||
@Throws(IOException::class)
|
||||
get() {
|
||||
if (!file.exists()) {
|
||||
if (!file.createNewFile()) {
|
||||
throw IOException("New file '${file.absolutePath}' could not be created.")
|
||||
}
|
||||
}
|
||||
return FileOutputStream(file)
|
||||
}
|
||||
|
||||
override val messageInputStream: InputStream
|
||||
@Throws(IOException::class)
|
||||
get() {
|
||||
if (!file.exists()) {
|
||||
throw IOException("File '${file.absolutePath}' does no longer exist.")
|
||||
}
|
||||
return FileInputStream(file)
|
||||
}
|
||||
|
||||
}
|
|
@ -69,7 +69,7 @@ public class InlineDetachImpl implements InlineDetach {
|
|||
if (armorIn.isClearText()) {
|
||||
try {
|
||||
signatures = ClearsignedMessageUtil.detachSignaturesFromInbandClearsignedMessage(armorIn, messageOutputStream);
|
||||
if (signatures == null) {
|
||||
if (signatures.isEmpty()) {
|
||||
throw new SOPGPException.BadData("Data did not contain OpenPGP signatures.");
|
||||
}
|
||||
} catch (WrongConsumingMethodException e) {
|
||||
|
|
Loading…
Reference in a new issue