diff --git a/pgpainless-core/src/main/kotlin/org/pgpainless/key/generation/GenerateOpenPgpKey.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/key/generation/GenerateOpenPgpKey.kt deleted file mode 100644 index b2b16898..00000000 --- a/pgpainless-core/src/main/kotlin/org/pgpainless/key/generation/GenerateOpenPgpKey.kt +++ /dev/null @@ -1,339 +0,0 @@ -// SPDX-FileCopyrightText: 2024 Paul Schaub -// -// SPDX-License-Identifier: Apache-2.0 - -package org.pgpainless.key.generation - -import java.io.IOException -import java.io.InputStream -import java.util.* -import org.bouncycastle.bcpg.attr.ImageAttribute -import org.bouncycastle.openpgp.PGPSecretKey -import org.bouncycastle.openpgp.PGPSecretKeyRing -import org.bouncycastle.openpgp.PGPUserAttributeSubpacketVector -import org.bouncycastle.openpgp.PGPUserAttributeSubpacketVectorGenerator -import org.bouncycastle.openpgp.operator.PBESecretKeyEncryptor -import org.bouncycastle.util.io.Streams -import org.pgpainless.algorithm.AlgorithmSuite -import org.pgpainless.algorithm.KeyFlag -import org.pgpainless.implementation.ImplementationFactory -import org.pgpainless.key.generation.type.KeyType -import org.pgpainless.key.protection.SecretKeyRingProtector -import org.pgpainless.policy.Policy -import org.pgpainless.signature.subpackets.SelfSignatureSubpackets - -/** - * OpenPGP key builder. This implementation supersedes the old [KeyRingBuilder]. - * - * @param policy algorithm policy, which is consulted to determine suitable algorithms - * @param referenceTime reference time for key generation - * @param preferences set of preferred algorithms and enabled features - */ -open class GenerateOpenPgpKey( - private val policy: Policy, - private val referenceTime: Date = Date(), - private val preferences: AlgorithmSuite = policy.keyGenerationAlgorithmSuite -) { - - /** Builder for OpenPGP secret keys. */ - abstract class OpinionatedPgpKeyBuilder( - protected val policy: Policy, - protected val referenceTime: Date, - protected val preferences: AlgorithmSuite - ) { - - /** Make sure, that the chosen [KeyType] is allowed. */ - open fun sanitizePublicKeyAlgorithms(keyType: KeyType, policy: Policy) { - verifyAlgorithmComplianceWithPolicy(keyType, policy) - } - - /** - * Make sure, that the chosen [KeyType] complies to the given [Policy] by comparing it to - * the [Policy.PublicKeyAlgorithmPolicy]. - * - * @throws IllegalArgumentException if [keyType] fails to be accepted by [policy] - */ - private fun verifyAlgorithmComplianceWithPolicy(keyType: KeyType, policy: Policy) { - val algorithm = keyType.algorithm - val bitStrength = keyType.bitStrength - require(policy.publicKeyAlgorithmPolicy.isAcceptable(algorithm, bitStrength)) { - "Public key algorithm policy violation: $algorithm with bit strength $bitStrength is not acceptable." - } - } - } - - /** - * Build an OpenPGP v4 key. The result will be a key compliant to RFC4880, RFC6637. - * - * @param keyType type of the primary key - * @param flags key flags for the primary key. Defaults to [KeyFlag.CERTIFY_OTHER]. - * @return [OpinionatedV4KeyBuilder] which can be further modified, e.g. add subkeys, user-ids - * etc. - */ - fun buildV4Key( - keyType: KeyType, - flags: List? = listOf(KeyFlag.CERTIFY_OTHER) - ): OpinionatedV4KeyBuilder = - OpinionatedV4KeyBuilder(keyType, flags, policy, referenceTime, preferences) - - /** - * Builder for version 4 OpenPGP keys. - * - * @param primaryKeyType type of the primary key - * @param primaryFlags list of key-flags for the primary key. Can be `null`. - * @param policy algorithm policy - * @param referenceTime reference time for key generation - * @param preferences set of algorithm preferences and enabled features for the key - */ - class OpinionatedV4KeyBuilder - internal constructor( - primaryKeyType: KeyType, - primaryFlags: List?, - policy: Policy, - referenceTime: Date, - preferences: AlgorithmSuite - ) : OpinionatedPgpKeyBuilder(policy, referenceTime, preferences) { - - init { - require(primaryKeyType.canCertify) { - "KeyType $primaryKeyType MUST be certification capable." - } - sanitizePublicKeyAlgorithms(primaryKeyType, policy) - } - - private val primaryKey = - OpenPgpComponentKeyBuilder.V4PrimaryKeyBuilder(primaryKeyType, referenceTime, policy) - private val subkeys = mutableListOf() - private var addDirectKeySignature = true - - private val preferencesCallback = - SelfSignatureSubpackets.applyHashed { - setPreferredSymmetricKeyAlgorithms(preferences.symmetricKeyAlgorithms) - setPreferredHashAlgorithms(preferences.hashAlgorithms) - setPreferredCompressionAlgorithms(preferences.compressionAlgorithms) - setFeatures(*preferences.features.toTypedArray()) - primaryFlags?.let { setKeyFlags(*it.toTypedArray()) } - } - - /** - * Add a direct-key signature to the primary key. If this method is called, the automatic - * addition of a direct-key signature in the final build-step will be omitted. - * - * @param subpacketsCallback callback to modify the subpackets of the direct-key signature. - */ - fun directKeySignature( - subpacketsCallback: SelfSignatureSubpackets.Callback = SelfSignatureSubpackets.nop() - ) = apply { - addDirectKeySignature = false - primaryKey.directKeySignature( - subpacketsCallback = preferencesCallback.then(subpacketsCallback)) - } - - /** - * If this method is called, the automatic addition of a direct-key signature in the final - * build-step will be omitted. - */ - fun noDirectKeySignature() = apply { addDirectKeySignature = false } - - /** - * Add a user-id to the key. The subpackets of the binding signature are prepopulated, - * setting algorithm preferences and features. However, the subpackets can still be modified - * using the provided [subpacketsCallback]. - * - * @param userId user-id to add - * @param subpacketsCallback callback to modify the user-id binding signatures subpackets. - * @return this - */ - fun addUserId( - userId: CharSequence, - subpacketsCallback: SelfSignatureSubpackets.Callback = SelfSignatureSubpackets.nop() - ) = apply { - primaryKey.userId( - userId, - subpacketsCallback = - preferencesCallback.then(markFirstPrimaryUserId()).then(subpacketsCallback)) - } - - private fun markFirstPrimaryUserId() = - SelfSignatureSubpackets.applyHashed { - if (primaryKeyHasPrimaryUserId()) { - setPrimaryUserId(null) - } else { - setPrimaryUserId() - } - } - - private fun primaryKeyHasPrimaryUserId() = - primaryKey.pair.publicKey.let { pk -> - pk.userIDs.asSequence().any { uid -> - pk.getSignaturesForID(uid).asSequence().any { - it.hashedSubPackets.isPrimaryUserID - } - } - } - - /** - * Add a user-attribute to the key. The subpackets of the binding signature are - * prepopulated, setting algorithm preferences and features. However, the subpackets can - * still be modified using the provided [subpacketsCallback]. - * - * @param attribute user-attribute to add - * @param subpacketsCallback callback to modify the user-attribute binding signatures - * subpackets. - * @return this - */ - fun addUserAttribute( - attribute: PGPUserAttributeSubpacketVector, - subpacketsCallback: SelfSignatureSubpackets.Callback = SelfSignatureSubpackets.nop() - ) = apply { - primaryKey.userAttribute( - attribute, subpacketsCallback = preferencesCallback.then(subpacketsCallback)) - } - - /** - * Add the contents of a JPEG input stream as image attribute to the key. - * - * @param jpegInputStream input stream containing a JPEG image - * @param subpacketsCallback callback to modify the user-attribute binding signature - * subpackets. - * @return this - */ - @Throws(IOException::class) - fun addJpegImage( - jpegInputStream: InputStream, - subpacketsCallback: SelfSignatureSubpackets.Callback = SelfSignatureSubpackets.nop() - ) = apply { - PGPUserAttributeSubpacketVectorGenerator() - .apply { setImageAttribute(ImageAttribute.JPEG, Streams.readAll(jpegInputStream)) } - .generate() - .let { addUserAttribute(it, subpacketsCallback) } - } - - /** - * Add a subkey to the key. The subpackets of the binding signature will be populated with - * issuer information, the passed in [bindingTime] as signature creation time and given - * key-flags (if non-null). You can further manipulate the subpackets by passing in an - * appropriate [subpacketsCallback]. - * - * @param keyType type of the key - * @param creationTime creation time of the key. Defaults to [referenceTime] - * @param bindingTime creation time of the binding signature. Defaults to [creationTime] - * @param keyFlags list of key-flags for the subkey. - * @param subpacketsCallback callback to modify the subpackets of the binding signature - */ - fun addSubkey( - keyType: KeyType, - creationTime: Date = referenceTime, - bindingTime: Date = creationTime, - keyFlags: List? = null, - subpacketsCallback: SelfSignatureSubpackets.Callback = SelfSignatureSubpackets.nop() - ) = - addSubkey( - OpenPgpComponentKeyBuilder.V4SubkeyBuilder( - keyType, creationTime, policy, primaryKey), - SelfSignatureSubpackets.applyHashed { - setSignatureCreationTime(bindingTime) - keyFlags?.let { setKeyFlags(it) } - } - .then(subpacketsCallback)) - - fun addSubkey( - subkeyBuilder: OpenPgpComponentKeyBuilder.V4SubkeyBuilder, - subpacketsCallback: SelfSignatureSubpackets.Callback = SelfSignatureSubpackets.nop() - ) = apply { - sanitizePublicKeyAlgorithms(subkeyBuilder.type, policy) - subkeys.add(subkeyBuilder.bindingSignature(subpacketsCallback = subpacketsCallback)) - } - - /** - * Add a new subkey to be used for encryption. The binding signature will mark the key as - * encryption-capable using both [KeyFlag.ENCRYPT_COMMS] and [KeyFlag.ENCRYPT_STORAGE]. - * - * @param keyType type of the encryption subkey - * @param creationTime time of creation of the subkey - * @param bindingTime creation time of the binding signature - * @return builder - */ - fun addEncryptionSubkey( - keyType: KeyType, - creationTime: Date = referenceTime, - bindingTime: Date = creationTime - ) = apply { - require(keyType.canEncryptCommunication || keyType.canEncryptStorage) { - "KeyType $keyType cannot be used for encryption keys." - } - addSubkey( - keyType, - creationTime, - bindingTime, - listOf(KeyFlag.ENCRYPT_STORAGE, KeyFlag.ENCRYPT_COMMS)) - } - - /** - * Add a new subkey to be used for creating data signatures. The binding signature will mark - * the key as signing-capable using [KeyFlag.SIGN_DATA]. - * - * @param keyType type of the signing subkey - * @param creationTime time of creation of the subkey - * @param bindingTime creation time of the binding signature - * @return builder - */ - fun addSigningSubkey( - keyType: KeyType, - creationTime: Date = referenceTime, - bindingTime: Date = creationTime - ) = apply { - require(keyType.canSign) { "KeyType $keyType cannot be used for signing keys." } - addSubkey(keyType, creationTime, bindingTime, listOf(KeyFlag.SIGN_DATA)) - } - - /** - * Build the finished OpenPGP key. By default, the key will not be protected using - * passphrases. To set a passphrase, you can provide - * [SecretKeyRingProtector.unlockAnyKeyWith] with a passphrase of your choice. - * - * @param protector protector to secure the secret keys using passphrases. Defaults to - * [SecretKeyRingProtector.unprotectedKeys]. - * @return OpenPGP Secret Key - */ - fun build( - protector: SecretKeyRingProtector = SecretKeyRingProtector.unprotectedKeys() - ): PGPSecretKeyRing { - - // add a direct key sig with preferences - if (addDirectKeySignature) { - primaryKey.directKeySignature(subpacketsCallback = preferencesCallback) - } - - return PGPSecretKeyRing( - mutableListOf( - toSecretKey( - primaryKey, true, protector.getEncryptor(primaryKey.pair.keyID))) - .plus( - subkeys.map { - toSecretKey(it, false, protector.getEncryptor(it.pair.keyID)) - })) - } - - /** - * Convert a [OpenPgpComponentKeyBuilder.V4ComponentKeyBuilder] to a version 4 - * [PGPSecretKey]. - * - * @param key builder - * @param isPrimaryKey if true, the result will be a primary key, a subkey otherwise. - * @param encryptor encryptor to protect the secret key. Can be null for unencrypted keys. - */ - private fun toSecretKey( - key: OpenPgpComponentKeyBuilder.V4ComponentKeyBuilder<*>, - isPrimaryKey: Boolean, - encryptor: PBESecretKeyEncryptor? - ): PGPSecretKey { - return PGPSecretKey( - key.pair.privateKey, - key.pair.publicKey, - ImplementationFactory.getInstance().v4FingerprintCalculator, - isPrimaryKey, - encryptor) - } - } -} diff --git a/pgpainless-core/src/main/kotlin/org/pgpainless/key/generation/OpenPgpComponentKeyBuilder.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/key/generation/OpenPgpComponentKeyBuilder.kt deleted file mode 100644 index 3f7b62a0..00000000 --- a/pgpainless-core/src/main/kotlin/org/pgpainless/key/generation/OpenPgpComponentKeyBuilder.kt +++ /dev/null @@ -1,230 +0,0 @@ -// SPDX-FileCopyrightText: 2024 Paul Schaub -// -// SPDX-License-Identifier: Apache-2.0 - -package org.pgpainless.key.generation - -import java.security.KeyPairGenerator -import java.util.* -import org.pgpainless.bouncycastle.extensions.toPrimaryKeyFormat -import org.pgpainless.bouncycastle.extensions.toSubkeyFormat -import org.bouncycastle.openpgp.PGPKeyPair -import org.bouncycastle.openpgp.PGPPublicKey -import org.bouncycastle.openpgp.PGPSignature -import org.bouncycastle.openpgp.PGPUserAttributeSubpacketVector -import org.pgpainless.algorithm.AlgorithmSuite -import org.pgpainless.algorithm.CertificationType -import org.pgpainless.algorithm.HashAlgorithm -import org.pgpainless.algorithm.KeyFlag -import org.pgpainless.implementation.ImplementationFactory -import org.pgpainless.key.generation.type.KeyType -import org.pgpainless.policy.Policy -import org.pgpainless.provider.ProviderFactory -import org.pgpainless.signature.builder.DirectKeySelfSignatureBuilder -import org.pgpainless.signature.builder.PrimaryKeyBindingSignatureBuilder -import org.pgpainless.signature.builder.SelfSignatureBuilder -import org.pgpainless.signature.builder.SubkeyBindingSignatureBuilder -import org.pgpainless.signature.subpackets.SelfSignatureSubpackets - -class OpenPgpComponentKeyBuilder { - - abstract class V4ComponentKeyBuilder>( - val type: KeyType, - val creationTime: Date, - val certificateCreationTime: Date = Date(), - val policy: Policy - ) { - - internal var pair = generateKeyPair() - - fun subkey(type: KeyType, creationTime: Date = certificateCreationTime): V4SubkeyBuilder = - V4SubkeyBuilder(type, creationTime, policy, primaryKey()) - - internal abstract fun primaryKey(): V4PrimaryKeyBuilder - - // Note: The result is a *primary* key pair, so subkeys need adjustment (toPrimaryOrSubkey) - private fun generateKeyPair(): PGPKeyPair { - // Create raw Key Pair - val keyPair = - KeyPairGenerator.getInstance(type.name, ProviderFactory.provider) - .also { it.initialize(type.algorithmSpec) } - .generateKeyPair() - - // Form PGP Key Pair - return ImplementationFactory.getInstance() - .getPGPV4KeyPair(type.algorithm, keyPair, creationTime) - .let { toPrimaryOrSubkey(it) } - } - - /** - * Make sure, the PGP key packet is a subkey packet for subkeys, and a primary key packet - * for primary keys. - */ - protected abstract fun toPrimaryOrSubkey(keyPair: PGPKeyPair): PGPKeyPair - } - - class V4PrimaryKeyBuilder(type: KeyType, creationTime: Date, policy: Policy) : - V4ComponentKeyBuilder(type, creationTime, policy = policy) { - - fun userId( - userId: CharSequence, - certificationType: CertificationType = CertificationType.POSITIVE, - bindingTime: Date = creationTime, - hashAlgorithm: HashAlgorithm = - policy.certificationSignatureHashAlgorithmPolicy.defaultHashAlgorithm, - subpacketsCallback: SelfSignatureSubpackets.Callback = SelfSignatureSubpackets.nop() - ) = apply { - val sig = - buildCertificationFor( - userId, certificationType, bindingTime, hashAlgorithm, subpacketsCallback) - pair = - PGPKeyPair( - PGPPublicKey.addCertification(pair.publicKey, userId.toString(), sig), - pair.privateKey) - } - - fun buildCertificationFor( - userId: CharSequence, - certificationType: CertificationType, - bindingTime: Date, - hashAlgorithm: HashAlgorithm, - subpacketsCallback: SelfSignatureSubpackets.Callback - ): PGPSignature { - val builder = - SelfSignatureBuilder( - pair.privateKey, pair.publicKey, certificationType.signatureType, hashAlgorithm) - builder.hashedSubpackets.apply { setSignatureCreationTime(bindingTime) } - builder.applyCallback(subpacketsCallback) - return builder.build(userId) - } - - fun userAttribute( - userAttribute: PGPUserAttributeSubpacketVector, - certificationType: CertificationType = CertificationType.POSITIVE, - bindingTime: Date = creationTime, - hashAlgorithm: HashAlgorithm = - policy.certificationSignatureHashAlgorithmPolicy.defaultHashAlgorithm, - subpacketsCallback: SelfSignatureSubpackets.Callback = SelfSignatureSubpackets.nop() - ) = apply { - val sig = - buildCertificationFor( - userAttribute, - certificationType, - bindingTime, - hashAlgorithm, - subpacketsCallback) - pair = - PGPKeyPair( - PGPPublicKey.addCertification(pair.publicKey, userAttribute, sig), - pair.privateKey) - } - - fun buildCertificationFor( - userAttribute: PGPUserAttributeSubpacketVector, - certificationType: CertificationType, - bindingTime: Date, - hashAlgorithm: HashAlgorithm, - subpacketsCallback: SelfSignatureSubpackets.Callback - ): PGPSignature { - val builder = - SelfSignatureBuilder( - pair.privateKey, pair.publicKey, certificationType.signatureType, hashAlgorithm) - builder.hashedSubpackets.apply { setSignatureCreationTime(bindingTime) } - builder.applyCallback(subpacketsCallback) - return builder.build(userAttribute) - } - - fun directKeySignature( - bindingTime: Date = creationTime, - algorithmSuite: AlgorithmSuite = policy.keyGenerationAlgorithmSuite, - hashAlgorithm: HashAlgorithm = - policy.certificationSignatureHashAlgorithmPolicy.defaultHashAlgorithm(), - subpacketsCallback: SelfSignatureSubpackets.Callback = SelfSignatureSubpackets.nop() - ) = apply { - val sig = - buildDirectKeySignature( - bindingTime, algorithmSuite, hashAlgorithm, subpacketsCallback) - pair = PGPKeyPair(PGPPublicKey.addCertification(pair.publicKey, sig), pair.privateKey) - } - - fun buildDirectKeySignature( - bindingTime: Date, - algorithmSuite: AlgorithmSuite, - hashAlgorithm: HashAlgorithm, - subpacketsCallback: SelfSignatureSubpackets.Callback - ): PGPSignature { - val builder = - DirectKeySelfSignatureBuilder(pair.privateKey, pair.publicKey, hashAlgorithm) - - builder.hashedSubpackets.apply { - setSignatureCreationTime(bindingTime) - setPreferredHashAlgorithms(algorithmSuite.hashAlgorithms) - setPreferredSymmetricKeyAlgorithms(algorithmSuite.symmetricKeyAlgorithms) - setPreferredCompressionAlgorithms(algorithmSuite.compressionAlgorithms) - } - - builder.applyCallback(subpacketsCallback) - - return builder.build() - } - - override fun toPrimaryOrSubkey(keyPair: PGPKeyPair) = keyPair.toPrimaryKeyFormat() - - override fun primaryKey() = this - } - - class V4SubkeyBuilder( - type: KeyType, - creationTime: Date, - policy: Policy, - private val primaryKeyBuilder: V4PrimaryKeyBuilder - ) : V4ComponentKeyBuilder(type, creationTime, policy = policy) { - - fun bindingSignature( - bindingTime: Date = creationTime, - hashAlgorithm: HashAlgorithm = - policy.certificationSignatureHashAlgorithmPolicy.defaultHashAlgorithm, - subpacketsCallback: SelfSignatureSubpackets.Callback = SelfSignatureSubpackets.nop() - ) = apply { - val sig = buildBindingSignature(bindingTime, hashAlgorithm, subpacketsCallback) - pair = PGPKeyPair(PGPPublicKey.addCertification(pair.publicKey, sig), pair.privateKey) - } - - fun buildBindingSignature( - bindingTime: Date = creationTime, - hashAlgorithm: HashAlgorithm = - policy.certificationSignatureHashAlgorithmPolicy.defaultHashAlgorithm, - subpacketsCallback: SelfSignatureSubpackets.Callback = SelfSignatureSubpackets.nop() - ): PGPSignature { - val builder = - SubkeyBindingSignatureBuilder( - primaryKeyBuilder.pair.privateKey, - primaryKeyBuilder.pair.publicKey, - hashAlgorithm) - - builder.hashedSubpackets.setSignatureCreationTime(bindingTime) - builder.applyCallback(subpacketsCallback) - - // For signing-keys: Add backsig - if (builder.hashedSubpackets.getKeyFlags().orEmpty().contains(KeyFlag.SIGN_DATA) && - builder.hashedSubpackets.getEmbeddedSignaturePackets().isEmpty()) { - - // Create back-sig - val backSigBuilder = - PrimaryKeyBindingSignatureBuilder( - pair.privateKey, pair.publicKey, hashAlgorithm) - - backSigBuilder.hashedSubpackets.setSignatureCreationTime(bindingTime) - - val backSig = backSigBuilder.build(primaryKey().pair.publicKey) - builder.hashedSubpackets.addEmbeddedSignature(backSig) - } - - return builder.build(pair.publicKey) - } - - override fun toPrimaryOrSubkey(keyPair: PGPKeyPair) = keyPair.toSubkeyFormat() - - override fun primaryKey() = primaryKeyBuilder.primaryKey() - } -} diff --git a/pgpainless-core/src/test/kotlin/org/pgpainless/key/generation/GenerateOpenPgpKeyTest.kt b/pgpainless-core/src/test/kotlin/org/pgpainless/key/generation/GenerateOpenPgpKeyTest.kt deleted file mode 100644 index 13844139..00000000 --- a/pgpainless-core/src/test/kotlin/org/pgpainless/key/generation/GenerateOpenPgpKeyTest.kt +++ /dev/null @@ -1,146 +0,0 @@ -// SPDX-FileCopyrightText: 2024 Paul Schaub -// -// SPDX-License-Identifier: Apache-2.0 - -package org.pgpainless.key.generation - -import java.io.InputStream -import org.bouncycastle.util.io.Streams -import org.junit.jupiter.api.Assertions.assertArrayEquals -import org.junit.jupiter.api.Assertions.assertTrue -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.assertThrows -import org.opentest4j.TestAbortedException -import org.pgpainless.PGPainless -import org.pgpainless.algorithm.KeyFlag -import org.pgpainless.algorithm.PublicKeyAlgorithm -import org.pgpainless.key.generation.type.KeyType -import org.pgpainless.key.generation.type.eddsa.EdDSACurve -import org.pgpainless.key.generation.type.rsa.RsaLength -import org.pgpainless.key.generation.type.xdh.XDHSpec -import org.pgpainless.key.protection.SecretKeyRingProtector -import org.pgpainless.policy.Policy -import org.pgpainless.util.DateUtil - -class GenerateOpenPgpKeyTest { - - @Test - fun test() { - val date = DateUtil.parseUTCDate("2020-04-01 10:00:00 UTC") - val key = - GenerateOpenPgpKey(Policy(), date) - .buildV4Key(KeyType.EDDSA(EdDSACurve._Ed25519), listOf(KeyFlag.CERTIFY_OTHER)) - .addUserId("Alice") - .addEncryptionSubkey(KeyType.XDH(XDHSpec._X25519)) - .addSigningSubkey(KeyType.EDDSA(EdDSACurve._Ed25519)) - .build(SecretKeyRingProtector.unprotectedKeys()) - println(PGPainless.asciiArmor(key)) - } - - @Test - fun minimal() { - val key = - GenerateOpenPgpKey(Policy()) - .buildV4Key(KeyType.EDDSA(EdDSACurve._Ed25519), listOf(KeyFlag.CERTIFY_OTHER)) - .build() - println(PGPainless.asciiArmor(key)) - } - - @Test - fun minimalWithUserId() { - val key = - GenerateOpenPgpKey(Policy()) - .buildV4Key(KeyType.EDDSA(EdDSACurve._Ed25519), listOf(KeyFlag.CERTIFY_OTHER)) - .addUserId("Alice ") - .build() - println(PGPainless.asciiArmor(key)) - } - - @Test - fun primaryKeyMustBeCertificationCapable() { - assertThrows { - GenerateOpenPgpKey(Policy()) - // XDH is not signing/certification capable - .buildV4Key(KeyType.XDH(XDHSpec._X25519)) - } - } - - @Test - fun encryptionSubkeyMustBeEncryptionCapable() { - val builder = GenerateOpenPgpKey(Policy()).buildV4Key(KeyType.EDDSA(EdDSACurve._Ed25519)) - - assertThrows { - builder.addEncryptionSubkey(KeyType.EDDSA(EdDSACurve._Ed25519)) - } - } - - @Test - fun signingSubkeysMustBeSigningCapable() { - val builder = GenerateOpenPgpKey(Policy()).buildV4Key(KeyType.EDDSA(EdDSACurve._Ed25519)) - - assertThrows { - builder.addSigningSubkey(KeyType.XDH(XDHSpec._X25519)) - } - } - - @Test - fun testKeyGenerationWithUnacceptablePKAlgorithmFails() { - // Policy only allows RSA 4096 algorithms - val policy = - Policy( - publicKeyAlgorithmPolicy = - Policy.PublicKeyAlgorithmPolicy(mapOf(PublicKeyAlgorithm.RSA_GENERAL to 4096)), - ) - val builder = GenerateOpenPgpKey(policy) - - assertThrows { - builder.buildV4Key(KeyType.RSA(RsaLength._3072)) // too weak - } - - val v4Builder = builder.buildV4Key(KeyType.RSA(RsaLength._4096)) // ok - assertThrows { - v4Builder.addSigningSubkey(KeyType.RSA(RsaLength._2048)) // too weak - } - } - - @Test - fun testKeyGenerationWithJPEGAttribute() { - val key = - GenerateOpenPgpKey(Policy()) - .buildV4Key(KeyType.EDDSA(EdDSACurve._Ed25519)) - .addJpegImage(requireResource("suzanne.jpg")) - .build() - - assertTrue(key.publicKey.userAttributes.hasNext()) - assertArrayEquals( - Streams.readAll(requireResource("suzanne.jpg")), - key.publicKey.userAttributes.next().imageAttribute.imageData) - } - - private fun requireResource(resourceName: String): InputStream { - return javaClass.classLoader.getResourceAsStream(resourceName) - ?: throw TestAbortedException( - "Cannot read resource $resourceName: InputStream is null.") - } - - interface TestInterface> { - fun doSomething(): T - } - - class LowerTestClass : TestInterface { - override fun doSomething(): LowerTestClass { - TODO("Not yet implemented") - } - } - - class TestClass : TestInterface { - - override fun doSomething(): TestClass { - TODO("Not yet implemented") - } - - fun lower(): LowerTestClass { - return LowerTestClass() - } - } -} diff --git a/pgpainless-core/src/test/kotlin/org/pgpainless/key/generation/MalformedKeyGenerationTest.kt b/pgpainless-core/src/test/kotlin/org/pgpainless/key/generation/MalformedKeyGenerationTest.kt index f92a3198..c98c551c 100644 --- a/pgpainless-core/src/test/kotlin/org/pgpainless/key/generation/MalformedKeyGenerationTest.kt +++ b/pgpainless-core/src/test/kotlin/org/pgpainless/key/generation/MalformedKeyGenerationTest.kt @@ -1,6 +1,6 @@ -// SPDX-FileCopyrightText: 2024 Paul Schaub +// SPDX-FileCopyrightText: 2024 Paul Schaub // -// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: Apache-2.0 package org.pgpainless.key.generation @@ -24,13 +24,14 @@ class MalformedKeyGenerationTest { fun malformedPrimaryUserIdSubpacket() { val userId = "Alice " val key = - GenerateOpenPgpKey(Policy()) - .buildV4Key(KeyType.EDDSA(EdDSACurve._Ed25519)) - .addUserId( - userId, - SelfSignatureSubpackets.applyHashed { - setPrimaryUserId(PrimaryUserID(false, false, byteArrayOf(0x02))) - }) + OpenPgpKeyGenerator.buildV4(Policy()) + .setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519)) { + addUserId( + userId, + SelfSignatureSubpackets.applyHashed { + setPrimaryUserId(PrimaryUserID(false, false, byteArrayOf(0x02))) + }) + } .build() println(PGPainless.asciiArmor(key)) @@ -42,13 +43,14 @@ class MalformedKeyGenerationTest { @Test fun malformedExportableSubpacket() { val key = - GenerateOpenPgpKey(Policy()) - .buildV4Key(KeyType.EDDSA(EdDSACurve._Ed25519)) - .addUserId( - "Alice ", - SelfSignatureSubpackets.applyHashed { - setExportable(Exportable(false, false, byteArrayOf(0x03))) - }) + OpenPgpKeyGenerator.buildV4(Policy()) + .setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519)) { + addUserId( + "Alice ", + SelfSignatureSubpackets.applyHashed { + setExportable(Exportable(false, false, byteArrayOf(0x03))) + }) + } .build() println(PGPainless.asciiArmor(key)) @@ -60,13 +62,14 @@ class MalformedKeyGenerationTest { @Test fun malformedRevocableSubpacket() { val key = - GenerateOpenPgpKey(Policy()) - .buildV4Key(KeyType.EDDSA(EdDSACurve._Ed25519)) - .addUserId( - "Alice ", - SelfSignatureSubpackets.applyHashed { - setRevocable(Revocable(false, false, byteArrayOf(0x04))) - }) + OpenPgpKeyGenerator.buildV4(Policy()) + .setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519)) { + addUserId( + "Alice ", + SelfSignatureSubpackets.applyHashed { + setRevocable(Revocable(false, false, byteArrayOf(0x04))) + }) + } .build() println(PGPainless.asciiArmor(key)) @@ -79,27 +82,28 @@ class MalformedKeyGenerationTest { fun primaryUserIdOnDirectKeySig() { val policy = Policy() val key = - GenerateOpenPgpKey(policy) - .buildV4Key( + OpenPgpKeyGenerator.buildV4(policy) + .setPrimaryKey( KeyType.EDDSA(EdDSACurve._Ed25519), - listOf(KeyFlag.CERTIFY_OTHER, KeyFlag.SIGN_DATA)) - .directKeySignature( - SelfSignatureSubpackets.applyHashed { - setPrimaryUserId() - setPreferredHashAlgorithms(HashAlgorithm.SHA224) - }) - .addUserId( - "Alice ", - SelfSignatureSubpackets.applyHashed { - setPrimaryUserId(null) - setPreferredHashAlgorithms(HashAlgorithm.SHA256) - }) - .addUserId( - "Bob ", - SelfSignatureSubpackets.applyHashed { - setPrimaryUserId() - setPreferredHashAlgorithms(HashAlgorithm.SHA384) - }) + listOf(KeyFlag.CERTIFY_OTHER, KeyFlag.SIGN_DATA)) { + addDirectKeySignature( + SelfSignatureSubpackets.applyHashed { + setPrimaryUserId() + setPreferredHashAlgorithms(HashAlgorithm.SHA224) + }) + addUserId( + "Alice ", + SelfSignatureSubpackets.applyHashed { + setPrimaryUserId(null) + setPreferredHashAlgorithms(HashAlgorithm.SHA256) + }) + addUserId( + "Bob ", + SelfSignatureSubpackets.applyHashed { + setPrimaryUserId() + setPreferredHashAlgorithms(HashAlgorithm.SHA384) + }) + } .addEncryptionSubkey(KeyType.XDH(XDHSpec._X25519)) .build() println(key.toAsciiArmor())