Improve Key Generation API

This commit is contained in:
Paul Schaub 2024-02-29 14:40:06 +01:00
parent 20002efbf6
commit b4240ac9f7
Signed by: vanitasvitae
GPG Key ID: 62BEE9264BF17311
7 changed files with 219 additions and 154 deletions

View File

@ -0,0 +1,24 @@
// SPDX-FileCopyrightText: 2024 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package openpgp
import org.pgpainless.util.Passphrase
/**
* Extension function to convert a nullable [CharSequence] into an [Array]. Iff [this] is `null`,
* then return an empty array, otherwise return an array only consisting of [this].
*
* @return array
*/
fun CharSequence?.toArray(): Array<CharSequence> = this?.let { arrayOf(it) } ?: emptyArray()
/**
* Return a [Passphrase] from this [CharSequence]. Iff [this] is `null` or blank, then this method
* returns [Passphrase.emptyPassphrase], otherwise it returns [Passphrase.fromPassword].
*
* @return passphrase
*/
fun CharSequence?.toPassphrase(): Passphrase =
this?.let { Passphrase.fromPassword(it) } ?: Passphrase.emptyPassphrase()

View File

@ -15,6 +15,7 @@ import org.pgpainless.encryption_signing.EncryptionBuilder
import org.pgpainless.key.certification.CertifyCertificate import org.pgpainless.key.certification.CertifyCertificate
import org.pgpainless.key.generation.KeyRingBuilder import org.pgpainless.key.generation.KeyRingBuilder
import org.pgpainless.key.generation.KeyRingTemplates import org.pgpainless.key.generation.KeyRingTemplates
import org.pgpainless.key.generation.OpenPgpKeyGenerator
import org.pgpainless.key.info.KeyRingInfo import org.pgpainless.key.info.KeyRingInfo
import org.pgpainless.key.modification.secretkeyring.SecretKeyRingEditor import org.pgpainless.key.modification.secretkeyring.SecretKeyRingEditor
import org.pgpainless.key.parsing.KeyRingReader import org.pgpainless.key.parsing.KeyRingReader
@ -26,19 +27,30 @@ class PGPainless private constructor() {
companion object { companion object {
/** Generate an OpenPGP key. */
@JvmOverloads
@JvmStatic
fun generateOpenPgpKey(policy: Policy = getPolicy()) = OpenPgpKeyGenerator(policy)
/** /**
* Generate a fresh OpenPGP key ring from predefined templates. * Generate a fresh OpenPGP key ring from predefined templates.
* *
* @return templates * @return templates
*/ */
@JvmStatic fun generateKeyRing() = KeyRingTemplates() @Deprecated(
"Deprecated in favor of new API",
ReplaceWith("generateOpenPgpKey().buildV4Key().fromTemplate()"))
@JvmStatic
fun generateKeyRing() = KeyRingTemplates()
/** /**
* Build a custom OpenPGP key ring. * Build a custom OpenPGP key ring.
* *
* @return builder * @return builder
*/ */
@JvmStatic fun buildKeyRing() = KeyRingBuilder() @Deprecated("Deprecated in favor of new API", ReplaceWith("generateOpenPgpKey()"))
@JvmStatic
fun buildKeyRing() = KeyRingBuilder()
/** /**
* Read an existing OpenPGP key ring. * Read an existing OpenPGP key ring.

View File

@ -4,6 +4,8 @@
package org.pgpainless.key.generation package org.pgpainless.key.generation
import openpgp.toArray
import openpgp.toPassphrase
import org.bouncycastle.openpgp.PGPSecretKeyRing import org.bouncycastle.openpgp.PGPSecretKeyRing
import org.pgpainless.algorithm.KeyFlag import org.pgpainless.algorithm.KeyFlag
import org.pgpainless.key.generation.type.KeyType import org.pgpainless.key.generation.type.KeyType
@ -30,15 +32,13 @@ class KeyRingTemplates {
length: RsaLength, length: RsaLength,
passphrase: Passphrase = Passphrase.emptyPassphrase() passphrase: Passphrase = Passphrase.emptyPassphrase()
): PGPSecretKeyRing = ): PGPSecretKeyRing =
OpenPgpKeyGenerator.buildV4Key() OpenPgpKeyGenerator()
.setPrimaryKey(KeyType.RSA(length), listOf(KeyFlag.CERTIFY_OTHER)) { .buildV4Key()
if (userId != null) { .fromTemplate()
addUserId(userId) .composedRsa(
} userId = userId.toArray(),
} length = length,
.addSigningSubkey(KeyType.RSA(length)) protector = SecretKeyRingProtector.unlockAnyKeyWith(passphrase))
.addEncryptionSubkey(KeyType.RSA(length))
.build(passphrase)
/** /**
* Generate an RSA OpenPGP key consisting of an RSA primary key used for certification, a * Generate an RSA OpenPGP key consisting of an RSA primary key used for certification, a
@ -50,14 +50,11 @@ class KeyRingTemplates {
* keys. * keys.
* @return key * @return key
*/ */
fun rsaKeyRing(userId: CharSequence?, length: RsaLength, password: String?): PGPSecretKeyRing = fun rsaKeyRing(
password.let { userId: CharSequence?,
if (it.isNullOrBlank()) { length: RsaLength,
rsaKeyRing(userId, length, Passphrase.emptyPassphrase()) password: CharSequence?
} else { ): PGPSecretKeyRing = rsaKeyRing(userId, length, password.toPassphrase())
rsaKeyRing(userId, length, Passphrase.fromPassword(it))
}
}
/** /**
* Creates a simple RSA KeyPair of length {@code length} with user-id {@code userId}. The * Creates a simple RSA KeyPair of length {@code length} with user-id {@code userId}. The
@ -75,19 +72,13 @@ class KeyRingTemplates {
length: RsaLength, length: RsaLength,
passphrase: Passphrase = Passphrase.emptyPassphrase() passphrase: Passphrase = Passphrase.emptyPassphrase()
): PGPSecretKeyRing = ): PGPSecretKeyRing =
OpenPgpKeyGenerator.buildV4Key() OpenPgpKeyGenerator()
.setPrimaryKey( .buildV4Key()
KeyType.RSA(length), .fromTemplate()
listOf( .singleRsa(
KeyFlag.CERTIFY_OTHER, userId = userId.toArray(),
KeyFlag.SIGN_DATA, length = length,
KeyFlag.ENCRYPT_COMMS, protector = SecretKeyRingProtector.unlockAnyKeyWith(passphrase))
KeyFlag.ENCRYPT_STORAGE)) {
if (userId != null) {
addUserId(userId)
}
}
.build(passphrase)
/** /**
* Creates a simple RSA KeyPair of length {@code length} with user-id {@code userId}. The * Creates a simple RSA KeyPair of length {@code length} with user-id {@code userId}. The
@ -99,14 +90,8 @@ class KeyRingTemplates {
* @param password Password of the key. Can be null or blank for unencrypted keys. * @param password Password of the key. Can be null or blank for unencrypted keys.
* @return {@link PGPSecretKeyRing} containing the KeyPair. * @return {@link PGPSecretKeyRing} containing the KeyPair.
*/ */
fun simpleRsaKeyRing(userId: CharSequence?, length: RsaLength, password: String?) = fun simpleRsaKeyRing(userId: CharSequence?, length: RsaLength, password: CharSequence?) =
password.let { simpleRsaKeyRing(userId, length, password.toPassphrase())
if (it.isNullOrBlank()) {
simpleRsaKeyRing(userId, length, Passphrase.emptyPassphrase())
} else {
simpleRsaKeyRing(userId, length, Passphrase.fromPassword(it))
}
}
/** /**
* Creates a key ring consisting of an ed25519 EdDSA primary key and a X25519 XDH subkey. The * Creates a key ring consisting of an ed25519 EdDSA primary key and a X25519 XDH subkey. The
@ -122,7 +107,8 @@ class KeyRingTemplates {
userId: CharSequence?, userId: CharSequence?,
passphrase: Passphrase = Passphrase.emptyPassphrase() passphrase: Passphrase = Passphrase.emptyPassphrase()
): PGPSecretKeyRing = ): PGPSecretKeyRing =
OpenPgpKeyGenerator.buildV4Key() OpenPgpKeyGenerator()
.buildV4Key()
.setPrimaryKey( .setPrimaryKey(
KeyType.EDDSA(EdDSACurve._Ed25519), KeyType.EDDSA(EdDSACurve._Ed25519),
listOf(KeyFlag.CERTIFY_OTHER, KeyFlag.SIGN_DATA)) { listOf(KeyFlag.CERTIFY_OTHER, KeyFlag.SIGN_DATA)) {
@ -142,14 +128,8 @@ class KeyRingTemplates {
* @param password Password of the private key. Can be null or blank for an unencrypted key. * @param password Password of the private key. Can be null or blank for an unencrypted key.
* @return {@link PGPSecretKeyRing} containing the key pairs. * @return {@link PGPSecretKeyRing} containing the key pairs.
*/ */
fun simpleEcKeyRing(userId: CharSequence?, password: String?): PGPSecretKeyRing = fun simpleEcKeyRing(userId: CharSequence?, password: CharSequence?): PGPSecretKeyRing =
password.let { simpleEcKeyRing(userId, password.toPassphrase())
if (it.isNullOrBlank()) {
simpleEcKeyRing(userId, Passphrase.emptyPassphrase())
} else {
simpleEcKeyRing(userId, Passphrase.fromPassword(it))
}
}
/** /**
* Generate a modern PGP key ring consisting of an ed25519 EdDSA primary key which is used to * Generate a modern PGP key ring consisting of an ed25519 EdDSA primary key which is used to
@ -164,17 +144,12 @@ class KeyRingTemplates {
userId: CharSequence?, userId: CharSequence?,
passphrase: Passphrase = Passphrase.emptyPassphrase() passphrase: Passphrase = Passphrase.emptyPassphrase()
): PGPSecretKeyRing = ): PGPSecretKeyRing =
OpenPgpKeyGenerator.buildV4Key() OpenPgpKeyGenerator()
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519), listOf(KeyFlag.CERTIFY_OTHER)) { .buildV4Key()
if (userId != null) { .fromTemplate()
addUserId(userId) .ed25519Curve25519(
} userId = userId.toArray(),
} protector = SecretKeyRingProtector.unlockAnyKeyWith(passphrase))
.addEncryptionSubkey(KeyType.XDH(XDHSpec._X25519))
.addSigningSubkey(KeyType.EDDSA(EdDSACurve._Ed25519))
.build(
if (passphrase.isEmpty) SecretKeyRingProtector.unprotectedKeys()
else SecretKeyRingProtector.unlockAnyKeyWith(passphrase))
/** /**
* Generate a modern PGP key ring consisting of an ed25519 EdDSA primary key which is used to * Generate a modern PGP key ring consisting of an ed25519 EdDSA primary key which is used to
@ -184,12 +159,6 @@ class KeyRingTemplates {
* @param password passphrase for the private key. Can be null or blank for an unencrypted key. * @param password passphrase for the private key. Can be null or blank for an unencrypted key.
* @return key ring * @return key ring
*/ */
fun modernKeyRing(userId: CharSequence?, password: String?): PGPSecretKeyRing = fun modernKeyRing(userId: CharSequence?, password: CharSequence?): PGPSecretKeyRing =
password.let { modernKeyRing(userId, password.toPassphrase())
if (it.isNullOrBlank()) {
modernKeyRing(userId, Passphrase.emptyPassphrase())
} else {
modernKeyRing(userId, Passphrase.fromPassword(it))
}
}
} }

View File

@ -24,6 +24,7 @@ import org.pgpainless.bouncycastle.extensions.plusCertification
import org.pgpainless.implementation.ImplementationFactory import org.pgpainless.implementation.ImplementationFactory
import org.pgpainless.key.generation.DefinePrimaryKey.PrimaryKeyBuilder import org.pgpainless.key.generation.DefinePrimaryKey.PrimaryKeyBuilder
import org.pgpainless.key.generation.DefineSubkeys.SubkeyBuilder import org.pgpainless.key.generation.DefineSubkeys.SubkeyBuilder
import org.pgpainless.key.generation.OpenPgpKeyTemplates.Companion.v4
import org.pgpainless.key.generation.type.KeyType import org.pgpainless.key.generation.type.KeyType
import org.pgpainless.key.generation.type.eddsa.EdDSACurve import org.pgpainless.key.generation.type.eddsa.EdDSACurve
import org.pgpainless.key.generation.type.rsa.RsaLength import org.pgpainless.key.generation.type.rsa.RsaLength
@ -37,8 +38,16 @@ import org.pgpainless.signature.builder.SubkeyBindingSignatureBuilder
import org.pgpainless.signature.subpackets.SelfSignatureSubpackets import org.pgpainless.signature.subpackets.SelfSignatureSubpackets
import org.pgpainless.util.Passphrase import org.pgpainless.util.Passphrase
/**
* Function block that is applied to the OpenPGP [PrimaryKeyBuilder]. Within this block, you add
* User-IDs, User-Attributes and Direct-Key signatures on the primary key.
*/
typealias PrimaryKeyBlock = (PrimaryKeyBuilder.() -> Unit) typealias PrimaryKeyBlock = (PrimaryKeyBuilder.() -> Unit)
/**
* Function block that is applied to an OpenPGP [SubkeyBuilder]. Here you typically add
* subkey-binding signatures.
*/
typealias SubkeyBlock = (SubkeyBuilder.() -> Unit) typealias SubkeyBlock = (SubkeyBuilder.() -> Unit)
/** /**
@ -54,25 +63,20 @@ typealias SubkeyBlock = (SubkeyBuilder.() -> Unit)
* You can switch from the opinionated API to the unopinionated API by calling `unopinionated()` on * You can switch from the opinionated API to the unopinionated API by calling `unopinionated()` on
* the builder. * the builder.
*/ */
class OpenPgpKeyGenerator internal constructor() { class OpenPgpKeyGenerator(private val policy: Policy = PGPainless.getPolicy()) {
companion object { /**
/** * Build a version 4 OpenPGP secret key.
* Build a version 4 OpenPGP secret key. *
* * @param creationTime creation time for the secret key
* @param policy policy to ensure algorithm compliance and to determine default algorithms * @param preferences suite of algorithm preferences and enabled features
* @param creationTime creation time for the secret key */
* @param preferences suite of algorithm preferences and enabled features @JvmOverloads
*/ fun buildV4Key(
@JvmStatic creationTime: Date = Date(),
@JvmOverloads preferences: AlgorithmSuite = policy.keyGenerationAlgorithmSuite
fun buildV4Key( ): OpinionatedDefinePrimaryKeyV4 {
policy: Policy = PGPainless.getPolicy(), return OpinionatedDefinePrimaryKeyV4(policy, creationTime, preferences)
creationTime: Date = Date(),
preferences: AlgorithmSuite = policy.keyGenerationAlgorithmSuite
): OpinionatedDefinePrimaryKeyV4 {
return OpinionatedDefinePrimaryKeyV4(policy, creationTime, preferences)
}
} }
} }
@ -211,6 +215,14 @@ internal constructor(val policy: Policy, val creationTime: Date, val preferences
// Do nothing // Do nothing
} }
/**
* Return a [OpenPgpKeyTemplates] object which provides factory methods for generating OpenPGP
* keys from templates.
*
* @return templates
*/
abstract fun fromTemplate(): OpenPgpKeyTemplates
/** /**
* Function that can be applied to the primary key. * Function that can be applied to the primary key.
* *
@ -1094,11 +1106,13 @@ class PrimaryKeyBuilderV4 internal constructor(keyPair: PGPKeyPair, builder: Def
this.keyPair this.keyPair
} }
} }
override fun fromTemplate(): OpenPgpKeyTemplates.V4 = v4()
} }
} }
/** Templates for OpenPGP key generation. */ /** Templates for OpenPGP key generation. */
class OpenPgpKeyTemplates private constructor() { open class OpenPgpKeyTemplates private constructor() {
companion object { companion object {
@ -1111,7 +1125,7 @@ class OpenPgpKeyTemplates private constructor() {
} }
/** Templates for version 4 OpenPGP keys. Version 4 keys are compliant to RFC4880. */ /** Templates for version 4 OpenPGP keys. Version 4 keys are compliant to RFC4880. */
class V4 internal constructor() { class V4 : OpenPgpKeyTemplates() {
/** /**
* Generate an OpenPGP key that consists of an Ed25519 primary key used for certification of * Generate an OpenPGP key that consists of an Ed25519 primary key used for certification of
@ -1123,9 +1137,11 @@ class OpenPgpKeyTemplates private constructor() {
*/ */
fun ed25519Curve25519( fun ed25519Curve25519(
vararg userId: CharSequence, vararg userId: CharSequence,
creationTime: Date = Date() creationTime: Date = Date(),
protector: SecretKeyRingProtector = SecretKeyRingProtector.unprotectedKeys()
): PGPSecretKeyRing = ): PGPSecretKeyRing =
OpenPgpKeyGenerator.buildV4Key(creationTime = creationTime) OpenPgpKeyGenerator()
.buildV4Key(creationTime = creationTime)
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519)) { .setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519)) {
// Add UserIDs // Add UserIDs
userId.forEachIndexed { index, uid -> userId.forEachIndexed { index, uid ->
@ -1145,7 +1161,7 @@ class OpenPgpKeyTemplates private constructor() {
.addSigningSubkey(KeyType.EDDSA(EdDSACurve._Ed25519)) .addSigningSubkey(KeyType.EDDSA(EdDSACurve._Ed25519))
// encryption key // encryption key
.addEncryptionSubkey(KeyType.XDH(XDHSpec._X25519)) .addEncryptionSubkey(KeyType.XDH(XDHSpec._X25519))
.build() .build(protector)
/** /**
* Generate an OpenPGP key that consists of an RSA primary key used for certification of * Generate an OpenPGP key that consists of an RSA primary key used for certification of
@ -1159,9 +1175,11 @@ class OpenPgpKeyTemplates private constructor() {
fun composedRsa( fun composedRsa(
vararg userId: CharSequence, vararg userId: CharSequence,
creationTime: Date = Date(), creationTime: Date = Date(),
length: RsaLength = RsaLength._4096 length: RsaLength = RsaLength._4096,
protector: SecretKeyRingProtector = SecretKeyRingProtector.unprotectedKeys()
): PGPSecretKeyRing = ): PGPSecretKeyRing =
OpenPgpKeyGenerator.buildV4Key(creationTime = creationTime) OpenPgpKeyGenerator()
.buildV4Key(creationTime = creationTime)
.setPrimaryKey(KeyType.RSA(length)) { .setPrimaryKey(KeyType.RSA(length)) {
// Add UserIDs // Add UserIDs
userId.forEachIndexed { index, uid -> userId.forEachIndexed { index, uid ->
@ -1181,7 +1199,7 @@ class OpenPgpKeyTemplates private constructor() {
.addSigningSubkey(KeyType.RSA(length)) .addSigningSubkey(KeyType.RSA(length))
// encryption key // encryption key
.addEncryptionSubkey(KeyType.RSA(length)) .addEncryptionSubkey(KeyType.RSA(length))
.build() .build(protector)
/** /**
* Generate an OpenPGP key consisting of a single RSA key that is used for certification of * Generate an OpenPGP key consisting of a single RSA key that is used for certification of
@ -1194,9 +1212,11 @@ class OpenPgpKeyTemplates private constructor() {
fun singleRsa( fun singleRsa(
vararg userId: CharSequence, vararg userId: CharSequence,
creationTime: Date = Date(), creationTime: Date = Date(),
length: RsaLength = RsaLength._4096 length: RsaLength = RsaLength._4096,
protector: SecretKeyRingProtector = SecretKeyRingProtector.unprotectedKeys()
): PGPSecretKeyRing = ): PGPSecretKeyRing =
OpenPgpKeyGenerator.buildV4Key(creationTime = creationTime) OpenPgpKeyGenerator()
.buildV4Key(creationTime = creationTime)
.setPrimaryKey(KeyType.RSA(length)) { .setPrimaryKey(KeyType.RSA(length)) {
userId.forEach { addUserId(it) } userId.forEach { addUserId(it) }
addDirectKeySignature( addDirectKeySignature(
@ -1208,6 +1228,6 @@ class OpenPgpKeyTemplates private constructor() {
KeyFlag.ENCRYPT_STORAGE) KeyFlag.ENCRYPT_STORAGE)
}) })
} }
.build() .build(protector)
} }
} }

View File

@ -11,7 +11,6 @@ import org.pgpainless.PGPainless
import org.pgpainless.algorithm.HashAlgorithm import org.pgpainless.algorithm.HashAlgorithm
import org.pgpainless.algorithm.KeyFlag import org.pgpainless.algorithm.KeyFlag
import org.pgpainless.bouncycastle.extensions.directKeySignatures import org.pgpainless.bouncycastle.extensions.directKeySignatures
import org.pgpainless.key.generation.OpenPgpKeyGenerator
import org.pgpainless.key.generation.type.KeyType import org.pgpainless.key.generation.type.KeyType
import org.pgpainless.key.generation.type.eddsa.EdDSACurve import org.pgpainless.key.generation.type.eddsa.EdDSACurve
import org.pgpainless.key.generation.type.xdh.XDHSpec import org.pgpainless.key.generation.type.xdh.XDHSpec
@ -21,19 +20,26 @@ class KeyWithInacceptableSelfSignatureTest {
@Test @Test
fun `key with inacceptable self-signature is not usable`() { fun `key with inacceptable self-signature is not usable`() {
val genPolicy = Policy().apply { val genPolicy =
certificationSignatureHashAlgorithmPolicy = Policy.HashAlgorithmPolicy( Policy().apply {
HashAlgorithm.SHA1, listOf(HashAlgorithm.SHA1)) certificationSignatureHashAlgorithmPolicy =
} Policy.HashAlgorithmPolicy(HashAlgorithm.SHA1, listOf(HashAlgorithm.SHA1))
}
val key = OpenPgpKeyGenerator.buildV4Key(genPolicy) val key =
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519), listOf(KeyFlag.CERTIFY_OTHER, KeyFlag.SIGN_DATA)) PGPainless.generateOpenPgpKey(genPolicy)
.addEncryptionSubkey(KeyType.XDH(XDHSpec._X25519)) .buildV4Key()
.build() .setPrimaryKey(
KeyType.EDDSA(EdDSACurve._Ed25519),
listOf(KeyFlag.CERTIFY_OTHER, KeyFlag.SIGN_DATA))
.addEncryptionSubkey(KeyType.XDH(XDHSpec._X25519))
.build()
assertEquals(HashAlgorithm.SHA1, assertEquals(
key.publicKey.directKeySignatures.single().hashAlgorithm HashAlgorithm.SHA1,
.let { HashAlgorithm.requireFromId(it) }) key.publicKey.directKeySignatures.single().hashAlgorithm.let {
HashAlgorithm.requireFromId(it)
})
val info = PGPainless.inspectKeyRing(key) val info = PGPainless.inspectKeyRing(key)
assertFalse(info.isUsableForSigning) assertFalse(info.isUsableForSigning)

View File

@ -24,7 +24,8 @@ class MalformedKeyGenerationTest {
fun malformedPrimaryUserIdSubpacket() { fun malformedPrimaryUserIdSubpacket() {
val userId = "Alice <alice@pgpainless.org>" val userId = "Alice <alice@pgpainless.org>"
val key = val key =
OpenPgpKeyGenerator.buildV4Key(Policy()) PGPainless.generateOpenPgpKey(Policy())
.buildV4Key()
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519)) { .setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519)) {
addUserId( addUserId(
userId, userId,
@ -43,7 +44,8 @@ class MalformedKeyGenerationTest {
@Test @Test
fun malformedExportableSubpacket() { fun malformedExportableSubpacket() {
val key = val key =
OpenPgpKeyGenerator.buildV4Key(Policy()) PGPainless.generateOpenPgpKey(Policy())
.buildV4Key()
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519)) { .setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519)) {
addUserId( addUserId(
"Alice <alice@pgpainless.org>", "Alice <alice@pgpainless.org>",
@ -62,7 +64,8 @@ class MalformedKeyGenerationTest {
@Test @Test
fun malformedRevocableSubpacket() { fun malformedRevocableSubpacket() {
val key = val key =
OpenPgpKeyGenerator.buildV4Key(Policy()) PGPainless.generateOpenPgpKey(Policy())
.buildV4Key()
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519)) { .setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519)) {
addUserId( addUserId(
"Alice <alice@pgpainless.org>", "Alice <alice@pgpainless.org>",
@ -82,7 +85,8 @@ class MalformedKeyGenerationTest {
fun primaryUserIdOnDirectKeySig() { fun primaryUserIdOnDirectKeySig() {
val policy = Policy() val policy = Policy()
val key = val key =
OpenPgpKeyGenerator.buildV4Key(policy) PGPainless.generateOpenPgpKey(policy)
.buildV4Key()
.setPrimaryKey( .setPrimaryKey(
KeyType.EDDSA(EdDSACurve._Ed25519), KeyType.EDDSA(EdDSACurve._Ed25519),
listOf(KeyFlag.CERTIFY_OTHER, KeyFlag.SIGN_DATA)) { listOf(KeyFlag.CERTIFY_OTHER, KeyFlag.SIGN_DATA)) {

View File

@ -38,7 +38,8 @@ class OpenPgpKeyGeneratorTest {
@Test @Test
fun `minimal call with opinionated builder adds a default DK sig but no user info`() { fun `minimal call with opinionated builder adds a default DK sig but no user info`() {
val key = val key =
OpenPgpKeyGenerator.buildV4Key() PGPainless.generateOpenPgpKey()
.buildV4Key()
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519)) .setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519))
.build() .build()
@ -55,7 +56,8 @@ class OpenPgpKeyGeneratorTest {
@Test @Test
fun `minimal call with unopinionated builder does not add a default DK sig`() { fun `minimal call with unopinionated builder does not add a default DK sig`() {
val key = val key =
OpenPgpKeyGenerator.buildV4Key() PGPainless.generateOpenPgpKey()
.buildV4Key()
.unopinionated() .unopinionated()
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519)) .setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519))
.build() .build()
@ -68,7 +70,8 @@ class OpenPgpKeyGeneratorTest {
@Test @Test
fun `adding a direct-key signature with the opinionated builder omits the default DK sig`() { fun `adding a direct-key signature with the opinionated builder omits the default DK sig`() {
val key = val key =
OpenPgpKeyGenerator.buildV4Key() PGPainless.generateOpenPgpKey()
.buildV4Key()
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519)) { .setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519)) {
addDirectKeySignature() // "overwrites" the default dk sig addDirectKeySignature() // "overwrites" the default dk sig
} }
@ -82,7 +85,8 @@ class OpenPgpKeyGeneratorTest {
@Test @Test
fun `adding two user-ids will mark the first one as primary`() { fun `adding two user-ids will mark the first one as primary`() {
val key = val key =
OpenPgpKeyGenerator.buildV4Key() PGPainless.generateOpenPgpKey()
.buildV4Key()
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519)) { .setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519)) {
addUserId("Primary <primary@example.com>") addUserId("Primary <primary@example.com>")
addUserId("Non Primary <non-primary@example.com>") addUserId("Non Primary <non-primary@example.com>")
@ -96,7 +100,8 @@ class OpenPgpKeyGeneratorTest {
@Test @Test
fun `adding two user-ids but mark the first as non-primary will mark the second one as primary`() { fun `adding two user-ids but mark the first as non-primary will mark the second one as primary`() {
val key = val key =
OpenPgpKeyGenerator.buildV4Key() PGPainless.generateOpenPgpKey()
.buildV4Key()
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519)) { .setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519)) {
addUserId( addUserId(
"Non Primary <non-primary@example.com>", "Non Primary <non-primary@example.com>",
@ -126,7 +131,8 @@ class OpenPgpKeyGeneratorTest {
.generate() .generate()
val key = val key =
OpenPgpKeyGenerator.buildV4Key(policy) PGPainless.generateOpenPgpKey(policy)
.buildV4Key()
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519)) { .setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519)) {
addUserAttribute(attr1) // primary, since it is the first addUserAttribute(attr1) // primary, since it is the first
addUserAttribute(attr2) // non-primary addUserAttribute(attr2) // non-primary
@ -160,7 +166,8 @@ class OpenPgpKeyGeneratorTest {
.generate() .generate()
val key = val key =
OpenPgpKeyGenerator.buildV4Key(policy) PGPainless.generateOpenPgpKey(policy)
.buildV4Key()
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519)) { .setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519)) {
addUserId(userId) addUserId(userId)
addUserAttribute(userAttribute) addUserAttribute(userAttribute)
@ -186,7 +193,8 @@ class OpenPgpKeyGeneratorTest {
@Test @Test
fun `adding signing key will add embedded back-signature`() { fun `adding signing key will add embedded back-signature`() {
val key = val key =
OpenPgpKeyGenerator.buildV4Key() PGPainless.generateOpenPgpKey()
.buildV4Key()
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519)) .setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519))
.addSubkey(KeyType.EDDSA(EdDSACurve._Ed25519), listOf(KeyFlag.SIGN_DATA)) .addSubkey(KeyType.EDDSA(EdDSACurve._Ed25519), listOf(KeyFlag.SIGN_DATA))
.build() .build()
@ -205,7 +213,8 @@ class OpenPgpKeyGeneratorTest {
@Test @Test
fun testUnopinionatedV4() { fun testUnopinionatedV4() {
// Unopinionated // Unopinionated
OpenPgpKeyGenerator.buildV4Key() PGPainless.generateOpenPgpKey()
.buildV4Key()
.unopinionated() .unopinionated()
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519)) { .setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519)) {
addDirectKeySignature() addDirectKeySignature()
@ -221,7 +230,8 @@ class OpenPgpKeyGeneratorTest {
fun testOpinionatedV4() { fun testOpinionatedV4() {
// Opinionated // Opinionated
val time = DateUtil.parseUTCDate("2024-01-01 00:00:00 UTC") val time = DateUtil.parseUTCDate("2024-01-01 00:00:00 UTC")
OpenPgpKeyGenerator.buildV4Key(creationTime = time) PGPainless.generateOpenPgpKey()
.buildV4Key(creationTime = time)
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519), listOf(KeyFlag.CERTIFY_OTHER)) { .setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519), listOf(KeyFlag.CERTIFY_OTHER)) {
addUserId("Alice <alice@pgpainless.org>") addUserId("Alice <alice@pgpainless.org>")
} }
@ -254,7 +264,8 @@ class OpenPgpKeyGeneratorTest {
@Test @Test
fun test() { fun test() {
OpenPgpKeyGenerator.buildV4Key() PGPainless.generateOpenPgpKey()
.buildV4Key()
.setPrimaryKey(KeyType.RSA(RsaLength._3072), keyFlags = listOf(KeyFlag.CERTIFY_OTHER)) .setPrimaryKey(KeyType.RSA(RsaLength._3072), keyFlags = listOf(KeyFlag.CERTIFY_OTHER))
.build() .build()
.toAsciiArmor() .toAsciiArmor()
@ -268,7 +279,8 @@ class OpenPgpKeyGeneratorTest {
Policy.PublicKeyAlgorithmPolicy(buildMap { put(PublicKeyAlgorithm.RSA_GENERAL, 3072) }) Policy.PublicKeyAlgorithmPolicy(buildMap { put(PublicKeyAlgorithm.RSA_GENERAL, 3072) })
assertThrows<IllegalArgumentException> { assertThrows<IllegalArgumentException> {
OpenPgpKeyGenerator.buildV4Key(policy) PGPainless.generateOpenPgpKey(policy)
.buildV4Key()
// opinionated builder verifies PK parameters // opinionated builder verifies PK parameters
.setPrimaryKey(KeyType.RSA(RsaLength._2048)) // too weak .setPrimaryKey(KeyType.RSA(RsaLength._2048)) // too weak
} }
@ -280,7 +292,8 @@ class OpenPgpKeyGeneratorTest {
policy.publicKeyAlgorithmPolicy = policy.publicKeyAlgorithmPolicy =
Policy.PublicKeyAlgorithmPolicy(buildMap { put(PublicKeyAlgorithm.RSA_GENERAL, 3072) }) Policy.PublicKeyAlgorithmPolicy(buildMap { put(PublicKeyAlgorithm.RSA_GENERAL, 3072) })
OpenPgpKeyGenerator.buildV4Key(policy) PGPainless.generateOpenPgpKey(policy)
.buildV4Key()
.unopinionated() // unopinionated builder allows for non-compliant configurations .unopinionated() // unopinionated builder allows for non-compliant configurations
.setPrimaryKey(KeyType.RSA(RsaLength._2048)) .setPrimaryKey(KeyType.RSA(RsaLength._2048))
} }
@ -288,7 +301,8 @@ class OpenPgpKeyGeneratorTest {
@Test @Test
fun `skip default DirectKey signature will not add one`() { fun `skip default DirectKey signature will not add one`() {
val key = val key =
OpenPgpKeyGenerator.buildV4Key() PGPainless.generateOpenPgpKey()
.buildV4Key()
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519)) { skipDefaultSignature() } .setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519)) { skipDefaultSignature() }
.build() .build()
@ -304,7 +318,7 @@ class OpenPgpKeyGeneratorTest {
fun `opinionated add UserID with weak hash algorithm fails`() { fun `opinionated add UserID with weak hash algorithm fails`() {
val policy = Policy() val policy = Policy()
assertThrows<IllegalArgumentException> { assertThrows<IllegalArgumentException> {
OpenPgpKeyGenerator.buildV4Key(policy).setPrimaryKey( PGPainless.generateOpenPgpKey(policy).buildV4Key().setPrimaryKey(
KeyType.EDDSA(EdDSACurve._Ed25519)) { KeyType.EDDSA(EdDSACurve._Ed25519)) {
addUserId("Alice <alice@example.org>", hashAlgorithm = HashAlgorithm.SHA1) addUserId("Alice <alice@example.org>", hashAlgorithm = HashAlgorithm.SHA1)
} }
@ -314,7 +328,7 @@ class OpenPgpKeyGeneratorTest {
@Test @Test
fun `unopinionated add UserID with weak hash algorithm is okay`() { fun `unopinionated add UserID with weak hash algorithm is okay`() {
val policy = Policy() val policy = Policy()
OpenPgpKeyGenerator.buildV4Key(policy).unopinionated().setPrimaryKey( PGPainless.generateOpenPgpKey(policy).buildV4Key().unopinionated().setPrimaryKey(
KeyType.EDDSA(EdDSACurve._Ed25519)) { KeyType.EDDSA(EdDSACurve._Ed25519)) {
addUserId("Alice <alice@example.org>", hashAlgorithm = HashAlgorithm.SHA1) addUserId("Alice <alice@example.org>", hashAlgorithm = HashAlgorithm.SHA1)
} }
@ -324,7 +338,7 @@ class OpenPgpKeyGeneratorTest {
fun `opinionated add UserAttribute with weak hash algorithm fails`() { fun `opinionated add UserAttribute with weak hash algorithm fails`() {
val policy = Policy() val policy = Policy()
assertThrows<IllegalArgumentException> { assertThrows<IllegalArgumentException> {
OpenPgpKeyGenerator.buildV4Key(policy).setPrimaryKey( PGPainless.generateOpenPgpKey(policy).buildV4Key().setPrimaryKey(
KeyType.EDDSA(EdDSACurve._Ed25519)) { KeyType.EDDSA(EdDSACurve._Ed25519)) {
addUserAttribute( addUserAttribute(
PGPUserAttributeSubpacketVectorGenerator().generate(), PGPUserAttributeSubpacketVectorGenerator().generate(),
@ -336,7 +350,7 @@ class OpenPgpKeyGeneratorTest {
@Test @Test
fun `unopinionated add UserAttribute with weak hash algorithm is okay`() { fun `unopinionated add UserAttribute with weak hash algorithm is okay`() {
val policy = Policy() val policy = Policy()
OpenPgpKeyGenerator.buildV4Key(policy).unopinionated().setPrimaryKey( PGPainless.generateOpenPgpKey(policy).buildV4Key().unopinionated().setPrimaryKey(
KeyType.EDDSA(EdDSACurve._Ed25519)) { KeyType.EDDSA(EdDSACurve._Ed25519)) {
addUserAttribute( addUserAttribute(
PGPUserAttributeSubpacketVectorGenerator().generate(), PGPUserAttributeSubpacketVectorGenerator().generate(),
@ -348,7 +362,7 @@ class OpenPgpKeyGeneratorTest {
fun `opinionated add DK sig with weak hash algorithm fails`() { fun `opinionated add DK sig with weak hash algorithm fails`() {
val policy = Policy() val policy = Policy()
assertThrows<IllegalArgumentException> { assertThrows<IllegalArgumentException> {
OpenPgpKeyGenerator.buildV4Key(policy).setPrimaryKey( PGPainless.generateOpenPgpKey(policy).buildV4Key().setPrimaryKey(
KeyType.EDDSA(EdDSACurve._Ed25519)) { KeyType.EDDSA(EdDSACurve._Ed25519)) {
addDirectKeySignature(hashAlgorithm = HashAlgorithm.SHA1) addDirectKeySignature(hashAlgorithm = HashAlgorithm.SHA1)
} }
@ -358,7 +372,7 @@ class OpenPgpKeyGeneratorTest {
@Test @Test
fun `unopinionated add DK sig with weak hash algorithm is okay`() { fun `unopinionated add DK sig with weak hash algorithm is okay`() {
val policy = Policy() val policy = Policy()
OpenPgpKeyGenerator.buildV4Key(policy).unopinionated().setPrimaryKey( PGPainless.generateOpenPgpKey(policy).buildV4Key().unopinionated().setPrimaryKey(
KeyType.EDDSA(EdDSACurve._Ed25519)) { KeyType.EDDSA(EdDSACurve._Ed25519)) {
addDirectKeySignature(hashAlgorithm = HashAlgorithm.SHA1) addDirectKeySignature(hashAlgorithm = HashAlgorithm.SHA1)
} }
@ -371,7 +385,7 @@ class OpenPgpKeyGeneratorTest {
val t1 = DateUtil.parseUTCDate("2024-02-01 00:00:00 UTC") val t1 = DateUtil.parseUTCDate("2024-02-01 00:00:00 UTC")
assertThrows<IllegalArgumentException> { assertThrows<IllegalArgumentException> {
OpenPgpKeyGenerator.buildV4Key(policy, t1).setPrimaryKey( PGPainless.generateOpenPgpKey(policy).buildV4Key(t1).setPrimaryKey(
KeyType.EDDSA(EdDSACurve._Ed25519)) { KeyType.EDDSA(EdDSACurve._Ed25519)) {
addUserId("Alice <alice@example.org>", bindingTime = t0) addUserId("Alice <alice@example.org>", bindingTime = t0)
} }
@ -384,7 +398,7 @@ class OpenPgpKeyGeneratorTest {
val t0 = DateUtil.parseUTCDate("2024-01-01 00:00:00 UTC") val t0 = DateUtil.parseUTCDate("2024-01-01 00:00:00 UTC")
val t1 = DateUtil.parseUTCDate("2024-02-01 00:00:00 UTC") val t1 = DateUtil.parseUTCDate("2024-02-01 00:00:00 UTC")
OpenPgpKeyGenerator.buildV4Key(policy, t1).unopinionated().setPrimaryKey( PGPainless.generateOpenPgpKey(policy).buildV4Key(t1).unopinionated().setPrimaryKey(
KeyType.EDDSA(EdDSACurve._Ed25519)) { KeyType.EDDSA(EdDSACurve._Ed25519)) {
addUserId("Alice <alice@example.org>", bindingTime = t0) addUserId("Alice <alice@example.org>", bindingTime = t0)
} }
@ -397,7 +411,7 @@ class OpenPgpKeyGeneratorTest {
val t1 = DateUtil.parseUTCDate("2024-02-01 00:00:00 UTC") val t1 = DateUtil.parseUTCDate("2024-02-01 00:00:00 UTC")
assertThrows<IllegalArgumentException> { assertThrows<IllegalArgumentException> {
OpenPgpKeyGenerator.buildV4Key(policy, t1).setPrimaryKey( PGPainless.generateOpenPgpKey(policy).buildV4Key(t1).setPrimaryKey(
KeyType.EDDSA(EdDSACurve._Ed25519)) { KeyType.EDDSA(EdDSACurve._Ed25519)) {
addUserAttribute( addUserAttribute(
PGPUserAttributeSubpacketVectorGenerator().generate(), bindingTime = t0) PGPUserAttributeSubpacketVectorGenerator().generate(), bindingTime = t0)
@ -411,7 +425,7 @@ class OpenPgpKeyGeneratorTest {
val t0 = DateUtil.parseUTCDate("2024-01-01 00:00:00 UTC") val t0 = DateUtil.parseUTCDate("2024-01-01 00:00:00 UTC")
val t1 = DateUtil.parseUTCDate("2024-02-01 00:00:00 UTC") val t1 = DateUtil.parseUTCDate("2024-02-01 00:00:00 UTC")
OpenPgpKeyGenerator.buildV4Key(policy, t1).unopinionated().setPrimaryKey( PGPainless.generateOpenPgpKey(policy).buildV4Key(t1).unopinionated().setPrimaryKey(
KeyType.EDDSA(EdDSACurve._Ed25519)) { KeyType.EDDSA(EdDSACurve._Ed25519)) {
addUserAttribute( addUserAttribute(
PGPUserAttributeSubpacketVectorGenerator().generate(), bindingTime = t0) PGPUserAttributeSubpacketVectorGenerator().generate(), bindingTime = t0)
@ -425,7 +439,7 @@ class OpenPgpKeyGeneratorTest {
val t1 = DateUtil.parseUTCDate("2024-02-01 00:00:00 UTC") val t1 = DateUtil.parseUTCDate("2024-02-01 00:00:00 UTC")
assertThrows<IllegalArgumentException> { assertThrows<IllegalArgumentException> {
OpenPgpKeyGenerator.buildV4Key(policy, t1).setPrimaryKey( PGPainless.generateOpenPgpKey(policy).buildV4Key(t1).setPrimaryKey(
KeyType.EDDSA(EdDSACurve._Ed25519)) { KeyType.EDDSA(EdDSACurve._Ed25519)) {
addDirectKeySignature(bindingTime = t0) addDirectKeySignature(bindingTime = t0)
} }
@ -438,7 +452,7 @@ class OpenPgpKeyGeneratorTest {
val t0 = DateUtil.parseUTCDate("2024-01-01 00:00:00 UTC") val t0 = DateUtil.parseUTCDate("2024-01-01 00:00:00 UTC")
val t1 = DateUtil.parseUTCDate("2024-02-01 00:00:00 UTC") val t1 = DateUtil.parseUTCDate("2024-02-01 00:00:00 UTC")
OpenPgpKeyGenerator.buildV4Key(policy, t1).unopinionated().setPrimaryKey( PGPainless.generateOpenPgpKey(policy).buildV4Key(t1).unopinionated().setPrimaryKey(
KeyType.EDDSA(EdDSACurve._Ed25519)) { KeyType.EDDSA(EdDSACurve._Ed25519)) {
addDirectKeySignature(bindingTime = t0) addDirectKeySignature(bindingTime = t0)
} }
@ -451,7 +465,8 @@ class OpenPgpKeyGeneratorTest {
val t1 = DateUtil.parseUTCDate("2024-02-01 00:00:00 UTC") val t1 = DateUtil.parseUTCDate("2024-02-01 00:00:00 UTC")
assertThrows<IllegalArgumentException> { assertThrows<IllegalArgumentException> {
OpenPgpKeyGenerator.buildV4Key(policy, t1) PGPainless.generateOpenPgpKey(policy)
.buildV4Key(t1)
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519)) .setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519))
.addSubkey(KeyType.XDH(XDHSpec._X25519), null, t0) .addSubkey(KeyType.XDH(XDHSpec._X25519), null, t0)
} }
@ -463,7 +478,8 @@ class OpenPgpKeyGeneratorTest {
val t0 = DateUtil.parseUTCDate("2024-01-01 00:00:00 UTC") val t0 = DateUtil.parseUTCDate("2024-01-01 00:00:00 UTC")
val t1 = DateUtil.parseUTCDate("2024-02-01 00:00:00 UTC") val t1 = DateUtil.parseUTCDate("2024-02-01 00:00:00 UTC")
OpenPgpKeyGenerator.buildV4Key(policy, t1) PGPainless.generateOpenPgpKey(policy)
.buildV4Key(t1)
.unopinionated() .unopinionated()
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519)) .setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519))
.addSubkey(KeyType.XDH(XDHSpec._X25519), null, t0) .addSubkey(KeyType.XDH(XDHSpec._X25519), null, t0)
@ -476,7 +492,8 @@ class OpenPgpKeyGeneratorTest {
val t1 = DateUtil.parseUTCDate("2024-02-01 00:00:00 UTC") val t1 = DateUtil.parseUTCDate("2024-02-01 00:00:00 UTC")
assertThrows<IllegalArgumentException> { assertThrows<IllegalArgumentException> {
OpenPgpKeyGenerator.buildV4Key(policy, t1) PGPainless.generateOpenPgpKey(policy)
.buildV4Key(t1)
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519)) .setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519))
.addSubkey(KeyType.XDH(XDHSpec._X25519)) { addBindingSignature(bindingTime = t0) } .addSubkey(KeyType.XDH(XDHSpec._X25519)) { addBindingSignature(bindingTime = t0) }
} }
@ -488,7 +505,8 @@ class OpenPgpKeyGeneratorTest {
val t0 = DateUtil.parseUTCDate("2024-01-01 00:00:00 UTC") val t0 = DateUtil.parseUTCDate("2024-01-01 00:00:00 UTC")
val t1 = DateUtil.parseUTCDate("2024-02-01 00:00:00 UTC") val t1 = DateUtil.parseUTCDate("2024-02-01 00:00:00 UTC")
OpenPgpKeyGenerator.buildV4Key(policy, t1) PGPainless.generateOpenPgpKey(policy)
.buildV4Key(t1)
.unopinionated() .unopinionated()
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519)) .setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519))
.addSubkey(KeyType.XDH(XDHSpec._X25519)) { addBindingSignature(bindingTime = t0) } .addSubkey(KeyType.XDH(XDHSpec._X25519)) { addBindingSignature(bindingTime = t0) }
@ -499,7 +517,8 @@ class OpenPgpKeyGeneratorTest {
val policy = Policy() val policy = Policy()
assertThrows<IllegalArgumentException> { assertThrows<IllegalArgumentException> {
OpenPgpKeyGenerator.buildV4Key(policy) PGPainless.generateOpenPgpKey(policy)
.buildV4Key()
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519)) .setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519))
.addSubkey(KeyType.XDH(XDHSpec._X25519)) { .addSubkey(KeyType.XDH(XDHSpec._X25519)) {
addBindingSignature(hashAlgorithm = HashAlgorithm.SHA1) addBindingSignature(hashAlgorithm = HashAlgorithm.SHA1)
@ -511,7 +530,8 @@ class OpenPgpKeyGeneratorTest {
fun `unopinionated add subkey with weak binding signature hash algorithm is okay`() { fun `unopinionated add subkey with weak binding signature hash algorithm is okay`() {
val policy = Policy() val policy = Policy()
OpenPgpKeyGenerator.buildV4Key(policy) PGPainless.generateOpenPgpKey(policy)
.buildV4Key()
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519)) .setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519))
.unopinionated() .unopinionated()
.addSubkey(KeyType.XDH(XDHSpec._X25519)) { .addSubkey(KeyType.XDH(XDHSpec._X25519)) {
@ -524,7 +544,9 @@ class OpenPgpKeyGeneratorTest {
val policy = Policy() val policy = Policy()
assertThrows<IllegalArgumentException> { assertThrows<IllegalArgumentException> {
OpenPgpKeyGenerator.buildV4Key(policy).setPrimaryKey(KeyType.XDH(XDHSpec._X25519)) PGPainless.generateOpenPgpKey(policy)
.buildV4Key()
.setPrimaryKey(KeyType.XDH(XDHSpec._X25519))
} }
} }
@ -533,7 +555,8 @@ class OpenPgpKeyGeneratorTest {
val policy = Policy() val policy = Policy()
assertThrows<IllegalArgumentException> { assertThrows<IllegalArgumentException> {
OpenPgpKeyGenerator.buildV4Key(policy) PGPainless.generateOpenPgpKey(policy)
.buildV4Key()
.setPrimaryKey( .setPrimaryKey(
KeyType.EDDSA(EdDSACurve._Ed25519), KeyType.EDDSA(EdDSACurve._Ed25519),
listOf(KeyFlag.CERTIFY_OTHER, KeyFlag.ENCRYPT_STORAGE)) listOf(KeyFlag.CERTIFY_OTHER, KeyFlag.ENCRYPT_STORAGE))
@ -544,7 +567,8 @@ class OpenPgpKeyGeneratorTest {
fun `unopinionated set primary key to sign-only algorithm but with encryption flag is okay`() { fun `unopinionated set primary key to sign-only algorithm but with encryption flag is okay`() {
val policy = Policy() val policy = Policy()
OpenPgpKeyGenerator.buildV4Key(policy) PGPainless.generateOpenPgpKey(policy)
.buildV4Key()
.unopinionated() .unopinionated()
.setPrimaryKey( .setPrimaryKey(
KeyType.EDDSA(EdDSACurve._Ed25519), KeyType.EDDSA(EdDSACurve._Ed25519),
@ -556,7 +580,8 @@ class OpenPgpKeyGeneratorTest {
val policy = Policy() val policy = Policy()
val key = val key =
OpenPgpKeyGenerator.buildV4Key(policy) PGPainless.generateOpenPgpKey(policy)
.buildV4Key()
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519), keyFlags = null) .setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519), keyFlags = null)
.build() .build()
@ -568,7 +593,8 @@ class OpenPgpKeyGeneratorTest {
val policy = Policy() val policy = Policy()
assertThrows<IllegalArgumentException> { assertThrows<IllegalArgumentException> {
OpenPgpKeyGenerator.buildV4Key(policy) PGPainless.generateOpenPgpKey(policy)
.buildV4Key()
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519)) .setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519))
.addSubkey( .addSubkey(
KeyType.XDH(XDHSpec._X25519), listOf(KeyFlag.ENCRYPT_COMMS, KeyFlag.SIGN_DATA)) KeyType.XDH(XDHSpec._X25519), listOf(KeyFlag.ENCRYPT_COMMS, KeyFlag.SIGN_DATA))
@ -580,7 +606,8 @@ class OpenPgpKeyGeneratorTest {
val policy = Policy() val policy = Policy()
assertThrows<IllegalArgumentException> { assertThrows<IllegalArgumentException> {
OpenPgpKeyGenerator.buildV4Key(policy) PGPainless.generateOpenPgpKey(policy)
.buildV4Key()
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519)) .setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519))
.addSubkey( .addSubkey(
KeyType.EDDSA(EdDSACurve._Ed25519), KeyType.EDDSA(EdDSACurve._Ed25519),
@ -592,7 +619,8 @@ class OpenPgpKeyGeneratorTest {
fun `unopinionated add sign-only sukey but with additional encryption flag is okay`() { fun `unopinionated add sign-only sukey but with additional encryption flag is okay`() {
val policy = Policy() val policy = Policy()
OpenPgpKeyGenerator.buildV4Key(policy) PGPainless.generateOpenPgpKey(policy)
.buildV4Key()
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519)) .setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519))
.unopinionated() .unopinionated()
.addSubkey( .addSubkey(
@ -609,7 +637,8 @@ class OpenPgpKeyGeneratorTest {
"ffd8ffe000104a46494600010101004800480000ffdb004300030202020202030202020303030304060404040404080606050609080a0a090809090a0c0f0c0a0b0e0b09090d110d0e0f101011100a0c12131210130f101010ffc9000b080001000101011100ffcc000600101005ffda0008010100003f00d2cf20ffd9") "ffd8ffe000104a46494600010101004800480000ffdb004300030202020202030202020303030304060404040404080606050609080a0a090809090a0c0f0c0a0b0e0b09090d110d0e0f101011100a0c12131210130f101010ffc9000b080001000101011100ffcc000600101005ffda0008010100003f00d2cf20ffd9")
val key = val key =
OpenPgpKeyGenerator.buildV4Key() PGPainless.generateOpenPgpKey()
.buildV4Key()
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519)) { .setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519)) {
addImageAttribute(jpegBytes.inputStream()) addImageAttribute(jpegBytes.inputStream())
} }
@ -622,7 +651,8 @@ class OpenPgpKeyGeneratorTest {
fun `generate key with expiration time`() { fun `generate key with expiration time`() {
val policy = Policy() val policy = Policy()
OpenPgpKeyGenerator.buildV4Key(policy) PGPainless.generateOpenPgpKey(policy)
.buildV4Key()
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519)) { .setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519)) {
addDirectKeySignature( addDirectKeySignature(
SelfSignatureSubpackets.applyHashed { SelfSignatureSubpackets.applyHashed {