From 3b335fa627e7e1b5f4292ed282ac5a34bbc328ce Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Mon, 22 Jan 2024 16:52:40 +0100 Subject: [PATCH] Progress --- .../key/generation/BaseOpenPgpKeyBuilder.kt | 253 +++++++++++++ .../key/generation/OpenPgpKeyBuilder.kt | 336 +++++++----------- .../key/generation/OpenPgpV4KeyGenerator.kt | 109 ------ ...eratorTest.kt => OpenPgpKeyBuilderTest.kt} | 21 +- 4 files changed, 395 insertions(+), 324 deletions(-) create mode 100644 pgpainless-core/src/main/kotlin/org/pgpainless/key/generation/BaseOpenPgpKeyBuilder.kt delete mode 100644 pgpainless-core/src/main/kotlin/org/pgpainless/key/generation/OpenPgpV4KeyGenerator.kt rename pgpainless-core/src/test/kotlin/org/pgpainless/key/generation/{OpenPgpV4KeyGeneratorTest.kt => OpenPgpKeyBuilderTest.kt} (62%) diff --git a/pgpainless-core/src/main/kotlin/org/pgpainless/key/generation/BaseOpenPgpKeyBuilder.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/key/generation/BaseOpenPgpKeyBuilder.kt new file mode 100644 index 00000000..540f1969 --- /dev/null +++ b/pgpainless-core/src/main/kotlin/org/pgpainless/key/generation/BaseOpenPgpKeyBuilder.kt @@ -0,0 +1,253 @@ +// 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.bouncycastle.bcpg.PublicSubkeyPacket +import org.bouncycastle.openpgp.PGPKeyPair +import org.bouncycastle.openpgp.PGPPrivateKey +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 BaseOpenPgpKeyBuilder { + + abstract class BaseV4KeyBuilder>( + val type: KeyType, + val creationTime: Date, + val certificateCreationTime: Date = Date(), + val policy: Policy + ) { + + internal var key = generateKeyPair() + + fun subkey( + type: KeyType, + creationTime: Date = certificateCreationTime + ): BaseV4SubkeyBuilder = BaseV4SubkeyBuilder(type, creationTime, policy, primaryKey()) + + internal abstract fun primaryKey(): BaseV4PrimaryKeyBuilder + + 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 { adjustKeyPacket(it) } + } + + /** + * Make sure, the PGP key packet is a subkey packet for subkeys, and a primary key packet + * for primary keys. + */ + protected abstract fun adjustKeyPacket(keyPair: PGPKeyPair): PGPKeyPair + } + + class BaseV4PrimaryKeyBuilder(type: KeyType, creationTime: Date, policy: Policy) : + BaseV4KeyBuilder(type, creationTime, policy = policy) { + + fun userId( + userId: CharSequence, + algorithmSuite: AlgorithmSuite, + certificationType: CertificationType = CertificationType.POSITIVE, + bindingTime: Date = creationTime, + hashAlgorithm: HashAlgorithm = + policy.certificationSignatureHashAlgorithmPolicy.defaultHashAlgorithm, + subpacketsCallback: SelfSignatureSubpackets.Callback = + SelfSignatureSubpackets.defaultCallback() + ) = apply { + val sig = + buildCertificationFor( + userId, algorithmSuite, certificationType, bindingTime, hashAlgorithm, subpacketsCallback) + key = + PGPKeyPair( + PGPPublicKey.addCertification(key.publicKey, userId.toString(), sig), + key.privateKey) + } + + fun buildCertificationFor( + userId: CharSequence, + algorithmSuite: AlgorithmSuite, + certificationType: CertificationType, + bindingTime: Date, + hashAlgorithm: HashAlgorithm, + subpacketsCallback: SelfSignatureSubpackets.Callback + ): PGPSignature { + val builder = + SelfSignatureBuilder( + key.privateKey, key.publicKey, certificationType.signatureType, hashAlgorithm) + builder.hashedSubpackets.apply { + setSignatureCreationTime(bindingTime) + setPreferredHashAlgorithms(algorithmSuite.hashAlgorithms) + setPreferredSymmetricKeyAlgorithms(algorithmSuite.symmetricKeyAlgorithms) + setPreferredCompressionAlgorithms(algorithmSuite.compressionAlgorithms) + } + builder.applyCallback(subpacketsCallback) + return builder.build(userId) + } + + fun userAttribute( + userAttribute: PGPUserAttributeSubpacketVector, + algorithmSuite: AlgorithmSuite, + certificationType: CertificationType = CertificationType.POSITIVE, + bindingTime: Date = creationTime, + hashAlgorithm: HashAlgorithm = + policy.certificationSignatureHashAlgorithmPolicy.defaultHashAlgorithm, + subpacketsCallback: SelfSignatureSubpackets.Callback = + SelfSignatureSubpackets.defaultCallback() + ) = apply { + val sig = + buildCertificationFor( + userAttribute, + algorithmSuite, + certificationType, + bindingTime, + hashAlgorithm, + subpacketsCallback) + key = + PGPKeyPair( + PGPPublicKey.addCertification(key.publicKey, userAttribute, sig), + key.privateKey) + } + + fun buildCertificationFor( + userAttribute: PGPUserAttributeSubpacketVector, + algorithmSuite: AlgorithmSuite, + certificationType: CertificationType, + bindingTime: Date, + hashAlgorithm: HashAlgorithm, + subpacketsCallback: SelfSignatureSubpackets.Callback + ): PGPSignature { + val builder = + SelfSignatureBuilder( + key.privateKey, key.publicKey, certificationType.signatureType, hashAlgorithm) + builder.hashedSubpackets.apply { + setSignatureCreationTime(bindingTime) + setPreferredHashAlgorithms(algorithmSuite.hashAlgorithms) + setPreferredSymmetricKeyAlgorithms(algorithmSuite.symmetricKeyAlgorithms) + setPreferredCompressionAlgorithms(algorithmSuite.compressionAlgorithms) + } + builder.applyCallback(subpacketsCallback) + return builder.build(userAttribute) + } + + fun directKeySignature( + bindingTime: Date = creationTime, + hashAlgorithm: HashAlgorithm = + policy.certificationSignatureHashAlgorithmPolicy.defaultHashAlgorithm(), + subpacketsCallback: SelfSignatureSubpackets.Callback = + SelfSignatureSubpackets.defaultCallback() + ) = apply { + val sig = buildDirectKeySignature(bindingTime, hashAlgorithm, subpacketsCallback) + key = PGPKeyPair(PGPPublicKey.addCertification(key.publicKey, sig), key.privateKey) + } + + fun buildDirectKeySignature( + bindingTime: Date, + hashAlgorithm: HashAlgorithm, + subpacketsCallback: SelfSignatureSubpackets.Callback + ): PGPSignature { + val builder = + DirectKeySelfSignatureBuilder(key.privateKey, key.publicKey, hashAlgorithm) + + builder.hashedSubpackets.setSignatureCreationTime(bindingTime) + builder.applyCallback(subpacketsCallback) + + return builder.build() + } + + override fun adjustKeyPacket(keyPair: PGPKeyPair): PGPKeyPair { + return keyPair // is already a secret key packet + } + + override fun primaryKey() = this + } + + class BaseV4SubkeyBuilder( + type: KeyType, + creationTime: Date, + policy: Policy, + private val primaryKeyBuilder: BaseV4PrimaryKeyBuilder + ) : BaseV4KeyBuilder(type, creationTime, policy = policy) { + + fun bindingSignature( + bindingTime: Date = creationTime, + hashAlgorithm: HashAlgorithm = + policy.certificationSignatureHashAlgorithmPolicy.defaultHashAlgorithm, + subpacketsCallback: SelfSignatureSubpackets.Callback = + SelfSignatureSubpackets.defaultCallback() + ) = apply { + val sig = buildBindingSignature(bindingTime, hashAlgorithm, subpacketsCallback) + key = PGPKeyPair(PGPPublicKey.addCertification(key.publicKey, sig), key.privateKey) + } + + fun buildBindingSignature( + bindingTime: Date = creationTime, + hashAlgorithm: HashAlgorithm = + policy.certificationSignatureHashAlgorithmPolicy.defaultHashAlgorithm, + subpacketsCallback: SelfSignatureSubpackets.Callback = + SelfSignatureSubpackets.defaultCallback() + ): PGPSignature { + val builder = + SubkeyBindingSignatureBuilder( + primaryKeyBuilder.key.privateKey, + primaryKeyBuilder.key.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(key.privateKey, key.publicKey, hashAlgorithm) + + backSigBuilder.hashedSubpackets.setSignatureCreationTime(bindingTime) + + val backSig = backSigBuilder.build(primaryKey().key.publicKey) + builder.hashedSubpackets.addEmbeddedSignature(backSig) + } + + return builder.build(key.publicKey) + } + + override fun adjustKeyPacket(keyPair: PGPKeyPair): PGPKeyPair { + val fpCalc = ImplementationFactory.getInstance().keyFingerprintCalculator + val pubkey = keyPair.publicKey + val privkey = keyPair.privateKey + // form subkey packet + val subkey = + PublicSubkeyPacket( + pubkey.algorithm, pubkey.creationTime, pubkey.publicKeyPacket.key) + return PGPKeyPair( + PGPPublicKey(subkey, fpCalc), + PGPPrivateKey(pubkey.keyID, subkey, privkey.privateKeyDataPacket)) + } + + override fun primaryKey() = primaryKeyBuilder.primaryKey() + } +} diff --git a/pgpainless-core/src/main/kotlin/org/pgpainless/key/generation/OpenPgpKeyBuilder.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/key/generation/OpenPgpKeyBuilder.kt index 7b55fe3f..158ca1ae 100644 --- a/pgpainless-core/src/main/kotlin/org/pgpainless/key/generation/OpenPgpKeyBuilder.kt +++ b/pgpainless-core/src/main/kotlin/org/pgpainless/key/generation/OpenPgpKeyBuilder.kt @@ -1,236 +1,156 @@ +// 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.bouncycastle.bcpg.PublicSubkeyPacket -import org.bouncycastle.openpgp.PGPKeyPair -import org.bouncycastle.openpgp.PGPPrivateKey -import org.bouncycastle.openpgp.PGPPublicKey -import org.bouncycastle.openpgp.PGPSignature +import org.bouncycastle.openpgp.PGPSecretKey +import org.bouncycastle.openpgp.PGPSecretKeyRing import org.bouncycastle.openpgp.PGPUserAttributeSubpacketVector -import org.pgpainless.algorithm.CertificationType -import org.pgpainless.algorithm.HashAlgorithm +import org.bouncycastle.openpgp.operator.PBESecretKeyEncryptor +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.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 OpenPgpKeyBuilder { +open class OpenPgpKeyBuilder( + protected val policy: Policy, + protected val referenceTime: Date = Date(), + protected val keyGenerationPolicy: AlgorithmSuite = policy.keyGenerationAlgorithmSuite +) { fun buildV4Key( - type: KeyType, - creationTime: Date = Date(), - policy: Policy - ): V4PrimaryKeyBuilder = V4PrimaryKeyBuilder(type, creationTime, policy) + keyType: KeyType, + ): V4OpenPgpKeyBuilder = + V4OpenPgpKeyBuilder(keyType, policy, referenceTime, keyGenerationPolicy) - abstract class V4KeyBuilder>( - val type: KeyType, - val creationTime: Date, - val certificateCreationTime: Date = Date(), - val policy: Policy - ) { - - internal var key = generateKeyPair() - - fun subkey(type: KeyType, creationTime: Date = certificateCreationTime): V4SubkeyBuilder = - V4SubkeyBuilder(type, creationTime, policy, primaryKey()) - - internal abstract fun primaryKey(): V4PrimaryKeyBuilder - - 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 { adjustKeyPacket(it) } - } - - /** - * Make sure, the PGP key packet is a subkey packet for subkeys, and a primary key packet - * for primary keys. - */ - protected abstract fun adjustKeyPacket(keyPair: PGPKeyPair): PGPKeyPair - } - - class V4PrimaryKeyBuilder(type: KeyType, creationTime: Date, policy: Policy) : - V4KeyBuilder(type, creationTime, policy = policy) { - - fun userId( - userId: CharSequence, - certificationType: CertificationType = CertificationType.POSITIVE, - bindingTime: Date = creationTime, - hashAlgorithm: HashAlgorithm = - policy.certificationSignatureHashAlgorithmPolicy.defaultHashAlgorithm, - subpacketsCallback: SelfSignatureSubpackets.Callback = - SelfSignatureSubpackets.defaultCallback() - ) = apply { - val sig = - buildCertificationFor( - userId, certificationType, bindingTime, hashAlgorithm, subpacketsCallback) - key = - PGPKeyPair( - PGPPublicKey.addCertification(key.publicKey, userId.toString(), sig), - key.privateKey) - } - - fun buildCertificationFor( - userId: CharSequence, - certificationType: CertificationType, - bindingTime: Date, - hashAlgorithm: HashAlgorithm, - subpacketsCallback: SelfSignatureSubpackets.Callback - ): PGPSignature { - val builder = - SelfSignatureBuilder( - key.privateKey, key.publicKey, certificationType.signatureType, hashAlgorithm) - builder.hashedSubpackets.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.defaultCallback() - ) = apply { - val sig = - buildCertificationFor( - userAttribute, - certificationType, - bindingTime, - hashAlgorithm, - subpacketsCallback) - key = - PGPKeyPair( - PGPPublicKey.addCertification(key.publicKey, userAttribute, sig), - key.privateKey) - } - - fun buildCertificationFor( - userAttribute: PGPUserAttributeSubpacketVector, - certificationType: CertificationType, - bindingTime: Date, - hashAlgorithm: HashAlgorithm, - subpacketsCallback: SelfSignatureSubpackets.Callback - ): PGPSignature { - val builder = - SelfSignatureBuilder( - key.privateKey, key.publicKey, certificationType.signatureType, hashAlgorithm) - builder.hashedSubpackets.setSignatureCreationTime(bindingTime) - builder.applyCallback(subpacketsCallback) - return builder.build(userAttribute) - } - - fun directKeySignature( - bindingTime: Date = creationTime, - hashAlgorithm: HashAlgorithm = - policy.certificationSignatureHashAlgorithmPolicy.defaultHashAlgorithm(), - subpacketsCallback: SelfSignatureSubpackets.Callback = - SelfSignatureSubpackets.defaultCallback() - ) = apply { - val sig = buildDirectKeySignature(bindingTime, hashAlgorithm, subpacketsCallback) - key = PGPKeyPair(PGPPublicKey.addCertification(key.publicKey, sig), key.privateKey) - } - - fun buildDirectKeySignature( - bindingTime: Date, - hashAlgorithm: HashAlgorithm, - subpacketsCallback: SelfSignatureSubpackets.Callback - ): PGPSignature { - val builder = - DirectKeySelfSignatureBuilder(key.privateKey, key.publicKey, hashAlgorithm) - - builder.hashedSubpackets.setSignatureCreationTime(bindingTime) - builder.applyCallback(subpacketsCallback) - - return builder.build() - } - - override fun adjustKeyPacket(keyPair: PGPKeyPair): PGPKeyPair { - return keyPair // is already a secret key packet - } - - override fun primaryKey() = this - } - - class V4SubkeyBuilder( - type: KeyType, - creationTime: Date, + class V4OpenPgpKeyBuilder( + keyType: KeyType, policy: Policy, - private val primaryKeyBuilder: V4PrimaryKeyBuilder - ) : V4KeyBuilder(type, creationTime, policy = policy) { + referenceTime: Date, + keyGenerationPolicy: AlgorithmSuite + ) : OpenPgpKeyBuilder(policy, referenceTime, keyGenerationPolicy) { - fun bindingSignature( - bindingTime: Date = creationTime, - hashAlgorithm: HashAlgorithm = - policy.certificationSignatureHashAlgorithmPolicy.defaultHashAlgorithm, + private val primaryKey = + BaseOpenPgpKeyBuilder.BaseV4PrimaryKeyBuilder(keyType, referenceTime, policy) + + private val subkeys = mutableListOf() + + fun addUserId( + userId: CharSequence, + algorithmSuite: AlgorithmSuite = keyGenerationPolicy, subpacketsCallback: SelfSignatureSubpackets.Callback = SelfSignatureSubpackets.defaultCallback() + ) = apply { primaryKey.userId(userId, algorithmSuite, subpacketsCallback = subpacketsCallback) } + + fun addUserAttribute( + attribute: PGPUserAttributeSubpacketVector, + algorithmSuite: AlgorithmSuite = keyGenerationPolicy, + subpacketsCallback: SelfSignatureSubpackets.Callback = + SelfSignatureSubpackets.defaultCallback() + ) = apply { primaryKey.userAttribute(attribute, algorithmSuite, subpacketsCallback = subpacketsCallback) } + + fun addSubkey( + keyType: KeyType, + creationTime: Date = referenceTime, + bindingTime: Date = creationTime, + keyFlags: List? + ) = + addSubkey( + BaseOpenPgpKeyBuilder.BaseV4SubkeyBuilder( + keyType, creationTime, policy, primaryKey), + bindingTime, + keyFlags) + + fun addSubkey( + subkeyBuilder: BaseOpenPgpKeyBuilder.BaseV4SubkeyBuilder, + bindingTime: Date = subkeyBuilder.creationTime, + keyFlags: List? ) = apply { - val sig = buildBindingSignature(bindingTime, hashAlgorithm, subpacketsCallback) - key = PGPKeyPair(PGPPublicKey.addCertification(key.publicKey, sig), key.privateKey) + subkeys.add( + subkeyBuilder.also { + it.bindingSignature( + bindingTime, + subpacketsCallback = + object : SelfSignatureSubpackets.Callback { + override fun modifyHashedSubpackets( + hashedSubpackets: SelfSignatureSubpackets + ) { + hashedSubpackets.setSignatureCreationTime(bindingTime) + keyFlags?.let { flagList -> + hashedSubpackets.setKeyFlags(flagList) + } + } + }) + }) } - fun buildBindingSignature( - bindingTime: Date = creationTime, - hashAlgorithm: HashAlgorithm = - policy.certificationSignatureHashAlgorithmPolicy.defaultHashAlgorithm, - subpacketsCallback: SelfSignatureSubpackets.Callback = - SelfSignatureSubpackets.defaultCallback() - ): PGPSignature { - val builder = - SubkeyBindingSignatureBuilder( - primaryKeyBuilder.key.privateKey, - primaryKeyBuilder.key.publicKey, - hashAlgorithm) + fun addEncryptionSubkey( + keyType: KeyType, + creationTime: Date = referenceTime, + bindingTime: Date = creationTime + ) = + addSubkey( + keyType, + creationTime, + bindingTime, + listOf(KeyFlag.ENCRYPT_STORAGE, KeyFlag.ENCRYPT_COMMS)) - builder.hashedSubpackets.setSignatureCreationTime(bindingTime) - builder.applyCallback(subpacketsCallback) + fun addSigningSubkey( + keyType: KeyType, + creationTime: Date = referenceTime, + bindingTime: Date = creationTime + ) = addSubkey(keyType, creationTime, bindingTime, listOf(KeyFlag.SIGN_DATA)) - if (builder.hashedSubpackets.getKeyFlags().orEmpty().contains(KeyFlag.SIGN_DATA) && - builder.hashedSubpackets.getEmbeddedSignaturePackets().isEmpty()) { + fun build( + protector: SecretKeyRingProtector = SecretKeyRingProtector.unprotectedKeys() + ): PGPSecretKeyRing { + return PGPSecretKeyRing( + mutableListOf( + PGPSecretKey( + primaryKey.key.privateKey, + primaryKey.key.publicKey, + ImplementationFactory.getInstance().v4FingerprintCalculator, + true, + protector.getEncryptor(primaryKey.key.keyID))) + .plus( + subkeys.map { + PGPSecretKey( + it.key.privateKey, + it.key.publicKey, + ImplementationFactory.getInstance().v4FingerprintCalculator, + false, + protector.getEncryptor(it.key.keyID)) + })) + } - // Create back-sig - val backSigBuilder = - PrimaryKeyBindingSignatureBuilder(key.privateKey, key.publicKey, hashAlgorithm) - - backSigBuilder.hashedSubpackets.setSignatureCreationTime(bindingTime) - - val backSig = backSigBuilder.build(primaryKey().key.publicKey) - builder.hashedSubpackets.addEmbeddedSignature(backSig) + private fun defaultPrimarySubpacketsCallback(): SelfSignatureSubpackets.Callback = + object : SelfSignatureSubpackets.Callback { + override fun modifyHashedSubpackets(hashedSubpackets: SelfSignatureSubpackets) { + hashedSubpackets.apply { + setPreferredHashAlgorithms(keyGenerationPolicy.hashAlgorithms) + setPreferredSymmetricKeyAlgorithms(keyGenerationPolicy.symmetricKeyAlgorithms) + setPreferredCompressionAlgorithms(keyGenerationPolicy.compressionAlgorithms) + setKeyFlags(KeyFlag.CERTIFY_OTHER) + } + } } - return builder.build(key.publicKey) + private fun toSecretKey( + key: BaseOpenPgpKeyBuilder.BaseV4KeyBuilder<*>, + isPrimaryKey: Boolean, + encryptor: PBESecretKeyEncryptor? + ): PGPSecretKey { + return PGPSecretKey( + key.key.privateKey, + key.key.publicKey, + ImplementationFactory.getInstance().v4FingerprintCalculator, + isPrimaryKey, + encryptor) } - - override fun adjustKeyPacket(keyPair: PGPKeyPair): PGPKeyPair { - val fpCalc = ImplementationFactory.getInstance().keyFingerprintCalculator - val pubkey = keyPair.publicKey - val privkey = keyPair.privateKey - // form subkey packet - val subkey = - PublicSubkeyPacket( - pubkey.algorithm, pubkey.creationTime, pubkey.publicKeyPacket.key) - return PGPKeyPair( - PGPPublicKey(subkey, fpCalc), - PGPPrivateKey(pubkey.keyID, subkey, privkey.privateKeyDataPacket)) - } - - override fun primaryKey() = primaryKeyBuilder.primaryKey() } } diff --git a/pgpainless-core/src/main/kotlin/org/pgpainless/key/generation/OpenPgpV4KeyGenerator.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/key/generation/OpenPgpV4KeyGenerator.kt deleted file mode 100644 index 341c3db9..00000000 --- a/pgpainless-core/src/main/kotlin/org/pgpainless/key/generation/OpenPgpV4KeyGenerator.kt +++ /dev/null @@ -1,109 +0,0 @@ -package org.pgpainless.key.generation - -import java.util.* -import org.bouncycastle.openpgp.PGPSecretKey -import org.bouncycastle.openpgp.PGPSecretKeyRing -import org.bouncycastle.openpgp.PGPUserAttributeSubpacketVector -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 - -class OpenPgpV4KeyGenerator( - keyType: KeyType, - private val policy: Policy, - private val referenceTime: Date = Date(), - private val keyGenerationPolicy: AlgorithmSuite = policy.keyGenerationAlgorithmSuite -) { - - private val primaryKey = OpenPgpKeyBuilder.V4PrimaryKeyBuilder(keyType, referenceTime, policy) - private val subkeys = mutableListOf() - - fun addUserId( - userId: CharSequence, - subpacketsCallback: SelfSignatureSubpackets.Callback = - SelfSignatureSubpackets.defaultCallback() - ) = apply { primaryKey.userId(userId, subpacketsCallback = subpacketsCallback) } - - fun addUserAttribute( - attribute: PGPUserAttributeSubpacketVector, - subpacketsCallback: SelfSignatureSubpackets.Callback = - SelfSignatureSubpackets.defaultCallback() - ) = apply { - primaryKey.userAttribute(attribute, subpacketsCallback = subpacketsCallback) - } - - fun addSubkey( - keyType: KeyType, - creationTime: Date = referenceTime, - bindingTime: Date = creationTime - ) = - addSubkey( - OpenPgpKeyBuilder.V4SubkeyBuilder(keyType, creationTime, policy, primaryKey), - bindingTime) - - fun addSubkey( - subkeyBuilder: OpenPgpKeyBuilder.V4SubkeyBuilder, - bindingTime: Date = subkeyBuilder.creationTime - ) = apply { subkeys.add(subkeyBuilder) } - - fun addEncryptionSubkey( - keyType: KeyType, - creationTime: Date = referenceTime, - bindingTime: Date = creationTime - ) = - addSubkey( - OpenPgpKeyBuilder.V4SubkeyBuilder(keyType, creationTime, policy, primaryKey) - .bindingSignature( - subpacketsCallback = - object : SelfSignatureSubpackets.Callback { - override fun modifyHashedSubpackets( - hashedSubpackets: SelfSignatureSubpackets - ) { - hashedSubpackets.setSignatureCreationTime(bindingTime) - hashedSubpackets.setKeyFlags( - KeyFlag.ENCRYPT_STORAGE, KeyFlag.ENCRYPT_COMMS) - } - })) - - fun addSigningSubkey( - keyType: KeyType, - creationTime: Date = referenceTime, - bindingTime: Date = creationTime - ) = - addSubkey( - OpenPgpKeyBuilder.V4SubkeyBuilder(keyType, creationTime, policy, primaryKey) - .bindingSignature( - subpacketsCallback = - object : SelfSignatureSubpackets.Callback { - override fun modifyHashedSubpackets( - hashedSubpackets: SelfSignatureSubpackets - ) { - hashedSubpackets.setSignatureCreationTime(bindingTime) - hashedSubpackets.setKeyFlags(KeyFlag.SIGN_DATA) - } - })) - - fun build(protector: SecretKeyRingProtector): PGPSecretKeyRing { - return PGPSecretKeyRing( - mutableListOf( - PGPSecretKey( - primaryKey.key.privateKey, - primaryKey.key.publicKey, - ImplementationFactory.getInstance().v4FingerprintCalculator, - true, - protector.getEncryptor(primaryKey.key.keyID))) - .plus( - subkeys.map { - PGPSecretKey( - it.key.privateKey, - it.key.publicKey, - ImplementationFactory.getInstance().v4FingerprintCalculator, - false, - protector.getEncryptor(it.key.keyID)) - })) - } -} diff --git a/pgpainless-core/src/test/kotlin/org/pgpainless/key/generation/OpenPgpV4KeyGeneratorTest.kt b/pgpainless-core/src/test/kotlin/org/pgpainless/key/generation/OpenPgpKeyBuilderTest.kt similarity index 62% rename from pgpainless-core/src/test/kotlin/org/pgpainless/key/generation/OpenPgpV4KeyGeneratorTest.kt rename to pgpainless-core/src/test/kotlin/org/pgpainless/key/generation/OpenPgpKeyBuilderTest.kt index 3afc0cd7..bae0bc6d 100644 --- a/pgpainless-core/src/test/kotlin/org/pgpainless/key/generation/OpenPgpV4KeyGeneratorTest.kt +++ b/pgpainless-core/src/test/kotlin/org/pgpainless/key/generation/OpenPgpKeyBuilderTest.kt @@ -11,22 +11,29 @@ import org.pgpainless.key.protection.SecretKeyRingProtector import org.pgpainless.policy.Policy import org.pgpainless.util.DateUtil -class OpenPgpV4KeyGeneratorTest { +class OpenPgpKeyBuilderTest { @Test fun test() { val date = DateUtil.parseUTCDate("2020-04-01 10:00:00 UTC") - val key = - OpenPgpV4KeyGenerator( - KeyType.EDDSA(EdDSACurve._Ed25519), Policy.getInstance(), referenceTime = date) + val key = OpenPgpKeyBuilder(Policy.getInstance(), date) + .buildV4Key(KeyType.EDDSA(EdDSACurve._Ed25519)) .addUserId("Alice") .addUserAttribute( - PGPUserAttributeSubpacketVectorGenerator().apply { - setImageAttribute(ImageAttribute.JPEG, byteArrayOf()) - }.generate()) + PGPUserAttributeSubpacketVectorGenerator() + .apply { setImageAttribute(ImageAttribute.JPEG, byteArrayOf()) } + .generate()) .addEncryptionSubkey(KeyType.XDH(XDHSpec._X25519)) .addSigningSubkey(KeyType.EDDSA(EdDSACurve._Ed25519)) .build(SecretKeyRingProtector.unprotectedKeys()) println(PGPainless.asciiArmor(key)) } + + @Test + fun minimal() { + val key = OpenPgpKeyBuilder(Policy.getInstance()) + .buildV4Key(KeyType.EDDSA(EdDSACurve._Ed25519)) + .build() + println(PGPainless.asciiArmor(key)) + } }