mirror of
https://github.com/pgpainless/pgpainless.git
synced 2025-09-09 18:29:39 +02:00
Rework ASCII armor API
This commit is contained in:
parent
02d72c2691
commit
1b6601cc19
7 changed files with 65 additions and 19 deletions
|
@ -4,8 +4,12 @@
|
||||||
|
|
||||||
package org.pgpainless
|
package org.pgpainless
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream
|
||||||
import java.io.OutputStream
|
import java.io.OutputStream
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
import org.bouncycastle.bcpg.ArmoredOutputStream
|
||||||
|
import org.bouncycastle.bcpg.BCPGOutputStream
|
||||||
|
import org.bouncycastle.bcpg.PacketFormat
|
||||||
import org.bouncycastle.openpgp.PGPKeyRing
|
import org.bouncycastle.openpgp.PGPKeyRing
|
||||||
import org.bouncycastle.openpgp.PGPPublicKeyRing
|
import org.bouncycastle.openpgp.PGPPublicKeyRing
|
||||||
import org.bouncycastle.openpgp.PGPSecretKeyRing
|
import org.bouncycastle.openpgp.PGPSecretKeyRing
|
||||||
|
@ -16,6 +20,7 @@ import org.bouncycastle.openpgp.api.OpenPGPImplementation
|
||||||
import org.bouncycastle.openpgp.api.OpenPGPKey
|
import org.bouncycastle.openpgp.api.OpenPGPKey
|
||||||
import org.bouncycastle.openpgp.api.OpenPGPKeyGenerator
|
import org.bouncycastle.openpgp.api.OpenPGPKeyGenerator
|
||||||
import org.bouncycastle.openpgp.api.OpenPGPKeyReader
|
import org.bouncycastle.openpgp.api.OpenPGPKeyReader
|
||||||
|
import org.bouncycastle.openpgp.api.OpenPGPSignature
|
||||||
import org.bouncycastle.openpgp.api.bc.BcOpenPGPApi
|
import org.bouncycastle.openpgp.api.bc.BcOpenPGPApi
|
||||||
import org.pgpainless.algorithm.OpenPGPKeyVersion
|
import org.pgpainless.algorithm.OpenPGPKeyVersion
|
||||||
import org.pgpainless.bouncycastle.PolicyAdapter
|
import org.pgpainless.bouncycastle.PolicyAdapter
|
||||||
|
@ -59,6 +64,46 @@ class PGPainless(
|
||||||
api = BcOpenPGPApi(implementation)
|
api = BcOpenPGPApi(implementation)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@JvmOverloads
|
||||||
|
fun toAsciiArmor(
|
||||||
|
certOrKey: OpenPGPCertificate,
|
||||||
|
packetFormat: PacketFormat = PacketFormat.ROUNDTRIP
|
||||||
|
): String {
|
||||||
|
val armorBuilder = ArmoredOutputStream.builder().clearHeaders()
|
||||||
|
ArmorUtils.keyToHeader(certOrKey.primaryKey.pgpPublicKey)
|
||||||
|
.getOrDefault(ArmorUtils.HEADER_COMMENT, setOf())
|
||||||
|
.forEach { armorBuilder.addComment(it) }
|
||||||
|
return certOrKey.toAsciiArmoredString(packetFormat, armorBuilder)
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmOverloads
|
||||||
|
fun toAsciiArmor(
|
||||||
|
signature: OpenPGPSignature,
|
||||||
|
packetFormat: PacketFormat = PacketFormat.ROUNDTRIP
|
||||||
|
): String {
|
||||||
|
val armorBuilder = ArmoredOutputStream.builder().clearHeaders()
|
||||||
|
armorBuilder.addComment(signature.keyIdentifier.toPrettyPrint())
|
||||||
|
return signature.toAsciiArmoredString(packetFormat, armorBuilder)
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmOverloads
|
||||||
|
fun toAsciiArmor(
|
||||||
|
signature: PGPSignature,
|
||||||
|
packetFormat: PacketFormat = PacketFormat.ROUNDTRIP
|
||||||
|
): String {
|
||||||
|
val armorBuilder = ArmoredOutputStream.builder().clearHeaders()
|
||||||
|
OpenPGPSignature.getMostExpressiveIdentifier(signature.keyIdentifiers)?.let {
|
||||||
|
armorBuilder.addComment(it.toPrettyPrint())
|
||||||
|
}
|
||||||
|
val bOut = ByteArrayOutputStream()
|
||||||
|
val aOut = armorBuilder.build(bOut)
|
||||||
|
val pOut = BCPGOutputStream(aOut, packetFormat)
|
||||||
|
signature.encode(pOut)
|
||||||
|
pOut.close()
|
||||||
|
aOut.close()
|
||||||
|
return bOut.toString()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate a new [OpenPGPKey] from predefined templates.
|
* Generate a new [OpenPGPKey] from predefined templates.
|
||||||
*
|
*
|
||||||
|
@ -290,10 +335,13 @@ class PGPainless(
|
||||||
*/
|
*/
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun asciiArmor(key: PGPKeyRing): String =
|
fun asciiArmor(key: PGPKeyRing): String =
|
||||||
if (key is PGPSecretKeyRing) ArmorUtils.toAsciiArmoredString(key)
|
getInstance().toAsciiArmor(getInstance().toKeyOrCertificate(key))
|
||||||
else ArmorUtils.toAsciiArmoredString(key as PGPPublicKeyRing)
|
|
||||||
|
|
||||||
@JvmStatic fun asciiArmor(cert: OpenPGPCertificate) = asciiArmor(cert.pgpKeyRing)
|
@JvmStatic
|
||||||
|
@Deprecated(
|
||||||
|
"Call getInstance().toAsciiArmor(cert) instead.",
|
||||||
|
replaceWith = ReplaceWith("getInstance().toAsciiArmor(cert)"))
|
||||||
|
fun asciiArmor(cert: OpenPGPCertificate): String = getInstance().toAsciiArmor(cert)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrap a key of certificate in ASCII armor and write the result into the given
|
* Wrap a key of certificate in ASCII armor and write the result into the given
|
||||||
|
@ -318,8 +366,10 @@ class PGPainless(
|
||||||
* @throws IOException in case of an error during the armoring process
|
* @throws IOException in case of an error during the armoring process
|
||||||
*/
|
*/
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@Deprecated("Covert to OpenPGPSignature and call .toAsciiArmoredString() instead.")
|
@Deprecated(
|
||||||
fun asciiArmor(signature: PGPSignature): String = ArmorUtils.toAsciiArmoredString(signature)
|
"Call toAsciiArmor(signature) on an instance of PGPainless instead.",
|
||||||
|
replaceWith = ReplaceWith("getInstance().toAsciiArmor(signature)"))
|
||||||
|
fun asciiArmor(signature: PGPSignature): String = getInstance().toAsciiArmor(signature)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create an [EncryptionBuilder], which can be used to encrypt and/or sign data using
|
* Create an [EncryptionBuilder], which can be used to encrypt and/or sign data using
|
||||||
|
|
|
@ -229,7 +229,7 @@ class ArmorUtils {
|
||||||
* @return header map
|
* @return header map
|
||||||
*/
|
*/
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
private fun keyToHeader(publicKey: PGPPublicKey): Map<String, Set<String>> {
|
fun keyToHeader(publicKey: PGPPublicKey): Map<String, Set<String>> {
|
||||||
val headerMap = mutableMapOf<String, MutableSet<String>>()
|
val headerMap = mutableMapOf<String, MutableSet<String>>()
|
||||||
val userIds = KeyRingUtils.getUserIdsIgnoringInvalidUTF8(publicKey)
|
val userIds = KeyRingUtils.getUserIdsIgnoringInvalidUTF8(publicKey)
|
||||||
val first: String? = userIds.firstOrNull()
|
val first: String? = userIds.firstOrNull()
|
||||||
|
|
|
@ -113,10 +113,11 @@ public class CanonicalizedDataEncryptionTest {
|
||||||
|
|
||||||
@BeforeAll
|
@BeforeAll
|
||||||
public static void readKeys() throws IOException {
|
public static void readKeys() throws IOException {
|
||||||
secretKeys = PGPainless.getInstance().readKey().parseKey(KEY);
|
PGPainless api = PGPainless.getInstance();
|
||||||
|
secretKeys = api.readKey().parseKey(KEY);
|
||||||
publicKeys = secretKeys.toCertificate();
|
publicKeys = secretKeys.toCertificate();
|
||||||
// CHECKSTYLE:OFF
|
// CHECKSTYLE:OFF
|
||||||
System.out.println(PGPainless.asciiArmor(secretKeys));
|
System.out.println(api.toAsciiArmor(secretKeys));
|
||||||
// CHECKSTYLE:ON
|
// CHECKSTYLE:ON
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -599,7 +599,7 @@ class KeyRingReaderTest {
|
||||||
public void testReadKeyRingWithArmoredPublicKey() throws IOException {
|
public void testReadKeyRingWithArmoredPublicKey() throws IOException {
|
||||||
OpenPGPKey secretKeys = api.generateKey().modernKeyRing("Alice <alice@pgpainless.org>");
|
OpenPGPKey secretKeys = api.generateKey().modernKeyRing("Alice <alice@pgpainless.org>");
|
||||||
OpenPGPCertificate publicKeys = secretKeys.toCertificate();
|
OpenPGPCertificate publicKeys = secretKeys.toCertificate();
|
||||||
String armored = PGPainless.asciiArmor(publicKeys);
|
String armored = api.toAsciiArmor(publicKeys);
|
||||||
|
|
||||||
PGPKeyRing keyRing = PGPainless.readKeyRing()
|
PGPKeyRing keyRing = PGPainless.readKeyRing()
|
||||||
.keyRing(armored);
|
.keyRing(armored);
|
||||||
|
|
|
@ -132,7 +132,7 @@ public class ArmorUtilsTest {
|
||||||
@Test
|
@Test
|
||||||
public void signatureToAsciiArmoredString() {
|
public void signatureToAsciiArmoredString() {
|
||||||
String SIG = "-----BEGIN PGP SIGNATURE-----\n" +
|
String SIG = "-----BEGIN PGP SIGNATURE-----\n" +
|
||||||
"Version: PGPainless\n" +
|
"Comment: 4F66 5C4D C2C4 660B C642 5E41 5736 E693 1ACF 370C\n" +
|
||||||
"\n" +
|
"\n" +
|
||||||
"iHUEARMKAB0WIQRPZlxNwsRmC8ZCXkFXNuaTGs83DAUCYJ/x5gAKCRBXNuaTGs83\n" +
|
"iHUEARMKAB0WIQRPZlxNwsRmC8ZCXkFXNuaTGs83DAUCYJ/x5gAKCRBXNuaTGs83\n" +
|
||||||
"DFRwAP9/4wMvV3WcX59Clo7mkRce6iwW3VBdiN+yMu3tjmHB2wD/RfE28Q1v4+eo\n" +
|
"DFRwAP9/4wMvV3WcX59Clo7mkRce6iwW3VBdiN+yMu3tjmHB2wD/RfE28Q1v4+eo\n" +
|
||||||
|
|
|
@ -7,7 +7,6 @@ package org.pgpainless.sop
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.io.OutputStream
|
import java.io.OutputStream
|
||||||
import org.pgpainless.PGPainless
|
import org.pgpainless.PGPainless
|
||||||
import org.pgpainless.util.ArmorUtils
|
|
||||||
import org.pgpainless.util.ArmoredOutputStreamFactory
|
import org.pgpainless.util.ArmoredOutputStreamFactory
|
||||||
import sop.Ready
|
import sop.Ready
|
||||||
import sop.operation.ExtractCert
|
import sop.operation.ExtractCert
|
||||||
|
@ -26,10 +25,8 @@ class ExtractCertImpl(private val api: PGPainless) : ExtractCert {
|
||||||
if (certs.size == 1) {
|
if (certs.size == 1) {
|
||||||
val cert = certs[0]
|
val cert = certs[0]
|
||||||
// This way we have a nice armor header with fingerprint and user-ids
|
// This way we have a nice armor header with fingerprint and user-ids
|
||||||
val armorOut =
|
val armored = cert.toAsciiArmoredString()
|
||||||
ArmorUtils.toAsciiArmoredStream(cert.pgpKeyRing, outputStream)
|
outputStream.write(armored.toByteArray())
|
||||||
armorOut.write(cert.encoded)
|
|
||||||
armorOut.close()
|
|
||||||
} else {
|
} else {
|
||||||
// for multiple certs, add no info headers to the ASCII armor
|
// for multiple certs, add no info headers to the ASCII armor
|
||||||
val armorOut = ArmoredOutputStreamFactory.get(outputStream)
|
val armorOut = ArmoredOutputStreamFactory.get(outputStream)
|
||||||
|
|
|
@ -18,7 +18,6 @@ import org.pgpainless.key.generation.type.KeyType
|
||||||
import org.pgpainless.key.generation.type.eddsa_legacy.EdDSALegacyCurve
|
import org.pgpainless.key.generation.type.eddsa_legacy.EdDSALegacyCurve
|
||||||
import org.pgpainless.key.generation.type.rsa.RsaLength
|
import org.pgpainless.key.generation.type.rsa.RsaLength
|
||||||
import org.pgpainless.key.generation.type.xdh_legacy.XDHLegacySpec
|
import org.pgpainless.key.generation.type.xdh_legacy.XDHLegacySpec
|
||||||
import org.pgpainless.util.ArmorUtils
|
|
||||||
import org.pgpainless.util.Passphrase
|
import org.pgpainless.util.Passphrase
|
||||||
import sop.Profile
|
import sop.Profile
|
||||||
import sop.Ready
|
import sop.Ready
|
||||||
|
@ -50,9 +49,8 @@ class GenerateKeyImpl(private val api: PGPainless) : GenerateKey {
|
||||||
return object : Ready() {
|
return object : Ready() {
|
||||||
override fun writeTo(outputStream: OutputStream) {
|
override fun writeTo(outputStream: OutputStream) {
|
||||||
if (armor) {
|
if (armor) {
|
||||||
val armorOut = ArmorUtils.toAsciiArmoredStream(key.pgpKeyRing, outputStream)
|
val armored = key.toAsciiArmoredString()
|
||||||
key.pgpKeyRing.encode(armorOut)
|
outputStream.write(armored.toByteArray())
|
||||||
armorOut.close()
|
|
||||||
} else {
|
} else {
|
||||||
key.pgpKeyRing.encode(outputStream)
|
key.pgpKeyRing.encode(outputStream)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue