mirror of
https://github.com/pgpainless/pgpainless.git
synced 2025-09-09 18:29:39 +02:00
Improve API for signatures in results
This commit is contained in:
parent
049f7422c0
commit
335cf8d162
9 changed files with 91 additions and 50 deletions
|
@ -15,8 +15,8 @@ import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
import org.bouncycastle.bcpg.ArmoredOutputStream;
|
import org.bouncycastle.bcpg.ArmoredOutputStream;
|
||||||
import org.bouncycastle.openpgp.PGPException;
|
import org.bouncycastle.openpgp.PGPException;
|
||||||
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
|
||||||
import org.bouncycastle.openpgp.PGPSignature;
|
import org.bouncycastle.openpgp.PGPSignature;
|
||||||
|
import org.bouncycastle.openpgp.api.OpenPGPKey;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.pgpainless.PGPainless;
|
import org.pgpainless.PGPainless;
|
||||||
import org.pgpainless.algorithm.CompressionAlgorithm;
|
import org.pgpainless.algorithm.CompressionAlgorithm;
|
||||||
|
@ -350,12 +350,13 @@ public class RoundTripInlineSignInlineVerifyCmdTest extends CLITest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void createMalformedMessage() throws IOException, PGPException {
|
public void createMalformedMessage() throws IOException, PGPException {
|
||||||
|
PGPainless api = PGPainless.getInstance();
|
||||||
String msg = "Hello, World!\n";
|
String msg = "Hello, World!\n";
|
||||||
PGPSecretKeyRing key = PGPainless.readKeyRing().secretKeyRing(KEY_2);
|
OpenPGPKey key = api.readKey().parseKey(KEY_2);
|
||||||
ByteArrayOutputStream ciphertext = new ByteArrayOutputStream();
|
ByteArrayOutputStream ciphertext = new ByteArrayOutputStream();
|
||||||
EncryptionStream encryptionStream = PGPainless.encryptAndOrSign()
|
EncryptionStream encryptionStream = api.generateMessage()
|
||||||
.onOutputStream(ciphertext)
|
.onOutputStream(ciphertext)
|
||||||
.withOptions(ProducerOptions.sign(SigningOptions.get()
|
.withOptions(ProducerOptions.sign(SigningOptions.get(api)
|
||||||
.addDetachedSignature(SecretKeyRingProtector.unprotectedKeys(), key)
|
.addDetachedSignature(SecretKeyRingProtector.unprotectedKeys(), key)
|
||||||
).overrideCompressionAlgorithm(CompressionAlgorithm.UNCOMPRESSED)
|
).overrideCompressionAlgorithm(CompressionAlgorithm.UNCOMPRESSED)
|
||||||
.setAsciiArmor(false));
|
.setAsciiArmor(false));
|
||||||
|
|
|
@ -152,7 +152,9 @@ class PGPainless(
|
||||||
*/
|
*/
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@JvmOverloads
|
@JvmOverloads
|
||||||
@Deprecated("Call buildKey() on an instance of PGPainless instead.")
|
@Deprecated(
|
||||||
|
"Call buildKey() on an instance of PGPainless instead.",
|
||||||
|
replaceWith = ReplaceWith("buildKey(version)"))
|
||||||
fun buildKeyRing(version: OpenPGPKeyVersion = OpenPGPKeyVersion.v4): KeyRingBuilder =
|
fun buildKeyRing(version: OpenPGPKeyVersion = OpenPGPKeyVersion.v4): KeyRingBuilder =
|
||||||
getInstance().buildKey(version)
|
getInstance().buildKey(version)
|
||||||
|
|
||||||
|
@ -186,7 +188,8 @@ class PGPainless(
|
||||||
* @throws PGPException in case of an error
|
* @throws PGPException in case of an error
|
||||||
*/
|
*/
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@Deprecated("Use mergeCertificate() instead.")
|
@Deprecated(
|
||||||
|
"Use mergeCertificate() instead.", replaceWith = ReplaceWith("mergeCertificate()"))
|
||||||
fun mergeCertificate(
|
fun mergeCertificate(
|
||||||
originalCopy: PGPPublicKeyRing,
|
originalCopy: PGPPublicKeyRing,
|
||||||
updatedCopy: PGPPublicKeyRing
|
updatedCopy: PGPPublicKeyRing
|
||||||
|
|
|
@ -779,34 +779,37 @@ class OpenPgpMessageInputStream(
|
||||||
fun addDetachedSignature(signature: PGPSignature) {
|
fun addDetachedSignature(signature: PGPSignature) {
|
||||||
val check = initializeSignature(signature)
|
val check = initializeSignature(signature)
|
||||||
val keyId = signature.issuerKeyId
|
val keyId = signature.issuerKeyId
|
||||||
if (check != null) {
|
if (check.issuer != null) {
|
||||||
detachedSignatures.add(check)
|
detachedSignatures.add(check)
|
||||||
} else {
|
} else {
|
||||||
LOGGER.debug(
|
LOGGER.debug(
|
||||||
"No suitable certificate for verification of signature by key ${keyId.openPgpKeyId()} found.")
|
"No suitable certificate for verification of signature by key ${keyId.openPgpKeyId()} found.")
|
||||||
detachedSignaturesWithMissingCert.add(
|
detachedSignaturesWithMissingCert.add(
|
||||||
SignatureVerification.Failure(
|
SignatureVerification.Failure(
|
||||||
signature, null, SignatureValidationException("Missing verification key.")))
|
check, SignatureValidationException("Missing verification key.")))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addPrependedSignature(signature: PGPSignature) {
|
fun addPrependedSignature(signature: PGPSignature) {
|
||||||
val check = initializeSignature(signature)
|
val check = initializeSignature(signature)
|
||||||
val keyId = signature.issuerKeyId
|
val keyId = signature.issuerKeyId
|
||||||
if (check != null) {
|
if (check.issuer != null) {
|
||||||
prependedSignatures.add(check)
|
prependedSignatures.add(check)
|
||||||
} else {
|
} else {
|
||||||
LOGGER.debug(
|
LOGGER.debug(
|
||||||
"No suitable certificate for verification of signature by key ${keyId.openPgpKeyId()} found.")
|
"No suitable certificate for verification of signature by key ${keyId.openPgpKeyId()} found.")
|
||||||
prependedSignaturesWithMissingCert.add(
|
prependedSignaturesWithMissingCert.add(
|
||||||
SignatureVerification.Failure(
|
SignatureVerification.Failure(
|
||||||
signature, null, SignatureValidationException("Missing verification key")))
|
check, SignatureValidationException("Missing verification key")))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun initializeSignature(signature: PGPSignature): OpenPGPDocumentSignature? {
|
fun initializeSignature(signature: PGPSignature): OpenPGPDocumentSignature {
|
||||||
val certificate = findCertificate(signature) ?: return null
|
val certificate =
|
||||||
val publicKey = certificate.getSigningKeyFor(signature) ?: return null
|
findCertificate(signature) ?: return OpenPGPDocumentSignature(signature, null)
|
||||||
|
val publicKey =
|
||||||
|
certificate.getSigningKeyFor(signature)
|
||||||
|
?: return OpenPGPDocumentSignature(signature, null)
|
||||||
initialize(signature, publicKey.pgpPublicKey)
|
initialize(signature, publicKey.pgpPublicKey)
|
||||||
return OpenPGPDocumentSignature(signature, publicKey)
|
return OpenPGPDocumentSignature(signature, publicKey)
|
||||||
}
|
}
|
||||||
|
@ -845,12 +848,7 @@ class OpenPgpMessageInputStream(
|
||||||
val documentSignature =
|
val documentSignature =
|
||||||
OpenPGPDocumentSignature(
|
OpenPGPDocumentSignature(
|
||||||
signature, check.verificationKeys.getSigningKeyFor(signature))
|
signature, check.verificationKeys.getSigningKeyFor(signature))
|
||||||
val verification =
|
val verification = SignatureVerification(documentSignature)
|
||||||
SignatureVerification(
|
|
||||||
signature,
|
|
||||||
SubkeyIdentifier(
|
|
||||||
check.verificationKeys.pgpPublicKeyRing,
|
|
||||||
check.onePassSignature.keyIdentifier))
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
signature.assertCreatedInBounds(
|
signature.assertCreatedInBounds(
|
||||||
|
@ -879,7 +877,8 @@ class OpenPgpMessageInputStream(
|
||||||
"No suitable certificate for verification of signature by key ${signature.issuerKeyId.openPgpKeyId()} found.")
|
"No suitable certificate for verification of signature by key ${signature.issuerKeyId.openPgpKeyId()} found.")
|
||||||
inbandSignaturesWithMissingCert.add(
|
inbandSignaturesWithMissingCert.add(
|
||||||
SignatureVerification.Failure(
|
SignatureVerification.Failure(
|
||||||
signature, null, SignatureValidationException("Missing verification key.")))
|
OpenPGPDocumentSignature(signature, null),
|
||||||
|
SignatureValidationException("Missing verification key.")))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -967,8 +966,7 @@ class OpenPgpMessageInputStream(
|
||||||
|
|
||||||
fun finish(layer: Layer) {
|
fun finish(layer: Layer) {
|
||||||
for (detached in detachedSignatures) {
|
for (detached in detachedSignatures) {
|
||||||
val verification =
|
val verification = SignatureVerification(detached)
|
||||||
SignatureVerification(detached.signature, SubkeyIdentifier(detached.issuer))
|
|
||||||
try {
|
try {
|
||||||
detached.signature.assertCreatedInBounds(
|
detached.signature.assertCreatedInBounds(
|
||||||
options.getVerifyNotBefore(), options.getVerifyNotAfter())
|
options.getVerifyNotBefore(), options.getVerifyNotAfter())
|
||||||
|
@ -988,8 +986,7 @@ class OpenPgpMessageInputStream(
|
||||||
}
|
}
|
||||||
|
|
||||||
for (prepended in prependedSignatures) {
|
for (prepended in prependedSignatures) {
|
||||||
val verification =
|
val verification = SignatureVerification(prepended)
|
||||||
SignatureVerification(prepended.signature, SubkeyIdentifier(prepended.issuer))
|
|
||||||
try {
|
try {
|
||||||
prepended.signature.assertCreatedInBounds(
|
prepended.signature.assertCreatedInBounds(
|
||||||
options.getVerifyNotBefore(), options.getVerifyNotAfter())
|
options.getVerifyNotBefore(), options.getVerifyNotAfter())
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
package org.pgpainless.decryption_verification
|
package org.pgpainless.decryption_verification
|
||||||
|
|
||||||
import org.bouncycastle.openpgp.PGPSignature
|
import org.bouncycastle.openpgp.PGPSignature
|
||||||
|
import org.bouncycastle.openpgp.api.OpenPGPSignature.OpenPGPDocumentSignature
|
||||||
import org.pgpainless.decryption_verification.SignatureVerification.Failure
|
import org.pgpainless.decryption_verification.SignatureVerification.Failure
|
||||||
import org.pgpainless.exception.SignatureValidationException
|
import org.pgpainless.exception.SignatureValidationException
|
||||||
import org.pgpainless.key.SubkeyIdentifier
|
import org.pgpainless.key.SubkeyIdentifier
|
||||||
|
@ -20,7 +21,10 @@ import org.pgpainless.signature.SignatureUtils
|
||||||
* @param signingKey [SubkeyIdentifier] of the (sub-) key that is used for signature verification.
|
* @param signingKey [SubkeyIdentifier] of the (sub-) key that is used for signature verification.
|
||||||
* Note, that this might be null, e.g. in case of a [Failure] due to missing verification key.
|
* Note, that this might be null, e.g. in case of a [Failure] due to missing verification key.
|
||||||
*/
|
*/
|
||||||
data class SignatureVerification(val signature: PGPSignature, val signingKey: SubkeyIdentifier) {
|
data class SignatureVerification(val documentSignature: OpenPGPDocumentSignature) {
|
||||||
|
|
||||||
|
val signature: PGPSignature = documentSignature.signature
|
||||||
|
val signingKey: SubkeyIdentifier = SubkeyIdentifier(documentSignature.issuer)
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
return "Signature: ${SignatureUtils.getSignatureDigestPrefix(signature)};" +
|
return "Signature: ${SignatureUtils.getSignatureDigestPrefix(signature)};" +
|
||||||
|
@ -36,15 +40,16 @@ data class SignatureVerification(val signature: PGPSignature, val signingKey: Su
|
||||||
* @param validationException exception that caused the verification to fail
|
* @param validationException exception that caused the verification to fail
|
||||||
*/
|
*/
|
||||||
data class Failure(
|
data class Failure(
|
||||||
val signature: PGPSignature,
|
val documentSignature: OpenPGPDocumentSignature,
|
||||||
val signingKey: SubkeyIdentifier?,
|
|
||||||
val validationException: SignatureValidationException
|
val validationException: SignatureValidationException
|
||||||
) {
|
) {
|
||||||
|
val signature: PGPSignature = documentSignature.signature
|
||||||
|
val signingKey: SubkeyIdentifier? = documentSignature.issuer?.let { SubkeyIdentifier(it) }
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
verification: SignatureVerification,
|
verification: SignatureVerification,
|
||||||
validationException: SignatureValidationException
|
validationException: SignatureValidationException
|
||||||
) : this(verification.signature, verification.signingKey, validationException)
|
) : this(verification.documentSignature, validationException)
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
return "Signature: ${SignatureUtils.getSignatureDigestPrefix(signature)}; Key: ${signingKey?.toString() ?: "null"}; Failure: ${validationException.message}"
|
return "Signature: ${SignatureUtils.getSignatureDigestPrefix(signature)}; Key: ${signingKey?.toString() ?: "null"}; Failure: ${validationException.message}"
|
||||||
|
|
|
@ -9,6 +9,7 @@ import org.bouncycastle.openpgp.PGPLiteralData
|
||||||
import org.bouncycastle.openpgp.PGPPublicKeyRing
|
import org.bouncycastle.openpgp.PGPPublicKeyRing
|
||||||
import org.bouncycastle.openpgp.PGPSignature
|
import org.bouncycastle.openpgp.PGPSignature
|
||||||
import org.bouncycastle.openpgp.api.OpenPGPCertificate
|
import org.bouncycastle.openpgp.api.OpenPGPCertificate
|
||||||
|
import org.bouncycastle.openpgp.api.OpenPGPSignature.OpenPGPDocumentSignature
|
||||||
import org.pgpainless.algorithm.CompressionAlgorithm
|
import org.pgpainless.algorithm.CompressionAlgorithm
|
||||||
import org.pgpainless.algorithm.StreamEncoding
|
import org.pgpainless.algorithm.StreamEncoding
|
||||||
import org.pgpainless.algorithm.SymmetricKeyAlgorithm
|
import org.pgpainless.algorithm.SymmetricKeyAlgorithm
|
||||||
|
@ -19,13 +20,25 @@ import org.pgpainless.util.MultiMap
|
||||||
data class EncryptionResult(
|
data class EncryptionResult(
|
||||||
val encryptionAlgorithm: SymmetricKeyAlgorithm,
|
val encryptionAlgorithm: SymmetricKeyAlgorithm,
|
||||||
val compressionAlgorithm: CompressionAlgorithm,
|
val compressionAlgorithm: CompressionAlgorithm,
|
||||||
val detachedSignatures: MultiMap<SubkeyIdentifier, PGPSignature>,
|
val detachedDocumentSignatures: OpenPGPSignatureSet<OpenPGPDocumentSignature>,
|
||||||
val recipients: Set<SubkeyIdentifier>,
|
val recipients: Set<SubkeyIdentifier>,
|
||||||
val fileName: String,
|
val fileName: String,
|
||||||
val modificationDate: Date,
|
val modificationDate: Date,
|
||||||
val fileEncoding: StreamEncoding
|
val fileEncoding: StreamEncoding
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
@Deprecated(
|
||||||
|
"Use detachedSignatures instead", replaceWith = ReplaceWith("detachedDocumentSignatures"))
|
||||||
|
// TODO: Remove in 2.1
|
||||||
|
val detachedSignatures: MultiMap<SubkeyIdentifier, PGPSignature>
|
||||||
|
get() {
|
||||||
|
val map = MultiMap<SubkeyIdentifier, PGPSignature>()
|
||||||
|
detachedDocumentSignatures.signatures
|
||||||
|
.map { SubkeyIdentifier(it.issuer) to it.signature }
|
||||||
|
.forEach { map.put(it.first, it.second) }
|
||||||
|
return map
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return true, if the message is marked as for-your-eyes-only. This is typically done by
|
* Return true, if the message is marked as for-your-eyes-only. This is typically done by
|
||||||
* setting the filename "_CONSOLE".
|
* setting the filename "_CONSOLE".
|
||||||
|
@ -59,7 +72,7 @@ data class EncryptionResult(
|
||||||
var _encryptionAlgorithm: SymmetricKeyAlgorithm? = null
|
var _encryptionAlgorithm: SymmetricKeyAlgorithm? = null
|
||||||
var _compressionAlgorithm: CompressionAlgorithm? = null
|
var _compressionAlgorithm: CompressionAlgorithm? = null
|
||||||
|
|
||||||
val detachedSignatures: MultiMap<SubkeyIdentifier, PGPSignature> = MultiMap()
|
val detachedSignatures: MutableList<OpenPGPDocumentSignature> = mutableListOf()
|
||||||
val recipients: Set<SubkeyIdentifier> = mutableSetOf()
|
val recipients: Set<SubkeyIdentifier> = mutableSetOf()
|
||||||
private var _fileName = ""
|
private var _fileName = ""
|
||||||
private var _modificationDate = Date(0)
|
private var _modificationDate = Date(0)
|
||||||
|
@ -85,10 +98,9 @@ data class EncryptionResult(
|
||||||
(recipients as MutableSet).add(recipient)
|
(recipients as MutableSet).add(recipient)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addDetachedSignature(
|
fun addDetachedSignature(signature: OpenPGPDocumentSignature): Builder = apply {
|
||||||
signingSubkeyIdentifier: SubkeyIdentifier,
|
detachedSignatures.add(signature)
|
||||||
detachedSignature: PGPSignature
|
}
|
||||||
) = apply { detachedSignatures.put(signingSubkeyIdentifier, detachedSignature) }
|
|
||||||
|
|
||||||
fun build(): EncryptionResult {
|
fun build(): EncryptionResult {
|
||||||
checkNotNull(_encryptionAlgorithm) { "Encryption algorithm not set." }
|
checkNotNull(_encryptionAlgorithm) { "Encryption algorithm not set." }
|
||||||
|
@ -97,7 +109,7 @@ data class EncryptionResult(
|
||||||
return EncryptionResult(
|
return EncryptionResult(
|
||||||
_encryptionAlgorithm!!,
|
_encryptionAlgorithm!!,
|
||||||
_compressionAlgorithm!!,
|
_compressionAlgorithm!!,
|
||||||
detachedSignatures,
|
OpenPGPSignatureSet(detachedSignatures),
|
||||||
recipients,
|
recipients,
|
||||||
_fileName,
|
_fileName,
|
||||||
_modificationDate,
|
_modificationDate,
|
||||||
|
|
|
@ -13,11 +13,11 @@ 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.PGPLiteralDataGenerator
|
||||||
|
import org.bouncycastle.openpgp.api.OpenPGPSignature.OpenPGPDocumentSignature
|
||||||
import org.pgpainless.PGPainless
|
import org.pgpainless.PGPainless
|
||||||
import org.pgpainless.algorithm.CompressionAlgorithm
|
import org.pgpainless.algorithm.CompressionAlgorithm
|
||||||
import org.pgpainless.algorithm.StreamEncoding
|
import org.pgpainless.algorithm.StreamEncoding
|
||||||
import org.pgpainless.algorithm.SymmetricKeyAlgorithm
|
import org.pgpainless.algorithm.SymmetricKeyAlgorithm
|
||||||
import org.pgpainless.key.SubkeyIdentifier
|
|
||||||
import org.pgpainless.util.ArmoredOutputStreamFactory
|
import org.pgpainless.util.ArmoredOutputStreamFactory
|
||||||
|
|
||||||
// 1 << 8 causes wrong partial body length encoding
|
// 1 << 8 causes wrong partial body length encoding
|
||||||
|
@ -246,8 +246,9 @@ class EncryptionStream(
|
||||||
|
|
||||||
options.signingOptions.signingMethods.entries.reversed().forEach { (key, method) ->
|
options.signingOptions.signingMethods.entries.reversed().forEach { (key, method) ->
|
||||||
method.signatureGenerator.generate().let { sig ->
|
method.signatureGenerator.generate().let { sig ->
|
||||||
|
val documentSignature = OpenPGPDocumentSignature(sig, key.publicKey)
|
||||||
if (method.isDetached) {
|
if (method.isDetached) {
|
||||||
resultBuilder.addDetachedSignature(SubkeyIdentifier(key), sig)
|
resultBuilder.addDetachedSignature(documentSignature)
|
||||||
}
|
}
|
||||||
if (!method.isDetached || options.isCleartextSigned) {
|
if (!method.isDetached || options.isCleartextSigned) {
|
||||||
sig.encode(signatureLayerStream)
|
sig.encode(signatureLayerStream)
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
// SPDX-FileCopyrightText: 2025 Paul Schaub <vanitasvitae@fsfe.org>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package org.pgpainless.encryption_signing
|
||||||
|
|
||||||
|
import org.bouncycastle.openpgp.api.OpenPGPCertificate
|
||||||
|
import org.bouncycastle.openpgp.api.OpenPGPSignature
|
||||||
|
|
||||||
|
class OpenPGPSignatureSet<S : OpenPGPSignature>(val signatures: List<S>) : Iterable<S> {
|
||||||
|
|
||||||
|
fun getSignaturesBy(cert: OpenPGPCertificate): List<S> =
|
||||||
|
signatures.filter { sig -> sig.signature.keyIdentifiers.any { cert.getKey(it) != null } }
|
||||||
|
|
||||||
|
fun getSignaturesBy(componentKey: OpenPGPCertificate.OpenPGPComponentKey): List<S> =
|
||||||
|
signatures.filter { sig ->
|
||||||
|
sig.signature.keyIdentifiers.any { componentKey.keyIdentifier.matches(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun iterator(): Iterator<S> {
|
||||||
|
return signatures.iterator()
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,9 +14,9 @@ import java.io.InputStream;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
import org.bouncycastle.openpgp.PGPException;
|
import org.bouncycastle.openpgp.PGPException;
|
||||||
import org.bouncycastle.openpgp.PGPSignature;
|
|
||||||
import org.bouncycastle.openpgp.api.OpenPGPCertificate;
|
import org.bouncycastle.openpgp.api.OpenPGPCertificate;
|
||||||
import org.bouncycastle.openpgp.api.OpenPGPKey;
|
import org.bouncycastle.openpgp.api.OpenPGPKey;
|
||||||
|
import org.bouncycastle.openpgp.api.OpenPGPSignature;
|
||||||
import org.bouncycastle.util.io.Streams;
|
import org.bouncycastle.util.io.Streams;
|
||||||
import org.junit.jupiter.api.BeforeAll;
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
@ -26,7 +26,6 @@ import org.pgpainless.encryption_signing.EncryptionResult;
|
||||||
import org.pgpainless.encryption_signing.EncryptionStream;
|
import org.pgpainless.encryption_signing.EncryptionStream;
|
||||||
import org.pgpainless.encryption_signing.ProducerOptions;
|
import org.pgpainless.encryption_signing.ProducerOptions;
|
||||||
import org.pgpainless.encryption_signing.SigningOptions;
|
import org.pgpainless.encryption_signing.SigningOptions;
|
||||||
import org.pgpainless.key.SubkeyIdentifier;
|
|
||||||
import org.pgpainless.key.protection.SecretKeyRingProtector;
|
import org.pgpainless.key.protection.SecretKeyRingProtector;
|
||||||
import org.pgpainless.util.ArmorUtils;
|
import org.pgpainless.util.ArmorUtils;
|
||||||
|
|
||||||
|
@ -70,7 +69,7 @@ public class Sign {
|
||||||
/**
|
/**
|
||||||
* Demonstration of how to create a detached signature for a message.
|
* Demonstration of how to create a detached signature for a message.
|
||||||
* A detached signature can be distributed alongside the message/file itself.
|
* A detached signature can be distributed alongside the message/file itself.
|
||||||
*
|
* <p>
|
||||||
* The message/file doesn't need to be altered for detached signature creation.
|
* The message/file doesn't need to be altered for detached signature creation.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
|
@ -82,9 +81,9 @@ public class Sign {
|
||||||
// After signing, you want to distribute the original value of 'message' along with the 'detachedSignature'
|
// After signing, you want to distribute the original value of 'message' along with the 'detachedSignature'
|
||||||
// from below.
|
// from below.
|
||||||
ByteArrayOutputStream ignoreMe = new ByteArrayOutputStream();
|
ByteArrayOutputStream ignoreMe = new ByteArrayOutputStream();
|
||||||
EncryptionStream signingStream = PGPainless.encryptAndOrSign()
|
EncryptionStream signingStream = api.generateMessage()
|
||||||
.onOutputStream(ignoreMe)
|
.onOutputStream(ignoreMe)
|
||||||
.withOptions(ProducerOptions.sign(SigningOptions.get()
|
.withOptions(ProducerOptions.sign(SigningOptions.get(api)
|
||||||
.addDetachedSignature(protector, key, DocumentSignatureType.CANONICAL_TEXT_DOCUMENT))
|
.addDetachedSignature(protector, key, DocumentSignatureType.CANONICAL_TEXT_DOCUMENT))
|
||||||
.setAsciiArmor(false)
|
.setAsciiArmor(false)
|
||||||
);
|
);
|
||||||
|
@ -94,9 +93,9 @@ public class Sign {
|
||||||
|
|
||||||
EncryptionResult result = signingStream.getResult();
|
EncryptionResult result = signingStream.getResult();
|
||||||
|
|
||||||
OpenPGPCertificate.OpenPGPComponentKey signingKey = PGPainless.inspectKeyRing(key).getSigningSubkeys().get(0);
|
OpenPGPCertificate.OpenPGPComponentKey signingKey = api.inspect(key).getSigningSubkeys().get(0);
|
||||||
PGPSignature signature = result.getDetachedSignatures().get(new SubkeyIdentifier(signingKey)).iterator().next();
|
OpenPGPSignature.OpenPGPDocumentSignature signature = result.getDetachedDocumentSignatures().getSignaturesBy(signingKey).get(0);
|
||||||
String detachedSignature = ArmorUtils.toAsciiArmoredString(signature.getEncoded());
|
String detachedSignature = ArmorUtils.toAsciiArmoredString(signature.getSignature().getEncoded());
|
||||||
|
|
||||||
assertTrue(detachedSignature.startsWith("-----BEGIN PGP SIGNATURE-----"));
|
assertTrue(detachedSignature.startsWith("-----BEGIN PGP SIGNATURE-----"));
|
||||||
|
|
||||||
|
@ -126,9 +125,9 @@ public class Sign {
|
||||||
"limitations under the License.";
|
"limitations under the License.";
|
||||||
InputStream messageIn = new ByteArrayInputStream(message.getBytes(StandardCharsets.UTF_8));
|
InputStream messageIn = new ByteArrayInputStream(message.getBytes(StandardCharsets.UTF_8));
|
||||||
ByteArrayOutputStream signedOut = new ByteArrayOutputStream();
|
ByteArrayOutputStream signedOut = new ByteArrayOutputStream();
|
||||||
EncryptionStream signingStream = PGPainless.encryptAndOrSign()
|
EncryptionStream signingStream = api.generateMessage()
|
||||||
.onOutputStream(signedOut)
|
.onOutputStream(signedOut)
|
||||||
.withOptions(ProducerOptions.sign(SigningOptions.get()
|
.withOptions(ProducerOptions.sign(SigningOptions.get(api)
|
||||||
.addDetachedSignature(protector, key, DocumentSignatureType.CANONICAL_TEXT_DOCUMENT)) // Human-readable text document
|
.addDetachedSignature(protector, key, DocumentSignatureType.CANONICAL_TEXT_DOCUMENT)) // Human-readable text document
|
||||||
.setCleartextSigned() // <- Explicitly use Cleartext Signature Framework!!!
|
.setCleartextSigned() // <- Explicitly use Cleartext Signature Framework!!!
|
||||||
);
|
);
|
||||||
|
|
|
@ -73,16 +73,16 @@ class DetachedSignImpl(private val api: PGPainless) : DetachedSign {
|
||||||
// forget passphrases
|
// forget passphrases
|
||||||
protector.clear()
|
protector.clear()
|
||||||
|
|
||||||
val signatures = result.detachedSignatures.map { it.value }.flatten()
|
val signatures = result.detachedDocumentSignatures
|
||||||
val out =
|
val out =
|
||||||
if (armor) ArmoredOutputStreamFactory.get(outputStream) else outputStream
|
if (armor) ArmoredOutputStreamFactory.get(outputStream) else outputStream
|
||||||
|
|
||||||
signatures.forEach { it.encode(out) }
|
signatures.forEach { it.signature.encode(out) }
|
||||||
out.close()
|
out.close()
|
||||||
outputStream.close()
|
outputStream.close()
|
||||||
|
|
||||||
return SigningResult.builder()
|
return SigningResult.builder()
|
||||||
.setMicAlg(micAlgFromSignatures(signatures))
|
.setMicAlg(micAlgFromSignatures(signatures.map { it.signature }))
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue