2024-01-22 16:52:40 +01:00
|
|
|
// SPDX-FileCopyrightText: 2024 Paul Schaub <vanitasvitae@fsfe.org>
|
|
|
|
//
|
|
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
|
2024-01-06 01:31:12 +01:00
|
|
|
package org.pgpainless.key.generation
|
|
|
|
|
2024-01-11 16:44:21 +01:00
|
|
|
import java.util.*
|
2024-01-22 16:52:40 +01:00
|
|
|
import org.bouncycastle.openpgp.PGPSecretKey
|
|
|
|
import org.bouncycastle.openpgp.PGPSecretKeyRing
|
2024-01-11 16:44:21 +01:00
|
|
|
import org.bouncycastle.openpgp.PGPUserAttributeSubpacketVector
|
2024-01-22 16:52:40 +01:00
|
|
|
import org.bouncycastle.openpgp.operator.PBESecretKeyEncryptor
|
|
|
|
import org.pgpainless.algorithm.AlgorithmSuite
|
2024-01-11 16:44:21 +01:00
|
|
|
import org.pgpainless.algorithm.KeyFlag
|
2024-01-06 01:31:12 +01:00
|
|
|
import org.pgpainless.implementation.ImplementationFactory
|
|
|
|
import org.pgpainless.key.generation.type.KeyType
|
2024-01-22 16:52:40 +01:00
|
|
|
import org.pgpainless.key.protection.SecretKeyRingProtector
|
2024-01-11 16:44:21 +01:00
|
|
|
import org.pgpainless.policy.Policy
|
2024-01-08 13:51:16 +01:00
|
|
|
import org.pgpainless.signature.subpackets.SelfSignatureSubpackets
|
2024-01-06 01:31:12 +01:00
|
|
|
|
2024-01-22 16:52:40 +01:00
|
|
|
open class OpenPgpKeyBuilder(
|
|
|
|
protected val policy: Policy,
|
|
|
|
protected val referenceTime: Date = Date(),
|
|
|
|
protected val keyGenerationPolicy: AlgorithmSuite = policy.keyGenerationAlgorithmSuite
|
|
|
|
) {
|
2024-01-06 01:31:12 +01:00
|
|
|
|
|
|
|
fun buildV4Key(
|
2024-01-22 16:52:40 +01:00
|
|
|
keyType: KeyType,
|
|
|
|
): V4OpenPgpKeyBuilder =
|
|
|
|
V4OpenPgpKeyBuilder(keyType, policy, referenceTime, keyGenerationPolicy)
|
2024-01-08 13:51:16 +01:00
|
|
|
|
2024-01-22 16:52:40 +01:00
|
|
|
class V4OpenPgpKeyBuilder(
|
|
|
|
keyType: KeyType,
|
|
|
|
policy: Policy,
|
|
|
|
referenceTime: Date,
|
|
|
|
keyGenerationPolicy: AlgorithmSuite
|
|
|
|
) : OpenPgpKeyBuilder(policy, referenceTime, keyGenerationPolicy) {
|
2024-01-06 01:31:12 +01:00
|
|
|
|
2024-01-22 16:52:40 +01:00
|
|
|
private val primaryKey =
|
|
|
|
BaseOpenPgpKeyBuilder.BaseV4PrimaryKeyBuilder(keyType, referenceTime, policy)
|
2024-01-06 01:31:12 +01:00
|
|
|
|
2024-01-22 16:52:40 +01:00
|
|
|
private val subkeys = mutableListOf<BaseOpenPgpKeyBuilder.BaseV4SubkeyBuilder>()
|
2024-01-08 13:51:16 +01:00
|
|
|
|
2024-01-22 16:52:40 +01:00
|
|
|
fun addUserId(
|
2024-01-11 16:44:21 +01:00
|
|
|
userId: CharSequence,
|
2024-01-22 16:52:40 +01:00
|
|
|
algorithmSuite: AlgorithmSuite = keyGenerationPolicy,
|
2024-01-24 11:27:42 +01:00
|
|
|
subpacketsCallback: SelfSignatureSubpackets.Callback = SelfSignatureSubpackets.nop()
|
|
|
|
) = apply {
|
|
|
|
primaryKey.userId(userId, algorithmSuite, subpacketsCallback = subpacketsCallback)
|
|
|
|
}
|
2024-01-11 16:44:21 +01:00
|
|
|
|
2024-01-22 16:52:40 +01:00
|
|
|
fun addUserAttribute(
|
|
|
|
attribute: PGPUserAttributeSubpacketVector,
|
|
|
|
algorithmSuite: AlgorithmSuite = keyGenerationPolicy,
|
2024-01-24 11:27:42 +01:00
|
|
|
subpacketsCallback: SelfSignatureSubpackets.Callback = SelfSignatureSubpackets.nop()
|
|
|
|
) = apply {
|
|
|
|
primaryKey.userAttribute(
|
|
|
|
attribute, algorithmSuite, subpacketsCallback = subpacketsCallback)
|
|
|
|
}
|
2024-01-11 16:44:21 +01:00
|
|
|
|
2024-01-22 16:52:40 +01:00
|
|
|
fun addSubkey(
|
|
|
|
keyType: KeyType,
|
|
|
|
creationTime: Date = referenceTime,
|
2024-01-11 16:44:21 +01:00
|
|
|
bindingTime: Date = creationTime,
|
2024-01-22 16:52:40 +01:00
|
|
|
keyFlags: List<KeyFlag>?
|
|
|
|
) =
|
|
|
|
addSubkey(
|
|
|
|
BaseOpenPgpKeyBuilder.BaseV4SubkeyBuilder(
|
|
|
|
keyType, creationTime, policy, primaryKey),
|
|
|
|
bindingTime,
|
|
|
|
keyFlags)
|
|
|
|
|
|
|
|
fun addSubkey(
|
|
|
|
subkeyBuilder: BaseOpenPgpKeyBuilder.BaseV4SubkeyBuilder,
|
|
|
|
bindingTime: Date = subkeyBuilder.creationTime,
|
|
|
|
keyFlags: List<KeyFlag>?
|
2024-01-11 16:44:21 +01:00
|
|
|
) = apply {
|
2024-01-22 16:52:40 +01:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
2024-01-11 16:44:21 +01:00
|
|
|
}
|
|
|
|
|
2024-01-22 16:52:40 +01:00
|
|
|
fun addEncryptionSubkey(
|
|
|
|
keyType: KeyType,
|
|
|
|
creationTime: Date = referenceTime,
|
|
|
|
bindingTime: Date = creationTime
|
|
|
|
) =
|
|
|
|
addSubkey(
|
|
|
|
keyType,
|
|
|
|
creationTime,
|
|
|
|
bindingTime,
|
|
|
|
listOf(KeyFlag.ENCRYPT_STORAGE, KeyFlag.ENCRYPT_COMMS))
|
|
|
|
|
|
|
|
fun addSigningSubkey(
|
|
|
|
keyType: KeyType,
|
|
|
|
creationTime: Date = referenceTime,
|
|
|
|
bindingTime: Date = creationTime
|
|
|
|
) = addSubkey(keyType, creationTime, bindingTime, listOf(KeyFlag.SIGN_DATA))
|
|
|
|
|
|
|
|
fun build(
|
|
|
|
protector: SecretKeyRingProtector = SecretKeyRingProtector.unprotectedKeys()
|
|
|
|
): PGPSecretKeyRing {
|
2024-01-22 17:17:26 +01:00
|
|
|
|
|
|
|
// Add DK sig in case of no user-id
|
|
|
|
if (primaryKey.isWithoutUserIds()) {
|
2024-01-24 11:27:42 +01:00
|
|
|
primaryKey.directKeySignature(
|
|
|
|
subpacketsCallback = defaultPrimarySubpacketsCallback())
|
2024-01-22 17:17:26 +01:00
|
|
|
}
|
|
|
|
|
2024-01-22 16:52:40 +01:00
|
|
|
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))
|
|
|
|
}))
|
|
|
|
}
|
2024-01-11 16:44:21 +01:00
|
|
|
|
2024-01-22 16:52:40 +01:00
|
|
|
private fun defaultPrimarySubpacketsCallback(): SelfSignatureSubpackets.Callback =
|
|
|
|
object : SelfSignatureSubpackets.Callback {
|
|
|
|
override fun modifyHashedSubpackets(hashedSubpackets: SelfSignatureSubpackets) {
|
|
|
|
hashedSubpackets.apply {
|
|
|
|
setPreferredHashAlgorithms(keyGenerationPolicy.hashAlgorithms)
|
2024-01-24 11:27:42 +01:00
|
|
|
setPreferredSymmetricKeyAlgorithms(
|
|
|
|
keyGenerationPolicy.symmetricKeyAlgorithms)
|
2024-01-22 16:52:40 +01:00
|
|
|
setPreferredCompressionAlgorithms(keyGenerationPolicy.compressionAlgorithms)
|
|
|
|
setKeyFlags(KeyFlag.CERTIFY_OTHER)
|
|
|
|
}
|
|
|
|
}
|
2024-01-11 16:44:21 +01:00
|
|
|
}
|
|
|
|
|
2024-01-22 16:52:40 +01:00
|
|
|
private fun toSecretKey(
|
|
|
|
key: BaseOpenPgpKeyBuilder.BaseV4KeyBuilder<*>,
|
|
|
|
isPrimaryKey: Boolean,
|
|
|
|
encryptor: PBESecretKeyEncryptor?
|
|
|
|
): PGPSecretKey {
|
|
|
|
return PGPSecretKey(
|
|
|
|
key.key.privateKey,
|
|
|
|
key.key.publicKey,
|
|
|
|
ImplementationFactory.getInstance().v4FingerprintCalculator,
|
|
|
|
isPrimaryKey,
|
|
|
|
encryptor)
|
2024-01-08 13:51:16 +01:00
|
|
|
}
|
|
|
|
}
|
2024-01-06 01:31:12 +01:00
|
|
|
}
|