From 0e25ada166499f2854a9ce8af8ba910a93f3abb1 Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Sat, 6 Jan 2024 01:31:12 +0100 Subject: [PATCH] WIP: Work on new key generation API --- .../key/generation/OpenPgpKeyBuilder.kt | 99 +++++++++++++++ .../key/generation/OpenPgpV4KeyGenerator.kt | 117 ++++++++++++++++++ .../generation/OpenPgpV4KeyGeneratorTest.kt | 26 ++++ 3 files changed, 242 insertions(+) create mode 100644 pgpainless-core/src/main/kotlin/org/pgpainless/key/generation/OpenPgpKeyBuilder.kt create mode 100644 pgpainless-core/src/main/kotlin/org/pgpainless/key/generation/OpenPgpV4KeyGenerator.kt create mode 100644 pgpainless-core/src/test/kotlin/org/pgpainless/key/generation/OpenPgpV4KeyGeneratorTest.kt 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 new file mode 100644 index 00000000..2d46322a --- /dev/null +++ b/pgpainless-core/src/main/kotlin/org/pgpainless/key/generation/OpenPgpKeyBuilder.kt @@ -0,0 +1,99 @@ +package org.pgpainless.key.generation + +import org.bouncycastle.openpgp.PGPKeyPair +import org.bouncycastle.openpgp.PGPSecretKeyRing +import org.pgpainless.implementation.ImplementationFactory +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.provider.ProviderFactory +import java.security.KeyPairGenerator +import java.util.Date + +class OpenPgpKeyBuilder { + + fun buildV4Key( + type: KeyType, + creationTime: Date = Date() + ): V4PrimaryKeyBuilder = V4PrimaryKeyBuilder(type, creationTime) + + abstract class V4KeyBuilder>( + protected val type: KeyType, + protected val creationTime: Date, + val certificateCreationTime: Date = Date() + ) { + + internal val keyPair = generateKeyPair() + + fun subkey( + type: KeyType, + creationTime: Date = certificateCreationTime + ): V4SubkeyBuilder = V4SubkeyBuilder(type, creationTime, this) + + fun generate(): PGPSecretKeyRing { + val keys = collectKeysForGeneration() + + assert(keys.first() is V4PrimaryKeyBuilder) + assert(keys.drop(1).all { it is V4SubkeyBuilder }) + + val primaryKey: V4PrimaryKeyBuilder = keys.first() as V4PrimaryKeyBuilder + + } + + private fun collectKeysForGeneration(): List> = + if (this is V4SubkeyBuilder) { + predecessor.collectKeysForGeneration().plus(this) + } else { + listOf(this) + } + + 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) + } + } + + class V4PrimaryKeyBuilder( + type: KeyType, + creationTime: Date + ): V4KeyBuilder(type, creationTime) { + + fun userId(userId: CharSequence) = userId(userId, OpenPgpV4KeyGenerator.Preferences()) + + fun userId(userId: CharSequence, preferences: OpenPgpV4KeyGenerator.Preferences) = apply { + keyPair.publicKey. + } + + fun selfSignature(preferences: OpenPgpV4KeyGenerator.Preferences) = apply { + + } + } + + class V4SubkeyBuilder( + type: KeyType, + creationTime: Date, + internal val predecessor: V4KeyBuilder<*>, + ): V4KeyBuilder(type, creationTime, predecessor.certificateCreationTime) { + fun bindingSignature(preferences: OpenPgpV4KeyGenerator.Preferences) = apply { + + } + } +} + +fun test() { + OpenPgpKeyBuilder() + .buildV4Key(KeyType.RSA(RsaLength._4096)) + .selfSignature(OpenPgpV4KeyGenerator.Preferences()) + .userId("Alice", OpenPgpV4KeyGenerator.Preferences()) + .subkey(KeyType.EDDSA(EdDSACurve._Ed25519)) + .bindingSignature(OpenPgpV4KeyGenerator.Preferences()) + .subkey(KeyType.XDH(XDHSpec._X25519)) + .bindingSignature(OpenPgpV4KeyGenerator.Preferences()) +} 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 new file mode 100644 index 00000000..9b0ff6f4 --- /dev/null +++ b/pgpainless-core/src/main/kotlin/org/pgpainless/key/generation/OpenPgpV4KeyGenerator.kt @@ -0,0 +1,117 @@ +package org.pgpainless.key.generation + +import org.bouncycastle.openpgp.PGPSecretKeyRing +import org.pgpainless.algorithm.KeyFlag +import org.pgpainless.key.generation.type.KeyType +import org.pgpainless.policy.Policy +import java.util.* + +class OpenPgpV4KeyGenerator( + private val policy: Policy, + private val referenceTime: Date = Date() +) { + + fun primaryKey( + type: KeyType, + vararg flag: KeyFlag = arrayOf(KeyFlag.CERTIFY_OTHER, KeyFlag.SIGN_DATA) + ) = primaryKey(type, referenceTime, *flag) + + fun primaryKey( + type: KeyType, + creationTime: Date, + vararg flag: KeyFlag = arrayOf(KeyFlag.CERTIFY_OTHER, KeyFlag.SIGN_DATA) + ) = WithSubkeys( + KeyDescription(type, creationTime, flag.toList()), + policy, + referenceTime + ) + + class WithSubkeys( + private val primaryKey: KeyDescription, + private val policy: Policy, + private val referenceTime: Date + ) { + + val builder = OpenPgpKeyBuilder() + .buildV4Key(primaryKey.type) + . + + init { + + } + + fun encryptionSubkey( + type: KeyType, + vararg flag: KeyFlag = arrayOf(KeyFlag.ENCRYPT_COMMS, KeyFlag.ENCRYPT_STORAGE) + ) = encryptionSubkey(type, referenceTime, *flag) + + fun encryptionSubkey( + type: KeyType, + creationTime: Date, + vararg flag: KeyFlag = arrayOf(KeyFlag.ENCRYPT_COMMS, KeyFlag.ENCRYPT_STORAGE) + ) = subkey(type, creationTime, *flag) + + fun signingSubkey( + type: KeyType + ) = signingSubkey(type, referenceTime) + + fun signingSubkey( + type: KeyType, + creationTime: Date + ) = subkey(type, creationTime, KeyFlag.SIGN_DATA) + + fun subkey( + type: KeyType, + vararg flag: KeyFlag + ) = subkey(type, referenceTime, *flag) + + fun subkey( + type: KeyType, + creationTime: Date = referenceTime, + vararg flag: KeyFlag + ) = apply { + + } + + fun noUserId( + preferences: Preferences + ): PGPSecretKeyRing { + + } + + fun userId( + userId: CharSequence, + preferences: Preferences + ): WithUserIds = WithUserIds().apply { + userId(userId, preferences) + } + } + + class WithUserIds { + fun userId( + userId: CharSequence, + preferences: Preferences + ): WithUserIds { + + } + + fun done(): PGPSecretKeyRing { + + } + + fun directKeySignature( + preferences: Preferences + ): PGPSecretKeyRing { + + } + } + + data class KeyDescription( + val type: KeyType, + val creationTime: Date, + val flags: List + ) + + data class Preferences() + +} diff --git a/pgpainless-core/src/test/kotlin/org/pgpainless/key/generation/OpenPgpV4KeyGeneratorTest.kt b/pgpainless-core/src/test/kotlin/org/pgpainless/key/generation/OpenPgpV4KeyGeneratorTest.kt new file mode 100644 index 00000000..b201d54e --- /dev/null +++ b/pgpainless-core/src/test/kotlin/org/pgpainless/key/generation/OpenPgpV4KeyGeneratorTest.kt @@ -0,0 +1,26 @@ +package org.pgpainless.key.generation + +import org.junit.jupiter.api.Test +import org.pgpainless.algorithm.KeyFlag +import org.pgpainless.key.generation.type.KeyType +import org.pgpainless.key.generation.type.rsa.RsaLength +import org.pgpainless.policy.Policy + +class OpenPgpV4KeyGeneratorTest { + + @Test + fun test() { + + OpenPgpV4KeyGenerator(Policy.getInstance()) + + OpenPgpV4KeyGenerator(Policy.getInstance()) + .primaryKey( + KeyType.RSA(RsaLength._4096), + KeyFlag.CERTIFY_OTHER + ).signingSubkey( + KeyType.RSA(RsaLength._4096) + ).encryptionSubkey( + KeyType.RSA(RsaLength._4096) + ) + } +}