mirror of
https://github.com/pgpainless/pgpainless.git
synced 2024-12-25 12:27:58 +01:00
Progress
This commit is contained in:
parent
699a5eabfc
commit
3b335fa627
4 changed files with 395 additions and 324 deletions
|
@ -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()
|
||||||
|
}
|
||||||
|
}
|
|
@ -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()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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))
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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))
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Reference in a new issue