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-22 16:52:40 +01:00
parent 699a5eabfc
commit 3b335fa627
Signed by: vanitasvitae
GPG key ID: 62BEE9264BF17311
4 changed files with 395 additions and 324 deletions

View file

@ -0,0 +1,253 @@
// SPDX-FileCopyrightText: 2024 Paul Schaub <vanitasvitae@fsfe.org>
//
// 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<T : BaseV4KeyBuilder<T>>(
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<BaseV4PrimaryKeyBuilder>(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<BaseV4SubkeyBuilder>(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()
}
}

View file

@ -1,236 +1,156 @@
// SPDX-FileCopyrightText: 2024 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package org.pgpainless.key.generation package org.pgpainless.key.generation
import java.security.KeyPairGenerator
import java.util.* import java.util.*
import org.bouncycastle.bcpg.PublicSubkeyPacket import org.bouncycastle.openpgp.PGPSecretKey
import org.bouncycastle.openpgp.PGPKeyPair import org.bouncycastle.openpgp.PGPSecretKeyRing
import org.bouncycastle.openpgp.PGPPrivateKey
import org.bouncycastle.openpgp.PGPPublicKey
import org.bouncycastle.openpgp.PGPSignature
import org.bouncycastle.openpgp.PGPUserAttributeSubpacketVector import org.bouncycastle.openpgp.PGPUserAttributeSubpacketVector
import org.pgpainless.algorithm.CertificationType import org.bouncycastle.openpgp.operator.PBESecretKeyEncryptor
import org.pgpainless.algorithm.HashAlgorithm import org.pgpainless.algorithm.AlgorithmSuite
import org.pgpainless.algorithm.KeyFlag import org.pgpainless.algorithm.KeyFlag
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.protection.SecretKeyRingProtector
import org.pgpainless.policy.Policy 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 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( fun buildV4Key(
type: KeyType, keyType: KeyType,
creationTime: Date = Date(), ): V4OpenPgpKeyBuilder =
policy: Policy V4OpenPgpKeyBuilder(keyType, policy, referenceTime, keyGenerationPolicy)
): V4PrimaryKeyBuilder = V4PrimaryKeyBuilder(type, creationTime, policy)
abstract class V4KeyBuilder<T : V4KeyBuilder<T>>( class V4OpenPgpKeyBuilder(
val type: KeyType, keyType: 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<V4PrimaryKeyBuilder>(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,
policy: Policy, policy: Policy,
private val primaryKeyBuilder: V4PrimaryKeyBuilder referenceTime: Date,
) : V4KeyBuilder<V4SubkeyBuilder>(type, creationTime, policy = policy) { keyGenerationPolicy: AlgorithmSuite
) : OpenPgpKeyBuilder(policy, referenceTime, keyGenerationPolicy) {
fun bindingSignature( private val primaryKey =
bindingTime: Date = creationTime, BaseOpenPgpKeyBuilder.BaseV4PrimaryKeyBuilder(keyType, referenceTime, policy)
hashAlgorithm: HashAlgorithm =
policy.certificationSignatureHashAlgorithmPolicy.defaultHashAlgorithm, private val subkeys = mutableListOf<BaseOpenPgpKeyBuilder.BaseV4SubkeyBuilder>()
fun addUserId(
userId: CharSequence,
algorithmSuite: AlgorithmSuite = keyGenerationPolicy,
subpacketsCallback: SelfSignatureSubpackets.Callback = subpacketsCallback: SelfSignatureSubpackets.Callback =
SelfSignatureSubpackets.defaultCallback() 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<KeyFlag>?
) =
addSubkey(
BaseOpenPgpKeyBuilder.BaseV4SubkeyBuilder(
keyType, creationTime, policy, primaryKey),
bindingTime,
keyFlags)
fun addSubkey(
subkeyBuilder: BaseOpenPgpKeyBuilder.BaseV4SubkeyBuilder,
bindingTime: Date = subkeyBuilder.creationTime,
keyFlags: List<KeyFlag>?
) = apply { ) = apply {
val sig = buildBindingSignature(bindingTime, hashAlgorithm, subpacketsCallback) subkeys.add(
key = PGPKeyPair(PGPPublicKey.addCertification(key.publicKey, sig), key.privateKey) 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( fun addEncryptionSubkey(
bindingTime: Date = creationTime, keyType: KeyType,
hashAlgorithm: HashAlgorithm = creationTime: Date = referenceTime,
policy.certificationSignatureHashAlgorithmPolicy.defaultHashAlgorithm, bindingTime: Date = creationTime
subpacketsCallback: SelfSignatureSubpackets.Callback = ) =
SelfSignatureSubpackets.defaultCallback() addSubkey(
): PGPSignature { keyType,
val builder = creationTime,
SubkeyBindingSignatureBuilder( bindingTime,
primaryKeyBuilder.key.privateKey, listOf(KeyFlag.ENCRYPT_STORAGE, KeyFlag.ENCRYPT_COMMS))
primaryKeyBuilder.key.publicKey,
hashAlgorithm)
builder.hashedSubpackets.setSignatureCreationTime(bindingTime) fun addSigningSubkey(
builder.applyCallback(subpacketsCallback) 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) && fun build(
builder.hashedSubpackets.getEmbeddedSignaturePackets().isEmpty()) { protector: SecretKeyRingProtector = SecretKeyRingProtector.unprotectedKeys()
): PGPSecretKeyRing {
// Create back-sig return PGPSecretKeyRing(
val backSigBuilder = mutableListOf(
PrimaryKeyBindingSignatureBuilder(key.privateKey, key.publicKey, hashAlgorithm) PGPSecretKey(
primaryKey.key.privateKey,
backSigBuilder.hashedSubpackets.setSignatureCreationTime(bindingTime) primaryKey.key.publicKey,
ImplementationFactory.getInstance().v4FingerprintCalculator,
val backSig = backSigBuilder.build(primaryKey().key.publicKey) true,
builder.hashedSubpackets.addEmbeddedSignature(backSig) protector.getEncryptor(primaryKey.key.keyID)))
.plus(
subkeys.map {
PGPSecretKey(
it.key.privateKey,
it.key.publicKey,
ImplementationFactory.getInstance().v4FingerprintCalculator,
false,
protector.getEncryptor(it.key.keyID))
}))
} }
return builder.build(key.publicKey) 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)
}
}
} }
override fun adjustKeyPacket(keyPair: PGPKeyPair): PGPKeyPair { private fun toSecretKey(
val fpCalc = ImplementationFactory.getInstance().keyFingerprintCalculator key: BaseOpenPgpKeyBuilder.BaseV4KeyBuilder<*>,
val pubkey = keyPair.publicKey isPrimaryKey: Boolean,
val privkey = keyPair.privateKey encryptor: PBESecretKeyEncryptor?
// form subkey packet ): PGPSecretKey {
val subkey = return PGPSecretKey(
PublicSubkeyPacket( key.key.privateKey,
pubkey.algorithm, pubkey.creationTime, pubkey.publicKeyPacket.key) key.key.publicKey,
return PGPKeyPair( ImplementationFactory.getInstance().v4FingerprintCalculator,
PGPPublicKey(subkey, fpCalc), isPrimaryKey,
PGPPrivateKey(pubkey.keyID, subkey, privkey.privateKeyDataPacket)) encryptor)
} }
override fun primaryKey() = primaryKeyBuilder.primaryKey()
} }
} }

