1
0
Fork 0
mirror of https://github.com/pgpainless/pgpainless.git synced 2024-11-05 03:55:58 +01:00
This commit is contained in:
Paul Schaub 2024-01-08 13:51:16 +01:00
parent 0e25ada166
commit 92550e35cc
Signed by: vanitasvitae
GPG key ID: 62BEE9264BF17311
6 changed files with 198 additions and 150 deletions

View file

@ -1,15 +1,22 @@
package org.pgpainless.key.generation package org.pgpainless.key.generation
import org.bouncycastle.bcpg.PublicSubkeyPacket
import org.bouncycastle.openpgp.PGPKeyPair import org.bouncycastle.openpgp.PGPKeyPair
import org.bouncycastle.openpgp.PGPSecretKeyRing import org.bouncycastle.openpgp.PGPPrivateKey
import org.bouncycastle.openpgp.PGPPublicKey
import org.pgpainless.algorithm.HashAlgorithm
import org.pgpainless.algorithm.SignatureType
import org.pgpainless.implementation.ImplementationFactory import org.pgpainless.implementation.ImplementationFactory
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
import org.pgpainless.key.generation.type.xdh.XDHSpec import org.pgpainless.key.generation.type.xdh.XDHSpec
import org.pgpainless.provider.ProviderFactory import org.pgpainless.provider.ProviderFactory
import org.pgpainless.signature.builder.SelfSignatureBuilder
import org.pgpainless.signature.builder.SubkeyBindingSignatureBuilder
import org.pgpainless.signature.subpackets.SelfSignatureSubpackets
import java.security.KeyPairGenerator import java.security.KeyPairGenerator
import java.util.Date import java.util.*
class OpenPgpKeyBuilder { class OpenPgpKeyBuilder {
@ -19,34 +26,19 @@ class OpenPgpKeyBuilder {
): V4PrimaryKeyBuilder = V4PrimaryKeyBuilder(type, creationTime) ): V4PrimaryKeyBuilder = V4PrimaryKeyBuilder(type, creationTime)
abstract class V4KeyBuilder<T: V4KeyBuilder<T>>( abstract class V4KeyBuilder<T: V4KeyBuilder<T>>(
protected val type: KeyType, val type: KeyType,
protected val creationTime: Date, val creationTime: Date,
val certificateCreationTime: Date = Date() val certificateCreationTime: Date = Date()
) { ) {
internal val keyPair = generateKeyPair() internal var key = generateKeyPair()
fun subkey( fun subkey(
type: KeyType, type: KeyType,
creationTime: Date = certificateCreationTime creationTime: Date = certificateCreationTime
): V4SubkeyBuilder = V4SubkeyBuilder(type, creationTime, this) ): V4SubkeyBuilder = V4SubkeyBuilder(type, creationTime, primaryKey())
fun generate(): PGPSecretKeyRing { internal abstract fun primaryKey(): V4PrimaryKeyBuilder
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<V4KeyBuilder<*>> =
if (this is V4SubkeyBuilder) {
predecessor.collectKeysForGeneration().plus(this)
} else {
listOf(this)
}
private fun generateKeyPair(): PGPKeyPair { private fun generateKeyPair(): PGPKeyPair {
// Create raw Key Pair // Create raw Key Pair
@ -57,43 +49,86 @@ class OpenPgpKeyBuilder {
// Form PGP Key Pair // Form PGP Key Pair
return ImplementationFactory.getInstance() return ImplementationFactory.getInstance()
.getPGPV4KeyPair(type.algorithm, keyPair, creationTime) .getPGPV4KeyPair(type.algorithm, keyPair, creationTime)
.let {
adjustKeyPacket(it)
} }
} }
protected abstract fun adjustKeyPacket(keyPair: PGPKeyPair): PGPKeyPair
}
class V4PrimaryKeyBuilder( class V4PrimaryKeyBuilder(
type: KeyType, type: KeyType,
creationTime: Date creationTime: Date
): V4KeyBuilder<V4PrimaryKeyBuilder>(type, creationTime) { ): V4KeyBuilder<V4PrimaryKeyBuilder>(type, creationTime) {
fun userId(userId: CharSequence) = userId(userId, OpenPgpV4KeyGenerator.Preferences()) fun userId(
userId: CharSequence,
fun userId(userId: CharSequence, preferences: OpenPgpV4KeyGenerator.Preferences) = apply { bindingTime: Date = creationTime,
keyPair.publicKey. hashAlgorithm: HashAlgorithm = HashAlgorithm.SHA512,
} subpacketsCallback: SelfSignatureSubpackets.Callback =
object : SelfSignatureSubpackets.Callback {
fun selfSignature(preferences: OpenPgpV4KeyGenerator.Preferences) = apply {
} }
) = apply {
val sig = SelfSignatureBuilder(
key.privateKey,
key.publicKey,
SignatureType.POSITIVE_CERTIFICATION,
hashAlgorithm)
.applyCallback(subpacketsCallback)
.build(userId)
key = PGPKeyPair(
PGPPublicKey.addCertification(key.publicKey, userId.toString(), sig),
key.privateKey
)
}
override fun adjustKeyPacket(keyPair: PGPKeyPair): PGPKeyPair {
return keyPair // is already a secret key packet
}
override fun primaryKey() = this
} }
class V4SubkeyBuilder( class V4SubkeyBuilder(
type: KeyType, type: KeyType,
creationTime: Date, creationTime: Date,
internal val predecessor: V4KeyBuilder<*>, private val primaryKeyBuilder: V4PrimaryKeyBuilder
): V4KeyBuilder<V4SubkeyBuilder>(type, creationTime, predecessor.certificateCreationTime) { ): V4KeyBuilder<V4SubkeyBuilder>(type, creationTime) {
fun bindingSignature(preferences: OpenPgpV4KeyGenerator.Preferences) = apply {
} fun bindingSignature(subpacketCallback: SelfSignatureSubpackets.Callback) = apply {
SubkeyBindingSignatureBuilder(primaryKeyBuilder.key.privateKey, primaryKeyBuilder.key.publicKey)
.applyCallback(subpacketCallback)
.build(key.publicKey)
.let {
key = PGPKeyPair(
PGPPublicKey.addCertification(key.publicKey, it),
key.privateKey)
} }
} }
fun test() { override fun adjustKeyPacket(keyPair: PGPKeyPair): PGPKeyPair {
OpenPgpKeyBuilder() val fpCalc = ImplementationFactory.getInstance().keyFingerprintCalculator
.buildV4Key(KeyType.RSA(RsaLength._4096)) val pubkey = keyPair.publicKey
.selfSignature(OpenPgpV4KeyGenerator.Preferences()) val privkey = keyPair.privateKey
.userId("Alice", OpenPgpV4KeyGenerator.Preferences()) // form subkey packet
.subkey(KeyType.EDDSA(EdDSACurve._Ed25519)) val subkey = PublicSubkeyPacket(pubkey.algorithm,
.bindingSignature(OpenPgpV4KeyGenerator.Preferences()) pubkey.creationTime, pubkey.publicKeyPacket.key)
.subkey(KeyType.XDH(XDHSpec._X25519)) return PGPKeyPair(
.bindingSignature(OpenPgpV4KeyGenerator.Preferences()) PGPPublicKey(subkey, fpCalc),
PGPPrivateKey(pubkey.keyID, subkey, privkey.privateKeyDataPacket)
)
}
override fun primaryKey() = primaryKeyBuilder.primaryKey()
fun bindingSignature(
bindingTime: Date = creationTime
): V4SubkeyBuilder = bindingSignature(object : SelfSignatureSubpackets.Callback {
override fun modifyHashedSubpackets(hashedSubpackets: SelfSignatureSubpackets) {
hashedSubpackets.setSignatureCreationTime(bindingTime)
}
})
}
} }

View file

@ -1,117 +1,79 @@
package org.pgpainless.key.generation package org.pgpainless.key.generation
import org.bouncycastle.openpgp.PGPSecretKey
import org.bouncycastle.openpgp.PGPSecretKeyRing import org.bouncycastle.openpgp.PGPSecretKeyRing
import org.pgpainless.algorithm.HashAlgorithm
import org.pgpainless.algorithm.KeyFlag import org.pgpainless.algorithm.KeyFlag
import org.pgpainless.implementation.ImplementationFactory
import org.pgpainless.key.generation.type.KeyType import org.pgpainless.key.generation.type.KeyType
import org.pgpainless.key.protection.SecretKeyRingProtector
import org.pgpainless.policy.Policy import org.pgpainless.policy.Policy
import org.pgpainless.signature.subpackets.SelfSignatureSubpackets
import java.util.* import java.util.*
class OpenPgpV4KeyGenerator( class OpenPgpV4KeyGenerator(
keyType: KeyType,
private val policy: Policy, private val policy: Policy,
private val referenceTime: Date = Date() private val referenceTime: Date = Date()
) { ) {
fun primaryKey( private val primaryKey = OpenPgpKeyBuilder.V4PrimaryKeyBuilder(keyType, referenceTime)
type: KeyType, private val subkeys = mutableListOf<OpenPgpKeyBuilder.V4SubkeyBuilder>()
vararg flag: KeyFlag = arrayOf(KeyFlag.CERTIFY_OTHER, KeyFlag.SIGN_DATA)
) = primaryKey(type, referenceTime, *flag)
fun primaryKey( fun addUserId(
type: KeyType, userId: CharSequence,
creationTime: Date, bindingTime: Date = referenceTime
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 { ) = apply {
primaryKey.userId(userId, bindingTime)
} }
fun noUserId( fun addSubkey(
preferences: Preferences keyType: KeyType,
): PGPSecretKeyRing { creationTime: Date = referenceTime,
bindingTime: Date = creationTime
) = addSubkey(OpenPgpKeyBuilder.V4SubkeyBuilder(keyType, creationTime, primaryKey), bindingTime)
fun addSubkey(
subkeyBuilder: OpenPgpKeyBuilder.V4SubkeyBuilder,
bindingTime: Date = subkeyBuilder.creationTime
) = apply {
subkeys.add(subkeyBuilder)
} }
fun userId( fun addEncryptionSubkey(
userId: CharSequence, keyType: KeyType,
preferences: Preferences creationTime: Date = referenceTime,
): WithUserIds = WithUserIds().apply { bindingTime: Date = creationTime
userId(userId, preferences) ) = addSubkey(OpenPgpKeyBuilder.V4SubkeyBuilder(keyType, creationTime, primaryKey)
.bindingSignature(object: SelfSignatureSubpackets.Callback {
override fun modifyHashedSubpackets(hashedSubpackets: SelfSignatureSubpackets) {
hashedSubpackets.setSignatureCreationTime(bindingTime)
hashedSubpackets.setKeyFlags(KeyFlag.ENCRYPT_STORAGE, KeyFlag.ENCRYPT_COMMS)
} }
} })
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<KeyFlag>
) )
data class Preferences() fun build(protector: SecretKeyRingProtector): PGPSecretKeyRing {
return PGPSecretKeyRing(
mutableListOf(
PGPSecretKey(
primaryKey.key.privateKey,
primaryKey.key.publicKey,
ImplementationFactory.getInstance().getPGPDigestCalculator(HashAlgorithm.SHA1),
true,
protector.getEncryptor(primaryKey.key.keyID)
)
).plus(
subkeys.map {
PGPSecretKey(
it.key.privateKey,
it.key.publicKey,
ImplementationFactory.getInstance().getPGPDigestCalculator(HashAlgorithm.SHA1),
false,
protector.getEncryptor(it.key.keyID)
)
}
)
)
}
} }

