271 lines
9.0 KiB
Kotlin
271 lines
9.0 KiB
Kotlin
// SPDX-FileCopyrightText: 2023 Paul Schaub <vanitasvitae@fsfe.org>
|
|
//
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package org.pgpainless.encryption_signing
|
|
|
|
import java.util.*
|
|
import org.bouncycastle.openpgp.PGPLiteralData
|
|
import org.pgpainless.PGPainless
|
|
import org.pgpainless.algorithm.CompressionAlgorithm
|
|
import org.pgpainless.algorithm.StreamEncoding
|
|
|
|
class ProducerOptions
|
|
private constructor(
|
|
val encryptionOptions: EncryptionOptions?,
|
|
val signingOptions: SigningOptions?
|
|
) {
|
|
|
|
private var _fileName: String = ""
|
|
private var _modificationDate: Date = PGPLiteralData.NOW
|
|
private var encodingField: StreamEncoding = StreamEncoding.BINARY
|
|
private var applyCRLFEncoding = false
|
|
private var cleartextSigned = false
|
|
private var _hideArmorHeaders = false
|
|
var isDisableAsciiArmorCRC = false
|
|
|
|
private var _compressionAlgorithmOverride: CompressionAlgorithm =
|
|
PGPainless.getPolicy().compressionAlgorithmPolicy.defaultCompressionAlgorithm
|
|
private var asciiArmor = true
|
|
private var _comment: String? = null
|
|
private var _version: String? = null
|
|
|
|
/**
|
|
* Specify, whether the result of the encryption/signing operation shall be ascii armored. The
|
|
* default value is true.
|
|
*
|
|
* @param asciiArmor ascii armor
|
|
* @return builder
|
|
*/
|
|
fun setAsciiArmor(asciiArmor: Boolean) = apply {
|
|
require(!(cleartextSigned && !asciiArmor)) {
|
|
"Cleartext signing is enabled. Cannot disable ASCII armoring."
|
|
}
|
|
this.asciiArmor = asciiArmor
|
|
}
|
|
|
|
/**
|
|
* Return true if the output of the encryption/signing operation shall be ascii armored.
|
|
*
|
|
* @return ascii armored
|
|
*/
|
|
val isAsciiArmor: Boolean
|
|
get() = asciiArmor
|
|
|
|
/**
|
|
* Set the comment header in ASCII armored output. The default value is null, which means no
|
|
* comment header is added. Multiline comments are possible using '\\n'. <br> Note: If a default
|
|
* header comment is set using [org.pgpainless.util.ArmoredOutputStreamFactory.setComment], then
|
|
* both comments will be written to the produced ASCII armor.
|
|
*
|
|
* @param comment comment header text
|
|
* @return builder
|
|
*/
|
|
fun setComment(comment: String?) = apply { _comment = comment }
|
|
|
|
/**
|
|
* Return comment set for header in ascii armored output.
|
|
*
|
|
* @return comment
|
|
*/
|
|
val comment: String?
|
|
get() = _comment
|
|
|
|
/**
|
|
* Return whether a comment was set (!= null).
|
|
*
|
|
* @return true if commend is set
|
|
*/
|
|
fun hasComment() = _comment != null
|
|
|
|
/**
|
|
* Set the version header in ASCII armored output. The default value is null, which means no
|
|
* version header is added. <br> Note: If the value is non-null, then this method overrides the
|
|
* default version header set using
|
|
* [org.pgpainless.util.ArmoredOutputStreamFactory.setVersionInfo].
|
|
*
|
|
* @param version version header, or null for no version info.
|
|
* @return builder
|
|
*/
|
|
fun setVersion(version: String?) = apply { _version = version }
|
|
|
|
/**
|
|
* Return the version info header in ascii armored output.
|
|
*
|
|
* @return version info
|
|
*/
|
|
val version: String?
|
|
get() = _version
|
|
|
|
/**
|
|
* Return whether a version header was set (!= null).
|
|
*
|
|
* @return true if version header is set
|
|
*/
|
|
fun hasVersion() = version != null
|
|
|
|
fun setCleartextSigned() = apply {
|
|
require(signingOptions != null) {
|
|
"Signing Options cannot be null if cleartext signing is enabled."
|
|
}
|
|
require(encryptionOptions == null) {
|
|
"Cannot encode encrypted message as Cleartext Signed."
|
|
}
|
|
require(signingOptions.signingMethods.values.all { it.isDetached }) {
|
|
"For cleartext signed messages, all signatures must be added as detached signatures."
|
|
}
|
|
|
|
cleartextSigned = true
|
|
asciiArmor = true
|
|
_compressionAlgorithmOverride = CompressionAlgorithm.UNCOMPRESSED
|
|
}
|
|
|
|
val isCleartextSigned: Boolean
|
|
get() = cleartextSigned
|
|
|
|
/**
|
|
* Set the name of the encrypted file. Note: This option cannot be used simultaneously with
|
|
* [setForYourEyesOnly].
|
|
*
|
|
* @param fileName name of the encrypted file
|
|
* @return this
|
|
*/
|
|
fun setFileName(fileName: String) = apply { _fileName = fileName }
|
|
|
|
/**
|
|
* Return the encrypted files name.
|
|
*
|
|
* @return file name
|
|
*/
|
|
val fileName: String
|
|
get() = _fileName
|
|
|
|
/**
|
|
* Mark the encrypted message as for-your-eyes-only by setting a special file name. Note:
|
|
* Therefore this method cannot be used simultaneously with [setFileName].
|
|
*
|
|
* @return this
|
|
* @deprecated deprecated since at least crypto-refresh-05. It is not recommended using this
|
|
* special filename in newly generated literal data packets
|
|
*/
|
|
@Deprecated("Signaling using special file name is discouraged.")
|
|
fun setForYourEyesOnly() = apply { _fileName = PGPLiteralData.CONSOLE }
|
|
|
|
/**
|
|
* Set the modification date of the encrypted file.
|
|
*
|
|
* @param modificationDate Modification date of the encrypted file.
|
|
* @return this
|
|
*/
|
|
fun setModificationDate(modificationDate: Date) = apply { _modificationDate = modificationDate }
|
|
|
|
/**
|
|
* Return the modification date of the encrypted file.
|
|
*
|
|
* @return modification date
|
|
*/
|
|
val modificationDate: Date
|
|
get() = _modificationDate
|
|
|
|
/**
|
|
* Set format metadata field of the literal data packet. Defaults to [StreamEncoding.BINARY].
|
|
* <br> This does not change the encoding of the wrapped data itself. To apply CR/LF encoding to
|
|
* your input data before processing, use [applyCRLFEncoding] instead.
|
|
*
|
|
* @param encoding encoding
|
|
* @return this
|
|
* @see <a href="https://datatracker.ietf.org/doc/html/rfc4880#section-5.9">RFC4880 §5.9.
|
|
* Literal Data Packet</a>
|
|
* @deprecated options other than the default value of {@link StreamEncoding#BINARY} are
|
|
* discouraged.
|
|
*/
|
|
@Deprecated("Options other than BINARY are discouraged.")
|
|
fun setEncoding(encoding: StreamEncoding) = apply { encodingField = encoding }
|
|
|
|
val encoding: StreamEncoding
|
|
get() = encodingField
|
|
|
|
/**
|
|
* Apply special encoding of line endings to the input data. By default, this is disabled, which
|
|
* means that the data is not altered. <br> Enabling it will change the line endings to CR/LF.
|
|
* Note: The encoding will not be reversed when decrypting, so applying CR/LF encoding will
|
|
* result in the identity "decrypt(encrypt(data)) == data == verify(sign(data))".
|
|
*
|
|
* @return this
|
|
*/
|
|
fun applyCRLFEncoding() = apply { applyCRLFEncoding = true }
|
|
|
|
/**
|
|
* Return the input encoding that will be applied before signing / encryption.
|
|
*
|
|
* @return input encoding
|
|
*/
|
|
val isApplyCRLFEncoding: Boolean
|
|
get() = applyCRLFEncoding
|
|
|
|
/**
|
|
* Override which compression algorithm shall be used.
|
|
*
|
|
* @param compressionAlgorithm compression algorithm override
|
|
* @return builder
|
|
*/
|
|
fun overrideCompressionAlgorithm(compressionAlgorithm: CompressionAlgorithm) = apply {
|
|
_compressionAlgorithmOverride = compressionAlgorithm
|
|
}
|
|
|
|
val compressionAlgorithmOverride: CompressionAlgorithm
|
|
get() = _compressionAlgorithmOverride
|
|
|
|
val isHideArmorHeaders: Boolean
|
|
get() = _hideArmorHeaders
|
|
|
|
/**
|
|
* If set to `true`, armor headers like version or comments will be omitted from armored output.
|
|
* By default, armor headers are not hidden. Note: If comments are added via [setComment], those
|
|
* are not omitted, even if [hideArmorHeaders] is set to `true`.
|
|
*
|
|
* @param hideArmorHeaders true or false
|
|
* @return this
|
|
*/
|
|
fun setHideArmorHeaders(hideArmorHeaders: Boolean) = apply {
|
|
_hideArmorHeaders = hideArmorHeaders
|
|
}
|
|
|
|
companion object {
|
|
/**
|
|
* Sign and encrypt some data.
|
|
*
|
|
* @param encryptionOptions encryption options
|
|
* @param signingOptions signing options
|
|
* @return builder
|
|
*/
|
|
@JvmStatic
|
|
fun signAndEncrypt(encryptionOptions: EncryptionOptions, signingOptions: SigningOptions) =
|
|
ProducerOptions(encryptionOptions, signingOptions)
|
|
|
|
/**
|
|
* Sign some data without encryption.
|
|
*
|
|
* @param signingOptions signing options
|
|
* @return builder
|
|
*/
|
|
@JvmStatic fun sign(signingOptions: SigningOptions) = ProducerOptions(null, signingOptions)
|
|
|
|
/**
|
|
* Encrypt some data without signing.
|
|
*
|
|
* @param encryptionOptions encryption options
|
|
* @return builder
|
|
*/
|
|
@JvmStatic
|
|
fun encrypt(encryptionOptions: EncryptionOptions) = ProducerOptions(encryptionOptions, null)
|
|
|
|
/**
|
|
* Only wrap the data in an OpenPGP packet. No encryption or signing will be applied.
|
|
*
|
|
* @return builder
|
|
*/
|
|
@JvmStatic fun noEncryptionNoSigning() = ProducerOptions(null, null)
|
|
}
|
|
}
|