View file

@ -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<OpenPgpKeyBuilder.V4SubkeyBuilder>()
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))
}))
}
}

View file

@ -11,22 +11,29 @@ import org.pgpainless.key.protection.SecretKeyRingProtector
import org.pgpainless.policy.Policy import org.pgpainless.policy.Policy
import org.pgpainless.util.DateUtil import org.pgpainless.util.DateUtil
class OpenPgpV4KeyGeneratorTest { class OpenPgpKeyBuilderTest {
@Test @Test
fun test() { fun test() {
val date = DateUtil.parseUTCDate("2020-04-01 10:00:00 UTC") val date = DateUtil.parseUTCDate("2020-04-01 10:00:00 UTC")
val key = val key = OpenPgpKeyBuilder(Policy.getInstance(), date)
OpenPgpV4KeyGenerator( .buildV4Key(KeyType.EDDSA(EdDSACurve._Ed25519))
KeyType.EDDSA(EdDSACurve._Ed25519), Policy.getInstance(), referenceTime = date)
.addUserId("Alice") .addUserId("Alice")
.addUserAttribute( .addUserAttribute(
PGPUserAttributeSubpacketVectorGenerator().apply { PGPUserAttributeSubpacketVectorGenerator()
setImageAttribute(ImageAttribute.JPEG, byteArrayOf()) .apply { setImageAttribute(ImageAttribute.JPEG, byteArrayOf()) }
}.generate()) .generate())
.addEncryptionSubkey(KeyType.XDH(XDHSpec._X25519)) .addEncryptionSubkey(KeyType.XDH(XDHSpec._X25519))
.addSigningSubkey(KeyType.EDDSA(EdDSACurve._Ed25519)) .addSigningSubkey(KeyType.EDDSA(EdDSACurve._Ed25519))
.build(SecretKeyRingProtector.unprotectedKeys()) .build(SecretKeyRingProtector.unprotectedKeys())
println(PGPainless.asciiArmor(key)) println(PGPainless.asciiArmor(key))
} }
@Test
fun minimal() {
val key = OpenPgpKeyBuilder(Policy.getInstance())
.buildV4Key(KeyType.EDDSA(EdDSACurve._Ed25519))
.build()
println(PGPainless.asciiArmor(key))
}
} }