View file

@ -53,6 +53,20 @@ abstract class AbstractSignatureBuilder<B : AbstractSignatureBuilder<B>>(
hashedSubpackets, hashedSubpackets,
unhashedSubpackets) unhashedSubpackets)
@Throws(PGPException::class)
constructor(
privateSigningKey: PGPPrivateKey,
publicSigningKey: PGPPublicKey,
archetypeSignature: PGPSignature
) : this(
privateSigningKey,
publicSigningKey,
negotiateHashAlgorithm(publicSigningKey),
SignatureType.requireFromCode(archetypeSignature.signatureType),
SignatureSubpackets.refreshHashedSubpackets(publicSigningKey, archetypeSignature),
SignatureSubpackets.refreshUnhashedSubpackets(archetypeSignature)
)
@Throws(PGPException::class) @Throws(PGPException::class)
constructor( constructor(
signatureType: SignatureType, signatureType: SignatureType,

View file

@ -4,14 +4,18 @@
package org.pgpainless.signature.builder package org.pgpainless.signature.builder
import java.util.function.Predicate
import org.bouncycastle.openpgp.PGPException import org.bouncycastle.openpgp.PGPException
import org.bouncycastle.openpgp.PGPPrivateKey
import org.bouncycastle.openpgp.PGPPublicKey
import org.bouncycastle.openpgp.PGPSecretKey import org.bouncycastle.openpgp.PGPSecretKey
import org.bouncycastle.openpgp.PGPSignature import org.bouncycastle.openpgp.PGPSignature
import org.bouncycastle.openpgp.PGPUserAttributeSubpacketVector import org.bouncycastle.openpgp.PGPUserAttributeSubpacketVector
import org.pgpainless.algorithm.HashAlgorithm
import org.pgpainless.algorithm.SignatureType import org.pgpainless.algorithm.SignatureType
import org.pgpainless.key.protection.SecretKeyRingProtector import org.pgpainless.key.protection.SecretKeyRingProtector
import org.pgpainless.signature.subpackets.SelfSignatureSubpackets import org.pgpainless.signature.subpackets.SelfSignatureSubpackets
import org.pgpainless.signature.subpackets.SignatureSubpackets
import java.util.function.Predicate
/** /**
* [AbstractSignatureBuilder] devoted to all types of self-certifications. Self-certifications are * [AbstractSignatureBuilder] devoted to all types of self-certifications. Self-certifications are
@ -49,6 +53,28 @@ class SelfSignatureBuilder : AbstractSignatureBuilder<SelfSignatureBuilder> {
oldCertification: PGPSignature oldCertification: PGPSignature
) : super(primaryKey, primaryKeyProtector, oldCertification) ) : super(primaryKey, primaryKeyProtector, oldCertification)
@Throws(PGPException::class)
constructor(
privatePrimaryKey: PGPPrivateKey,
publicPrimaryKey: PGPPublicKey,
oldCertification: PGPSignature
) : super(privatePrimaryKey, publicPrimaryKey, oldCertification)
@Throws(PGPException::class)
constructor(
privatePrimaryKey: PGPPrivateKey,
publicPrimaryKey: PGPPublicKey,
signatureType: SignatureType = SignatureType.POSITIVE_CERTIFICATION,
hashAlgorithm: HashAlgorithm,
) : super(
privatePrimaryKey,
publicPrimaryKey,
hashAlgorithm,
signatureType,
SignatureSubpackets.createHashedSubpackets(publicPrimaryKey),
SignatureSubpackets.createEmptySubpackets()
)
val hashedSubpackets: SelfSignatureSubpackets = _hashedSubpackets val hashedSubpackets: SelfSignatureSubpackets = _hashedSubpackets
val unhashedSubpackets: SelfSignatureSubpackets = _unhashedSubpackets val unhashedSubpackets: SelfSignatureSubpackets = _unhashedSubpackets

View file

@ -6,6 +6,7 @@ package org.pgpainless.signature.builder
import java.util.function.Predicate import java.util.function.Predicate
import org.bouncycastle.openpgp.PGPException import org.bouncycastle.openpgp.PGPException
import org.bouncycastle.openpgp.PGPPrivateKey
import org.bouncycastle.openpgp.PGPPublicKey import org.bouncycastle.openpgp.PGPPublicKey
import org.bouncycastle.openpgp.PGPSecretKey import org.bouncycastle.openpgp.PGPSecretKey
import org.bouncycastle.openpgp.PGPSignature import org.bouncycastle.openpgp.PGPSignature
@ -24,6 +25,18 @@ class SubkeyBindingSignatureBuilder : AbstractSignatureBuilder<SubkeyBindingSign
override val signatureTypePredicate: Predicate<SignatureType> override val signatureTypePredicate: Predicate<SignatureType>
get() = Predicate<SignatureType> { it == SignatureType.SUBKEY_BINDING } get() = Predicate<SignatureType> { it == SignatureType.SUBKEY_BINDING }
@Throws(PGPException::class)
constructor(
signingKey: PGPPrivateKey,
publicSigningKey: PGPPublicKey,
) : super(signingKey,
publicSigningKey,
negotiateHashAlgorithm(publicSigningKey),
SignatureType.SUBKEY_BINDING,
SignatureSubpackets.createHashedSubpackets(publicSigningKey),
SignatureSubpackets.createEmptySubpackets()
)
@Throws(PGPException::class) @Throws(PGPException::class)
constructor( constructor(
signingKey: PGPSecretKey, signingKey: PGPSecretKey,

View file

@ -1,26 +1,24 @@
package org.pgpainless.key.generation package org.pgpainless.key.generation
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
import org.pgpainless.algorithm.KeyFlag import org.pgpainless.PGPainless
import org.pgpainless.key.generation.type.KeyType import org.pgpainless.key.generation.type.KeyType
import org.pgpainless.key.generation.type.ecc.EllipticCurve
import org.pgpainless.key.generation.type.eddsa.EdDSACurve
import org.pgpainless.key.generation.type.rsa.RsaLength 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.policy.Policy
class OpenPgpV4KeyGeneratorTest { class OpenPgpV4KeyGeneratorTest {
@Test @Test
fun test() { fun test() {
println(PGPainless.asciiArmor(
OpenPgpV4KeyGenerator(Policy.getInstance()) OpenPgpV4KeyGenerator(KeyType.EDDSA(EdDSACurve._Ed25519), Policy.getInstance())
.addUserId("Alice")
OpenPgpV4KeyGenerator(Policy.getInstance()) .addEncryptionSubkey(KeyType.XDH(XDHSpec._X25519))
.primaryKey( .build(SecretKeyRingProtector.unprotectedKeys())
KeyType.RSA(RsaLength._4096), ))
KeyFlag.CERTIFY_OTHER
).signingSubkey(
KeyType.RSA(RsaLength._4096)
).encryptionSubkey(
KeyType.RSA(RsaLength._4096)
)
} }
} }