2024-02-12 14:43:14 +01:00
|
|
|
package org.pgpainless.key.generation
|
|
|
|
|
2024-02-13 13:28:01 +01:00
|
|
|
import org.bouncycastle.bcpg.attr.ImageAttribute
|
2024-02-12 17:44:44 +01:00
|
|
|
import java.security.KeyPair
|
|
|
|
import java.security.KeyPairGenerator
|
|
|
|
import java.util.Date
|
2024-02-12 14:43:14 +01:00
|
|
|
import org.bouncycastle.openpgp.PGPKeyPair
|
|
|
|
import org.bouncycastle.openpgp.PGPPublicKey
|
|
|
|
import org.bouncycastle.openpgp.PGPSecretKey
|
|
|
|
import org.bouncycastle.openpgp.PGPSecretKeyRing
|
|
|
|
import org.bouncycastle.openpgp.PGPSignature
|
|
|
|
import org.bouncycastle.openpgp.PGPUserAttributeSubpacketVector
|
2024-02-13 13:28:01 +01:00
|
|
|
import org.bouncycastle.openpgp.PGPUserAttributeSubpacketVectorGenerator
|
|
|
|
import org.bouncycastle.util.io.Streams
|
2024-02-12 14:43:14 +01:00
|
|
|
import org.pgpainless.PGPainless
|
|
|
|
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.key.generation.type.eddsa.EdDSACurve
|
2024-02-12 17:44:44 +01:00
|
|
|
import org.pgpainless.key.generation.type.rsa.RsaLength
|
2024-02-12 14:43:14 +01:00
|
|
|
import org.pgpainless.key.generation.type.xdh.XDHSpec
|
|
|
|
import org.pgpainless.policy.Policy
|
|
|
|
import org.pgpainless.provider.ProviderFactory
|
|
|
|
import org.pgpainless.signature.builder.DirectKeySelfSignatureBuilder
|
|
|
|
import org.pgpainless.signature.builder.SelfSignatureBuilder
|
|
|
|
import org.pgpainless.signature.builder.SubkeyBindingSignatureBuilder
|
|
|
|
import org.pgpainless.signature.subpackets.SelfSignatureSubpackets
|
2024-02-13 13:28:01 +01:00
|
|
|
import java.io.InputStream
|
2024-02-12 14:43:14 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Build a version 4 OpenPGP secret key.
|
|
|
|
*
|
|
|
|
* @param policy policy to ensure algorithm compliance and to determine default algorithms
|
|
|
|
* @param creationTime creation time for the secret key
|
|
|
|
*/
|
|
|
|
fun buildV4(
|
|
|
|
policy: Policy = PGPainless.getPolicy(),
|
|
|
|
creationTime: Date = Date(),
|
|
|
|
preferences: AlgorithmSuite = policy.keyGenerationAlgorithmSuite
|
|
|
|
): OpinionatedDefinePrimaryKey.V4 {
|
|
|
|
return OpinionatedDefinePrimaryKey.V4(policy, creationTime, preferences)
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Build a version 6 OpenPGP secret key.
|
|
|
|
*
|
|
|
|
* @param policy policy to ensure algorithm compliance and to determine default algorithms
|
|
|
|
* @param creationTime creation time for the secret key
|
|
|
|
*/
|
|
|
|
fun buildV6(
|
|
|
|
policy: Policy = PGPainless.getPolicy(),
|
|
|
|
creationTime: Date = Date(),
|
|
|
|
preferences: AlgorithmSuite = policy.keyGenerationAlgorithmSuite
|
|
|
|
): OpinionatedDefinePrimaryKey.V6 {
|
|
|
|
return OpinionatedDefinePrimaryKey.V6(policy, creationTime, preferences)
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Builder that allows the user to define the primary key of the OpenPGP key.
|
|
|
|
*
|
|
|
|
* @param policy algorithm policy
|
|
|
|
* @param creationTime default value for the creation time of the primary key.
|
|
|
|
*/
|
|
|
|
abstract class DefinePrimaryKey<B : DefineSubkeys<B>>(
|
|
|
|
val policy: Policy,
|
|
|
|
val creationTime: Date,
|
|
|
|
) {
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Define the primary key of the OpenPGP key.
|
|
|
|
*
|
|
|
|
* @param type primary key type
|
2024-02-12 17:44:44 +01:00
|
|
|
* @param creationTime creation time of the primary key. Defaults to the [DefinePrimaryKey]'s
|
|
|
|
* [creationTime].
|
|
|
|
* @param applyToPrimaryKey function that gets applied to the primary key. Is used to add
|
|
|
|
* binding signatures, UserIDs and user-attributes on the primary key.
|
2024-02-12 14:43:14 +01:00
|
|
|
* @return next step key builder
|
|
|
|
*/
|
|
|
|
abstract fun setPrimaryKey(
|
|
|
|
type: KeyType,
|
|
|
|
creationTime: Date = this.creationTime,
|
|
|
|
applyToPrimaryKey: (ApplyToPrimaryKey.() -> PGPKeyPair)? = null // default: do nothing
|
|
|
|
): B
|
2024-02-12 17:44:44 +01:00
|
|
|
|
|
|
|
abstract fun preferencesSubpackets(): SelfSignatureSubpackets.Callback
|
2024-02-12 14:43:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2024-02-12 17:44:44 +01:00
|
|
|
* Opinionated implementation of [DefinePrimaryKey]. Contrary to an unopinionated implementation, an
|
|
|
|
* opinionated [DefinePrimaryKey] will sanity check user-provided parameters and make sure, required
|
|
|
|
* signatures are placed on the key etc.
|
2024-02-12 14:43:14 +01:00
|
|
|
*
|
2024-02-12 17:44:44 +01:00
|
|
|
* @param policy policy to sanity check algorithms, key strengths etc. and to determine fallback
|
|
|
|
* algorithms with
|
2024-02-12 14:43:14 +01:00
|
|
|
* @param creationTime creation time of the primary key
|
|
|
|
* @param unopinionated unopinionated implementation
|
|
|
|
* @param B opinionated builder type
|
|
|
|
* @param U unopinionated builder type
|
|
|
|
*/
|
2024-02-12 17:44:44 +01:00
|
|
|
abstract class OpinionatedDefinePrimaryKey<
|
|
|
|
B : OpinionatedDefineSubkeys, U : UnopinionatedDefineSubkeys>(
|
2024-02-12 14:43:14 +01:00
|
|
|
policy: Policy,
|
|
|
|
creationTime: Date,
|
2024-02-12 17:44:44 +01:00
|
|
|
val preferences: AlgorithmSuite,
|
2024-02-12 14:43:14 +01:00
|
|
|
protected val unopinionated: UnopinionatedDefinePrimaryKey<U>
|
|
|
|
) : DefinePrimaryKey<OpinionatedDefineSubkeys>(policy, creationTime) {
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Turn this builder into an unopinionated one by returning the underlying unopinionated
|
|
|
|
* implementation.
|
|
|
|
*
|
|
|
|
* @return unopinionated implementation
|
|
|
|
*/
|
|
|
|
abstract fun unopinionated(): UnopinionatedDefinePrimaryKey<U>
|
|
|
|
|
2024-02-12 17:44:44 +01:00
|
|
|
override fun preferencesSubpackets(): SelfSignatureSubpackets.Callback =
|
|
|
|
SelfSignatureSubpackets.applyHashed {
|
|
|
|
setSignatureCreationTime(creationTime)
|
|
|
|
setPreferredHashAlgorithms(preferences.hashAlgorithms)
|
|
|
|
setPreferredSymmetricKeyAlgorithms(preferences.symmetricKeyAlgorithms)
|
|
|
|
setPreferredCompressionAlgorithms(preferences.compressionAlgorithms)
|
|
|
|
setFeatures(preferences.features)
|
|
|
|
}
|
|
|
|
|
|
|
|
fun setCertificationKey(
|
|
|
|
type: KeyType,
|
|
|
|
creationTime: Date = this.creationTime,
|
|
|
|
applyToPrimaryKey: (ApplyToPrimaryKey.() -> PGPKeyPair)? = { keyPair }
|
|
|
|
): B {
|
|
|
|
return setPrimaryKey(type, creationTime) {
|
|
|
|
addDirectKeySignature(
|
|
|
|
preferencesSubpackets()
|
|
|
|
.then(
|
|
|
|
SelfSignatureSubpackets.applyHashed { setKeyFlags(KeyFlag.CERTIFY_OTHER) }))
|
|
|
|
then(applyToPrimaryKey)
|
|
|
|
}
|
|
|
|
as B
|
|
|
|
}
|
|
|
|
|
2024-02-12 14:43:14 +01:00
|
|
|
/**
|
|
|
|
* Implementation of an [OpinionatedDefinePrimaryKey] for OpenPGP v4 keys.
|
|
|
|
*
|
|
|
|
* @param policy policy for algorithm compliance and fallbacks
|
|
|
|
* @param creationTime creation time of the primary key
|
|
|
|
*/
|
2024-02-12 17:44:44 +01:00
|
|
|
class V4(policy: Policy, creationTime: Date, preferences: AlgorithmSuite) :
|
|
|
|
OpinionatedDefinePrimaryKey<OpinionatedDefineSubkeys.V4, UnopinionatedDefineSubkeys.V4>(
|
|
|
|
policy,
|
|
|
|
creationTime,
|
|
|
|
preferences,
|
|
|
|
UnopinionatedDefinePrimaryKey.V4(policy, creationTime)) {
|
2024-02-12 14:43:14 +01:00
|
|
|
|
|
|
|
override fun unopinionated(): UnopinionatedDefinePrimaryKey.V4 =
|
|
|
|
unopinionated as UnopinionatedDefinePrimaryKey.V4
|
|
|
|
|
|
|
|
override fun setPrimaryKey(
|
|
|
|
type: KeyType,
|
|
|
|
creationTime: Date,
|
|
|
|
applyToPrimaryKey: (ApplyToPrimaryKey.() -> PGPKeyPair)?
|
|
|
|
): OpinionatedDefineSubkeys.V4 {
|
|
|
|
|
2024-02-13 13:28:01 +01:00
|
|
|
require(policy.publicKeyAlgorithmPolicy.isAcceptable(type.algorithm, type.bitStrength)) {
|
|
|
|
"Public Key algorithm ${type.algorithm} with ${type.bitStrength} is too weak" +
|
|
|
|
" for the current public key algorithm policy."
|
|
|
|
}
|
|
|
|
|
2024-02-12 17:44:44 +01:00
|
|
|
val applier = applyToPrimaryKey ?: { addDirectKeySignature(preferencesSubpackets()) }
|
2024-02-12 14:43:14 +01:00
|
|
|
|
2024-02-12 17:44:44 +01:00
|
|
|
val unopinionatedSubkeys = unopinionated().setPrimaryKey(type, creationTime, applier)
|
2024-02-12 14:43:14 +01:00
|
|
|
return OpinionatedDefineSubkeys.V4(
|
|
|
|
unopinionatedSubkeys.primaryKey, policy, creationTime, unopinionatedSubkeys)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Implementation of an [OpinionatedDefinePrimaryKey] for OpenPGP v6 keys.
|
|
|
|
*
|
|
|
|
* @param policy policy for algorithm compliance and fallbacks
|
|
|
|
* @param creationTime creation time of the primary key
|
|
|
|
*/
|
2024-02-12 17:44:44 +01:00
|
|
|
class V6(policy: Policy, creationTime: Date, preferences: AlgorithmSuite) :
|
|
|
|
OpinionatedDefinePrimaryKey<OpinionatedDefineSubkeys.V6, UnopinionatedDefineSubkeys.V6>(
|
|
|
|
policy,
|
|
|
|
creationTime,
|
|
|
|
preferences,
|
|
|
|
UnopinionatedDefinePrimaryKey.V6(policy, creationTime)) {
|
2024-02-12 14:43:14 +01:00
|
|
|
|
|
|
|
override fun unopinionated(): UnopinionatedDefinePrimaryKey.V6 =
|
|
|
|
unopinionated as UnopinionatedDefinePrimaryKey.V6
|
|
|
|
|
|
|
|
override fun setPrimaryKey(
|
|
|
|
type: KeyType,
|
|
|
|
creationTime: Date,
|
|
|
|
applyToPrimaryKey: (ApplyToPrimaryKey.() -> PGPKeyPair)?
|
|
|
|
): OpinionatedDefineSubkeys.V6 {
|
2024-02-12 17:44:44 +01:00
|
|
|
val applier = applyToPrimaryKey ?: { addDirectKeySignature(preferencesSubpackets()) }
|
2024-02-12 14:43:14 +01:00
|
|
|
return OpinionatedDefineSubkeys.V6(
|
|
|
|
policy,
|
|
|
|
creationTime,
|
2024-02-12 17:44:44 +01:00
|
|
|
unopinionated.setPrimaryKey(type, creationTime, applier)
|
|
|
|
as UnopinionatedDefineSubkeys.V6)
|
2024-02-12 14:43:14 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2024-02-12 17:44:44 +01:00
|
|
|
* Unopinionated implementation of [DefinePrimaryKey]. An unopinionated [DefinePrimaryKey] will not
|
|
|
|
* perform any sanity checks on user-provided algorithms.
|
2024-02-12 14:43:14 +01:00
|
|
|
*
|
|
|
|
* @param creationTime creation time of the primary key
|
|
|
|
* @param U unopinionated builder type
|
|
|
|
*/
|
|
|
|
abstract class UnopinionatedDefinePrimaryKey<U : UnopinionatedDefineSubkeys>(
|
|
|
|
policy: Policy,
|
|
|
|
creationTime: Date,
|
2024-02-12 17:44:44 +01:00
|
|
|
) : DefinePrimaryKey<UnopinionatedDefineSubkeys>(policy, creationTime) {
|
|
|
|
|
|
|
|
override fun preferencesSubpackets(): SelfSignatureSubpackets.Callback =
|
|
|
|
SelfSignatureSubpackets.nop()
|
2024-02-12 14:43:14 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Implementation of an [UnopinionatedDefinePrimaryKey] for OpenPGP v4 keys.
|
|
|
|
*
|
|
|
|
* @param creationTime creation time of the primary key
|
|
|
|
*/
|
2024-02-12 17:44:44 +01:00
|
|
|
class V4(policy: Policy, creationTime: Date) :
|
|
|
|
UnopinionatedDefinePrimaryKey<UnopinionatedDefineSubkeys.V4>(policy, creationTime) {
|
2024-02-12 14:43:14 +01:00
|
|
|
|
|
|
|
override fun setPrimaryKey(
|
|
|
|
type: KeyType,
|
|
|
|
creationTime: Date,
|
|
|
|
applyToPrimaryKey: (ApplyToPrimaryKey.() -> PGPKeyPair)?
|
|
|
|
): UnopinionatedDefineSubkeys.V4 {
|
|
|
|
var primaryKey = OpenPgpKeyPairGenerator.V4().generatePrimaryKey(type, creationTime)
|
|
|
|
if (applyToPrimaryKey != null) {
|
2024-02-12 17:44:44 +01:00
|
|
|
primaryKey = ApplyToPrimaryKey.V4(primaryKey, this).applyToPrimaryKey()
|
2024-02-12 14:43:14 +01:00
|
|
|
}
|
|
|
|
return UnopinionatedDefineSubkeys.V4(primaryKey, policy, creationTime)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Implementation of an [UnopinionatedDefinePrimaryKey] for OpenPGP v6 keys.
|
|
|
|
*
|
|
|
|
* @param creationTime creation time of the primary key
|
|
|
|
*/
|
2024-02-12 17:44:44 +01:00
|
|
|
class V6(policy: Policy, creationTime: Date) :
|
|
|
|
UnopinionatedDefinePrimaryKey<UnopinionatedDefineSubkeys.V6>(policy, creationTime) {
|
2024-02-12 14:43:14 +01:00
|
|
|
override fun setPrimaryKey(
|
|
|
|
type: KeyType,
|
|
|
|
creationTime: Date,
|
|
|
|
applyToPrimaryKey: (ApplyToPrimaryKey.() -> PGPKeyPair)?
|
|
|
|
): UnopinionatedDefineSubkeys.V6 {
|
|
|
|
return UnopinionatedDefineSubkeys.V6(policy, creationTime)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-02-12 17:44:44 +01:00
|
|
|
/** Interface for key builder that can */
|
|
|
|
abstract class DefineSubkeys<B : DefineSubkeys<B>>(val policy: Policy, val creationTime: Date) {
|
2024-02-12 14:43:14 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Add a subkey to the OpenPGP key.
|
|
|
|
*
|
|
|
|
* @param type subkey type
|
|
|
|
* @param creationTime creation time of the subkey
|
|
|
|
* @param function function to apply to the subkey. Used to add binding signatures.
|
|
|
|
* @return this
|
|
|
|
*/
|
2024-02-12 17:44:44 +01:00
|
|
|
abstract fun addSubkey(
|
|
|
|
type: KeyType,
|
|
|
|
creationTime: Date = this.creationTime,
|
|
|
|
function: (ApplyToSubkey.() -> PGPKeyPair)? = null
|
|
|
|
): B
|
2024-02-12 14:43:14 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Finish the key generation and return the OpenPGP [PGPSecretKeyRing].
|
|
|
|
*
|
|
|
|
* @return finished [PGPSecretKeyRing]
|
|
|
|
*/
|
|
|
|
abstract fun build(): PGPSecretKeyRing
|
|
|
|
}
|
|
|
|
|
2024-02-12 17:44:44 +01:00
|
|
|
abstract class OpinionatedDefineSubkeys(policy: Policy, creationTime: Date) :
|
|
|
|
DefineSubkeys<OpinionatedDefineSubkeys>(policy, creationTime) {
|
2024-02-12 14:43:14 +01:00
|
|
|
|
|
|
|
abstract val unopinionated: UnopinionatedDefineSubkeys
|
|
|
|
|
|
|
|
override fun build(): PGPSecretKeyRing = unopinionated.build()
|
|
|
|
|
|
|
|
class V4(
|
|
|
|
primaryKey: PGPKeyPair,
|
|
|
|
policy: Policy,
|
|
|
|
creationTime: Date,
|
2024-02-12 17:44:44 +01:00
|
|
|
override val unopinionated: UnopinionatedDefineSubkeys.V4 =
|
|
|
|
UnopinionatedDefineSubkeys.V4(primaryKey, policy, creationTime)
|
2024-02-12 14:43:14 +01:00
|
|
|
) : OpinionatedDefineSubkeys(policy, creationTime) {
|
|
|
|
|
|
|
|
override fun addSubkey(
|
|
|
|
type: KeyType,
|
|
|
|
creationTime: Date,
|
|
|
|
applyToSubkey: (ApplyToSubkey.() -> PGPKeyPair)?
|
2024-02-12 17:44:44 +01:00
|
|
|
): V4 = apply { unopinionated.addSubkey(type, creationTime, applyToSubkey) }
|
|
|
|
|
|
|
|
fun addSigningSubkey(
|
|
|
|
type: KeyType,
|
|
|
|
creationTime: Date = this.creationTime,
|
|
|
|
applyToSubkey: (ApplyToSubkey.() -> PGPKeyPair)? = {
|
|
|
|
addBindingSignature(
|
|
|
|
SelfSignatureSubpackets.applyHashed {
|
|
|
|
setSignatureCreationTime(creationTime)
|
|
|
|
setKeyFlags(KeyFlag.SIGN_DATA)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
) = addSubkey(type, creationTime, applyToSubkey)
|
2024-02-12 14:43:14 +01:00
|
|
|
|
2024-02-12 17:44:44 +01:00
|
|
|
fun addEncryptionSubkey(
|
|
|
|
type: KeyType,
|
|
|
|
creationTime: Date = this.creationTime,
|
|
|
|
applyToSubkey: (ApplyToSubkey.() -> PGPKeyPair)? = {
|
|
|
|
addBindingSignature(
|
|
|
|
SelfSignatureSubpackets.applyHashed {
|
|
|
|
setSignatureCreationTime(creationTime)
|
|
|
|
setKeyFlags(KeyFlag.ENCRYPT_COMMS, KeyFlag.ENCRYPT_STORAGE)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
) = addSubkey(type, creationTime, applyToSubkey)
|
2024-02-12 14:43:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
class V6(
|
|
|
|
policy: Policy,
|
|
|
|
creationTime: Date,
|
2024-02-12 17:44:44 +01:00
|
|
|
override val unopinionated: UnopinionatedDefineSubkeys.V6 =
|
|
|
|
UnopinionatedDefineSubkeys.V6(policy, creationTime)
|
2024-02-12 14:43:14 +01:00
|
|
|
) : OpinionatedDefineSubkeys(policy, creationTime) {
|
|
|
|
|
|
|
|
override fun addSubkey(
|
|
|
|
type: KeyType,
|
|
|
|
creationTime: Date,
|
|
|
|
function: (ApplyToSubkey.() -> PGPKeyPair)?
|
2024-02-12 17:44:44 +01:00
|
|
|
): V6 = apply { unopinionated.addSubkey(type, creationTime, function) }
|
2024-02-12 14:43:14 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-02-12 17:44:44 +01:00
|
|
|
abstract class UnopinionatedDefineSubkeys(policy: Policy, creationTime: Date) :
|
|
|
|
DefineSubkeys<UnopinionatedDefineSubkeys>(policy, creationTime) {
|
2024-02-12 14:43:14 +01:00
|
|
|
|
2024-02-12 17:44:44 +01:00
|
|
|
class V4(val primaryKey: PGPKeyPair, policy: Policy, creationTime: Date) :
|
|
|
|
UnopinionatedDefineSubkeys(policy, creationTime) {
|
2024-02-12 14:43:14 +01:00
|
|
|
|
|
|
|
val subkeys: MutableList<PGPKeyPair> = mutableListOf()
|
|
|
|
|
|
|
|
override fun addSubkey(
|
|
|
|
type: KeyType,
|
|
|
|
creationTime: Date,
|
|
|
|
applyToSubkey: (ApplyToSubkey.() -> PGPKeyPair)?
|
|
|
|
): V4 = apply {
|
|
|
|
val subkey = OpenPgpKeyPairGenerator.V4().generateSubkey(type, creationTime)
|
2024-02-12 17:44:44 +01:00
|
|
|
subkeys.add(
|
|
|
|
if (applyToSubkey == null) {
|
|
|
|
subkey
|
|
|
|
} else {
|
|
|
|
ApplyToSubkey.V4(primaryKey, subkey, this).applyToSubkey()
|
|
|
|
})
|
2024-02-12 14:43:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
override fun build(): PGPSecretKeyRing {
|
2024-02-12 17:44:44 +01:00
|
|
|
val primary =
|
|
|
|
PGPSecretKey(
|
|
|
|
primaryKey.privateKey,
|
|
|
|
primaryKey.publicKey,
|
|
|
|
ImplementationFactory.getInstance().v4FingerprintCalculator,
|
|
|
|
true,
|
|
|
|
null)
|
|
|
|
return PGPSecretKeyRing(
|
|
|
|
buildList {
|
|
|
|
add(primary)
|
|
|
|
subkeys.forEach {
|
|
|
|
add(
|
|
|
|
PGPSecretKey(
|
|
|
|
it.privateKey,
|
|
|
|
it.publicKey,
|
|
|
|
ImplementationFactory.getInstance().v4FingerprintCalculator,
|
|
|
|
false,
|
|
|
|
null))
|
|
|
|
}
|
|
|
|
})
|
2024-02-12 14:43:14 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-02-12 17:44:44 +01:00
|
|
|
class V6(policy: Policy, creationTime: Date) :
|
|
|
|
UnopinionatedDefineSubkeys(policy, creationTime) {
|
2024-02-12 14:43:14 +01:00
|
|
|
|
|
|
|
override fun addSubkey(
|
|
|
|
type: KeyType,
|
|
|
|
creationTime: Date,
|
|
|
|
function: (ApplyToSubkey.() -> PGPKeyPair)?
|
2024-02-12 17:44:44 +01:00
|
|
|
): V6 =
|
|
|
|
apply {
|
|
|
|
// Add Key
|
|
|
|
}
|
2024-02-12 14:43:14 +01:00
|
|
|
|
|
|
|
override fun build(): PGPSecretKeyRing {
|
|
|
|
TODO("Not yet implemented")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-02-13 13:28:01 +01:00
|
|
|
/**
|
|
|
|
* Function that can be applied to the primary key.
|
|
|
|
*
|
|
|
|
* @param keyPair primary key pair
|
|
|
|
* @param builder builder instance that generated the primary key
|
|
|
|
*/
|
2024-02-12 14:43:14 +01:00
|
|
|
abstract class ApplyToPrimaryKey(var keyPair: PGPKeyPair, val builder: DefinePrimaryKey<*>) {
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Add a UserID to the primary key.
|
|
|
|
*
|
|
|
|
* @param userId UserID to be bound to the primary key
|
|
|
|
* @param subpacketsCallback callback to modify the binding signatures subpackets
|
2024-02-13 13:28:01 +01:00
|
|
|
* @param certificationType type of the certification signature. Defaults to [CertificationType.POSITIVE]
|
|
|
|
* @param hashAlgorithm hash algorithm to be used during signature calculation
|
|
|
|
* @param bindingTime creation time of the binding signature
|
|
|
|
*
|
|
|
|
* @return modified key pair
|
2024-02-12 14:43:14 +01:00
|
|
|
*/
|
|
|
|
abstract fun addUserId(
|
|
|
|
userId: CharSequence,
|
|
|
|
subpacketsCallback: SelfSignatureSubpackets.Callback = SelfSignatureSubpackets.nop(),
|
|
|
|
certificationType: CertificationType = CertificationType.POSITIVE,
|
2024-02-12 17:44:44 +01:00
|
|
|
hashAlgorithm: HashAlgorithm =
|
|
|
|
builder.policy.certificationSignatureHashAlgorithmPolicy.defaultHashAlgorithm,
|
|
|
|
bindingTime: Date = builder.creationTime
|
|
|
|
): PGPKeyPair
|
2024-02-12 14:43:14 +01:00
|
|
|
|
2024-02-13 13:28:01 +01:00
|
|
|
/**
|
|
|
|
* Add a UserAttribute to the primary key.
|
|
|
|
*
|
|
|
|
* @param userAttribute UserAttribute to be bound to the primary key
|
|
|
|
* @param subpacketsCallback callback to modify the binding signature subpackets
|
|
|
|
* @param certificationType type of the binding signature. Default to [CertificationType.POSITIVE]
|
|
|
|
* @param hashAlgorithm hash algorithm to be used during signature calculation
|
|
|
|
* @param bindingTime creation time of the binding signature
|
|
|
|
*
|
|
|
|
* @return modified key pair
|
|
|
|
*/
|
|
|
|
abstract fun addUserAttribute(
|
|
|
|
userAttribute: PGPUserAttributeSubpacketVector,
|
|
|
|
subpacketsCallback: SelfSignatureSubpackets.Callback = SelfSignatureSubpackets.nop(),
|
|
|
|
certificationType: CertificationType = CertificationType.POSITIVE,
|
|
|
|
hashAlgorithm: HashAlgorithm = builder.policy.certificationSignatureHashAlgorithmPolicy.defaultHashAlgorithm,
|
|
|
|
bindingTime: Date = builder.creationTime
|
|
|
|
): PGPKeyPair
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Add a JPEG image as UserAttribute to the primary key.
|
|
|
|
* This may for example be a profile picture of the key owner.
|
|
|
|
*
|
|
|
|
* @param jpegInputStream input stream containing the JPEG encoded image
|
|
|
|
* @param subpacketsCallback callback to modify the subpackets of the binding signature
|
|
|
|
* @param certificationType type of the binding signature. Defaults to [CertificationType.POSITIVE]
|
|
|
|
* @param hashAlgorithm hash algorithm to be used during signature calculation
|
|
|
|
* @param bindingTime creation time of the binding signature
|
|
|
|
*
|
|
|
|
* @return modified key pair
|
|
|
|
*/
|
|
|
|
fun addImageAttribute(
|
|
|
|
jpegInputStream: InputStream,
|
|
|
|
subpacketsCallback: SelfSignatureSubpackets.Callback = SelfSignatureSubpackets.nop(),
|
|
|
|
certificationType: CertificationType = CertificationType.POSITIVE,
|
|
|
|
hashAlgorithm: HashAlgorithm = builder.policy.certificationSignatureHashAlgorithmPolicy.defaultHashAlgorithm,
|
|
|
|
bindingTime: Date = builder.creationTime
|
|
|
|
): PGPKeyPair = addUserAttribute(
|
|
|
|
PGPUserAttributeSubpacketVectorGenerator().apply {
|
|
|
|
setImageAttribute(ImageAttribute.JPEG, Streams.readAll(jpegInputStream))
|
|
|
|
}.generate(),
|
|
|
|
subpacketsCallback,
|
|
|
|
certificationType,
|
|
|
|
hashAlgorithm,
|
|
|
|
bindingTime)
|
|
|
|
|
2024-02-12 14:43:14 +01:00
|
|
|
/**
|
2024-02-12 17:44:44 +01:00
|
|
|
* Add a DirectKeySignature to the primary key. Such a signature usually carries information
|
|
|
|
* that applies to the whole OpenPGP key, such as algorithm preferences etc.
|
2024-02-12 14:43:14 +01:00
|
|
|
*/
|
|
|
|
abstract fun addDirectKeySignature(
|
2024-02-12 17:44:44 +01:00
|
|
|
subpacketsCallback: SelfSignatureSubpackets.Callback = builder.preferencesSubpackets(),
|
|
|
|
hashAlgorithm: HashAlgorithm =
|
|
|
|
builder.policy.certificationSignatureHashAlgorithmPolicy.defaultHashAlgorithm,
|
2024-02-12 14:43:14 +01:00
|
|
|
bindingTime: Date = builder.creationTime
|
|
|
|
): PGPKeyPair
|
2024-02-12 17:44:44 +01:00
|
|
|
|
2024-02-13 13:28:01 +01:00
|
|
|
/**
|
|
|
|
* Schedule the execution of another [ApplyToPrimaryKey] function instance right after
|
|
|
|
* this one has been executed.
|
|
|
|
*
|
|
|
|
* @param other second instance
|
|
|
|
* @return modified key pair after this and [other] have been executed
|
|
|
|
*/
|
2024-02-12 17:44:44 +01:00
|
|
|
abstract fun then(other: (ApplyToPrimaryKey.() -> PGPKeyPair)?): PGPKeyPair
|
|
|
|
|
|
|
|
class V4(keyPair: PGPKeyPair, builder: DefinePrimaryKey<*>) :
|
|
|
|
ApplyToPrimaryKey(keyPair, builder) {
|
|
|
|
|
|
|
|
override fun addUserId(
|
|
|
|
userId: CharSequence,
|
|
|
|
subpacketsCallback: SelfSignatureSubpackets.Callback,
|
|
|
|
certificationType: CertificationType,
|
|
|
|
hashAlgorithm: HashAlgorithm,
|
|
|
|
bindingTime: Date
|
|
|
|
): PGPKeyPair {
|
|
|
|
val sig =
|
|
|
|
buildCertificationFor(
|
|
|
|
keyPair,
|
|
|
|
userId,
|
|
|
|
certificationType,
|
|
|
|
bindingTime,
|
|
|
|
hashAlgorithm,
|
|
|
|
subpacketsCallback)
|
|
|
|
|
|
|
|
keyPair =
|
|
|
|
PGPKeyPair(
|
|
|
|
PGPPublicKey.addCertification(keyPair.publicKey, userId.toString(), sig),
|
|
|
|
keyPair.privateKey)
|
|
|
|
return keyPair
|
|
|
|
}
|
|
|
|
|
2024-02-13 13:28:01 +01:00
|
|
|
override fun addUserAttribute(
|
|
|
|
userAttribute: PGPUserAttributeSubpacketVector,
|
|
|
|
subpacketsCallback: SelfSignatureSubpackets.Callback,
|
|
|
|
certificationType: CertificationType,
|
|
|
|
hashAlgorithm: HashAlgorithm,
|
|
|
|
bindingTime: Date
|
|
|
|
): PGPKeyPair {
|
|
|
|
val sig = buildCertificationFor(
|
|
|
|
keyPair,
|
|
|
|
userAttribute,
|
|
|
|
certificationType,
|
|
|
|
bindingTime,
|
|
|
|
hashAlgorithm,
|
|
|
|
subpacketsCallback)
|
|
|
|
|
|
|
|
keyPair = PGPKeyPair(
|
|
|
|
PGPPublicKey.addCertification(keyPair.publicKey, userAttribute, sig),
|
|
|
|
keyPair.privateKey)
|
|
|
|
|
|
|
|
return keyPair
|
|
|
|
}
|
|
|
|
|
2024-02-12 17:44:44 +01:00
|
|
|
override fun addDirectKeySignature(
|
|
|
|
subpacketsCallback: SelfSignatureSubpackets.Callback,
|
|
|
|
hashAlgorithm: HashAlgorithm,
|
|
|
|
bindingTime: Date
|
|
|
|
): PGPKeyPair {
|
|
|
|
val sig =
|
|
|
|
buildDirectKeySignature(
|
|
|
|
keyPair,
|
|
|
|
hashAlgorithm,
|
|
|
|
subpacketsCallback.then(
|
|
|
|
SelfSignatureSubpackets.applyHashed {
|
|
|
|
setSignatureCreationTime(bindingTime)
|
|
|
|
}))
|
|
|
|
keyPair =
|
|
|
|
PGPKeyPair(
|
|
|
|
PGPPublicKey.addCertification(keyPair.publicKey, sig), keyPair.privateKey)
|
|
|
|
return keyPair
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun then(other: (ApplyToPrimaryKey.() -> PGPKeyPair)?): PGPKeyPair {
|
|
|
|
if (other != null) {
|
|
|
|
keyPair = V4(keyPair, builder).other()
|
|
|
|
}
|
|
|
|
return keyPair
|
|
|
|
}
|
|
|
|
|
2024-02-13 13:28:01 +01:00
|
|
|
/**
|
|
|
|
* Build a certification signature that binds the given [userId] to the given
|
|
|
|
* primary key [pair].
|
|
|
|
*
|
|
|
|
* @param pair primary key pair
|
|
|
|
* @param userId UserID to be bound
|
|
|
|
* @param certificationType type of the binding signature
|
|
|
|
* @param bindingTime creation time of the binding signature
|
|
|
|
* @param hashAlgorithm hash algorithm to be used during signature calculation
|
|
|
|
* @param subpacketsCallback callback to modify the binding signatures subpackets
|
|
|
|
*
|
|
|
|
* @return binding signature
|
|
|
|
*/
|
2024-02-12 17:44:44 +01:00
|
|
|
fun buildCertificationFor(
|
|
|
|
pair: PGPKeyPair,
|
|
|
|
userId: CharSequence,
|
|
|
|
certificationType: CertificationType,
|
|
|
|
bindingTime: Date,
|
|
|
|
hashAlgorithm: HashAlgorithm,
|
|
|
|
subpacketsCallback: SelfSignatureSubpackets.Callback
|
|
|
|
): PGPSignature {
|
|
|
|
val builder =
|
|
|
|
SelfSignatureBuilder(
|
|
|
|
pair.privateKey, pair.publicKey, certificationType.signatureType, hashAlgorithm)
|
|
|
|
builder.hashedSubpackets.apply { setSignatureCreationTime(bindingTime) }
|
|
|
|
builder.applyCallback(subpacketsCallback)
|
|
|
|
return builder.build(userId)
|
|
|
|
}
|
|
|
|
|
2024-02-13 13:28:01 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Build a certification signature that binds the given [userAttribute] to the given
|
|
|
|
* primary key [pair].
|
|
|
|
*
|
|
|
|
* @param pair primary key pair
|
|
|
|
* @param userAttribute UserAttribute to be bound
|
|
|
|
* @param certificationType type of the binding signature
|
|
|
|
* @param bindingTime creation time of the binding signature
|
|
|
|
* @param hashAlgorithm hash algorithm to be used during signature calculation
|
|
|
|
* @param subpacketsCallback callback to modify the binding signatures subpackets
|
|
|
|
*
|
|
|
|
* @return binding signature
|
|
|
|
*/
|
2024-02-12 17:44:44 +01:00
|
|
|
fun buildCertificationFor(
|
|
|
|
pair: PGPKeyPair,
|
|
|
|
userAttribute: PGPUserAttributeSubpacketVector,
|
|
|
|
certificationType: CertificationType,
|
|
|
|
bindingTime: Date,
|
|
|
|
hashAlgorithm: HashAlgorithm,
|
|
|
|
subpacketsCallback: SelfSignatureSubpackets.Callback
|
|
|
|
): PGPSignature {
|
|
|
|
val builder =
|
|
|
|
SelfSignatureBuilder(
|
|
|
|
pair.privateKey, pair.publicKey, certificationType.signatureType, hashAlgorithm)
|
|
|
|
builder.hashedSubpackets.apply { setSignatureCreationTime(bindingTime) }
|
|
|
|
builder.applyCallback(subpacketsCallback)
|
|
|
|
return builder.build(userAttribute)
|
|
|
|
}
|
|
|
|
|
2024-02-13 13:28:01 +01:00
|
|
|
/**
|
|
|
|
* Build a DirectKey self signature over the primary key [pair].
|
|
|
|
*
|
|
|
|
* @param pair primary key pair
|
|
|
|
* @param hashAlgorithm hash algorithm to be used during signature calculation
|
|
|
|
* @param subpacketsCallback callback to modify the subpackets of the direct-key signature
|
|
|
|
*
|
|
|
|
* @return direct-key self signature
|
|
|
|
*/
|
2024-02-12 17:44:44 +01:00
|
|
|
fun buildDirectKeySignature(
|
|
|
|
pair: PGPKeyPair,
|
|
|
|
hashAlgorithm: HashAlgorithm,
|
|
|
|
subpacketsCallback: SelfSignatureSubpackets.Callback
|
|
|
|
): PGPSignature {
|
|
|
|
val builder =
|
|
|
|
DirectKeySelfSignatureBuilder(pair.privateKey, pair.publicKey, hashAlgorithm)
|
|
|
|
|
|
|
|
builder.applyCallback(subpacketsCallback)
|
|
|
|
|
|
|
|
return builder.build()
|
|
|
|
}
|
|
|
|
}
|
2024-02-12 14:43:14 +01:00
|
|
|
}
|
|
|
|
|
2024-02-13 13:28:01 +01:00
|
|
|
/**
|
|
|
|
* Function that can be applied to subkeys.
|
|
|
|
*
|
|
|
|
* @param primaryKey primary key pair
|
|
|
|
* @param subkey subkey pair
|
|
|
|
* @param builder builder instance that generated the subkey
|
|
|
|
*/
|
2024-02-12 14:43:14 +01:00
|
|
|
abstract class ApplyToSubkey(
|
|
|
|
val primaryKey: PGPKeyPair,
|
|
|
|
val subkey: PGPKeyPair,
|
2024-02-12 17:44:44 +01:00
|
|
|
val builder: DefineSubkeys<*>
|
|
|
|
) {
|
2024-02-12 14:43:14 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Add a binding signature to the subkey.
|
|
|
|
*
|
|
|
|
* @param subpacketsCallback callback to modify the binding signatures subpackets
|
2024-02-13 13:28:01 +01:00
|
|
|
* @param hashAlgorithm hash algorithm to be used during signature calculation
|
|
|
|
* @param bindingTime creation time of the binding signature
|
|
|
|
*
|
|
|
|
* @return modified subkey pair
|
2024-02-12 14:43:14 +01:00
|
|
|
*/
|
|
|
|
abstract fun addBindingSignature(
|
|
|
|
subpacketsCallback: SelfSignatureSubpackets.Callback = SelfSignatureSubpackets.nop(),
|
2024-02-12 17:44:44 +01:00
|
|
|
hashAlgorithm: HashAlgorithm =
|
|
|
|
builder.policy.certificationSignatureHashAlgorithmPolicy.defaultHashAlgorithm,
|
2024-02-12 14:43:14 +01:00
|
|
|
bindingTime: Date = subkey.publicKey.creationTime
|
|
|
|
): PGPKeyPair
|
2024-02-12 17:44:44 +01:00
|
|
|
|
2024-02-13 13:28:01 +01:00
|
|
|
/**
|
|
|
|
* Implementation of the [ApplyToSubkey] function tailored to OpenPGP v4 keys.
|
|
|
|
*
|
|
|
|
* @param primaryKey primary key pair
|
|
|
|
* @param subkey subkey pair
|
|
|
|
* @param builder builder instance that generated the subkey
|
|
|
|
*/
|
2024-02-12 17:44:44 +01:00
|
|
|
class V4(primaryKey: PGPKeyPair, subkey: PGPKeyPair, builder: DefineSubkeys<*>) :
|
|
|
|
ApplyToSubkey(primaryKey, subkey, builder) {
|
|
|
|
|
|
|
|
override fun addBindingSignature(
|
|
|
|
subpacketsCallback: SelfSignatureSubpackets.Callback,
|
|
|
|
hashAlgorithm: HashAlgorithm,
|
|
|
|
bindingTime: Date
|
|
|
|
): PGPKeyPair {
|
|
|
|
val sig =
|
|
|
|
buildBindingSignature(
|
|
|
|
primaryKey, subkey, hashAlgorithm, bindingTime, subpacketsCallback)
|
|
|
|
|
|
|
|
return PGPKeyPair(
|
|
|
|
PGPPublicKey.addCertification(subkey.publicKey, sig), subkey.privateKey)
|
|
|
|
}
|
|
|
|
|
2024-02-13 13:28:01 +01:00
|
|
|
/**
|
|
|
|
* Generate a version 4 binding signature that binds the [subkey] to the [primaryKey].
|
|
|
|
*
|
|
|
|
* @param primaryKey primary key pair
|
|
|
|
* @param subkey subkey pair
|
|
|
|
* @param hashAlgorithm hash algorithm to be used during signature calculation
|
|
|
|
* @param bindingTime creation time of the subkey
|
|
|
|
* @param subpacketsCallback callback to modify the subpackets of the binding signature
|
|
|
|
*
|
|
|
|
* @return subkey binding signature
|
|
|
|
*/
|
2024-02-12 17:44:44 +01:00
|
|
|
fun buildBindingSignature(
|
|
|
|
primaryKey: PGPKeyPair,
|
|
|
|
subkey: PGPKeyPair,
|
|
|
|
hashAlgorithm: HashAlgorithm,
|
|
|
|
bindingTime: Date,
|
|
|
|
subpacketsCallback: SelfSignatureSubpackets.Callback
|
|
|
|
): PGPSignature {
|
|
|
|
return SubkeyBindingSignatureBuilder(
|
2024-02-13 13:28:01 +01:00
|
|
|
primaryKey.privateKey, primaryKey.publicKey, hashAlgorithm)
|
2024-02-12 17:44:44 +01:00
|
|
|
.applyCallback(
|
|
|
|
subpacketsCallback.then(
|
|
|
|
SelfSignatureSubpackets.applyHashed {
|
|
|
|
setSignatureCreationTime(bindingTime)
|
|
|
|
}))
|
|
|
|
.build(subkey.publicKey)
|
|
|
|
}
|
|
|
|
}
|
2024-02-12 14:43:14 +01:00
|
|
|
}
|
|
|
|
|
2024-02-13 13:28:01 +01:00
|
|
|
/**
|
|
|
|
* Templates for OpenPGP key generation.
|
|
|
|
*/
|
2024-02-12 17:44:44 +01:00
|
|
|
class OpenPgpKeyTemplates {
|
|
|
|
|
|
|
|
companion object {
|
2024-02-13 13:28:01 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Templates for version 4 OpenPGP keys.
|
|
|
|
*
|
|
|
|
* @return templates
|
|
|
|
*/
|
2024-02-12 17:44:44 +01:00
|
|
|
@JvmStatic fun v4() = V4()
|
|
|
|
}
|
2024-02-12 14:43:14 +01:00
|
|
|
|
2024-02-13 13:28:01 +01:00
|
|
|
/**
|
|
|
|
* Templates for version 4 OpenPGP keys.
|
|
|
|
* Version 4 keys are compliant to RFC4880.
|
|
|
|
*/
|
2024-02-12 14:43:14 +01:00
|
|
|
class V4 {
|
2024-02-12 17:44:44 +01:00
|
|
|
|
2024-02-13 13:28:01 +01:00
|
|
|
/**
|
|
|
|
* Generate an OpenPGP key that consists of an Ed25519 primary key used for certification
|
|
|
|
* of third-party keys, a dedicated Ed25519 subkey for message signing, and an X25519
|
|
|
|
* subkey used for message encryption.
|
|
|
|
*
|
|
|
|
* @param userId an arbitrary number of user-ids. The first UserID will be marked as primary
|
|
|
|
* @param creationTime creation time for the OpenPGP key
|
|
|
|
*/
|
2024-02-12 17:44:44 +01:00
|
|
|
fun ed25519Curve25519(
|
|
|
|
vararg userId: CharSequence,
|
|
|
|
creationTime: Date = Date()
|
|
|
|
): PGPSecretKeyRing =
|
|
|
|
buildV4(creationTime = creationTime)
|
|
|
|
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519)) {
|
2024-02-13 13:28:01 +01:00
|
|
|
// Add UserIDs
|
|
|
|
userId.forEachIndexed { index, uid ->
|
|
|
|
if (index == 0) {
|
|
|
|
// Mark first UserID as primary
|
|
|
|
addUserId(uid, SelfSignatureSubpackets.applyHashed { setPrimaryUserId() })
|
|
|
|
} else {
|
|
|
|
addUserId(uid)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Add Direct-Key signature with preferences and keyFlags
|
2024-02-12 17:44:44 +01:00
|
|
|
addDirectKeySignature(
|
|
|
|
SelfSignatureSubpackets.applyHashed { setKeyFlags(KeyFlag.CERTIFY_OTHER) })
|
|
|
|
}
|
2024-02-13 13:28:01 +01:00
|
|
|
// singing key
|
2024-02-12 17:44:44 +01:00
|
|
|
.addSubkey(KeyType.EDDSA(EdDSACurve._Ed25519)) {
|
|
|
|
addBindingSignature(
|
|
|
|
SelfSignatureSubpackets.applyHashed { setKeyFlags(KeyFlag.SIGN_DATA) })
|
|
|
|
}
|
2024-02-13 13:28:01 +01:00
|
|
|
// encryption key
|
2024-02-12 17:44:44 +01:00
|
|
|
.addSubkey(KeyType.XDH(XDHSpec._X25519)) {
|
|
|
|
addBindingSignature(
|
|
|
|
SelfSignatureSubpackets.applyHashed {
|
|
|
|
setKeyFlags(KeyFlag.ENCRYPT_COMMS, KeyFlag.ENCRYPT_STORAGE)
|
2024-02-12 14:43:14 +01:00
|
|
|
})
|
2024-02-12 17:44:44 +01:00
|
|
|
}
|
|
|
|
.build()
|
|
|
|
|
2024-02-13 13:28:01 +01:00
|
|
|
/**
|
|
|
|
* Generate an OpenPGP key that consists of an RSA primary key used for certification
|
|
|
|
* of third-party keys, a dedicated RSA subkey for message signing, and an RSA
|
|
|
|
* subkey used for message encryption.
|
|
|
|
*
|
|
|
|
* @param userId an arbitrary number of user-ids. The first UserID will be marked as primary
|
|
|
|
* @param creationTime creation time for the OpenPGP key
|
|
|
|
* @param length RSA bit strength
|
|
|
|
*/
|
2024-02-12 17:44:44 +01:00
|
|
|
fun composedRsa(
|
|
|
|
vararg userId: CharSequence,
|
|
|
|
creationTime: Date = Date(),
|
|
|
|
length: RsaLength = RsaLength._4096
|
|
|
|
): PGPSecretKeyRing =
|
|
|
|
buildV4(creationTime = creationTime)
|
|
|
|
.setPrimaryKey(KeyType.RSA(length)) {
|
2024-02-13 13:28:01 +01:00
|
|
|
// Add UserIDs
|
|
|
|
userId.forEachIndexed { index, uid ->
|
|
|
|
if (index == 0) {
|
|
|
|
// Mark first UserID as primary
|
|
|
|
addUserId(uid, SelfSignatureSubpackets.applyHashed { setPrimaryUserId() })
|
|
|
|
} else {
|
|
|
|
addUserId(uid)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Add Direct-Key signature with preferences and keyFlags
|
2024-02-12 17:44:44 +01:00
|
|
|
addDirectKeySignature(
|
|
|
|
SelfSignatureSubpackets.applyHashed { setKeyFlags(KeyFlag.CERTIFY_OTHER) })
|
|
|
|
}
|
2024-02-13 13:28:01 +01:00
|
|
|
// signing key
|
2024-02-12 17:44:44 +01:00
|
|
|
.addSubkey(KeyType.RSA(length)) {
|
|
|
|
addBindingSignature(
|
|
|
|
SelfSignatureSubpackets.applyHashed { setKeyFlags(KeyFlag.SIGN_DATA) })
|
|
|
|
}
|
2024-02-13 13:28:01 +01:00
|
|
|
// encryption key
|
2024-02-12 17:44:44 +01:00
|
|
|
.addSubkey(KeyType.RSA(length)) {
|
|
|
|
addBindingSignature(
|
|
|
|
SelfSignatureSubpackets.applyHashed {
|
2024-02-12 14:43:14 +01:00
|
|
|
setKeyFlags(KeyFlag.ENCRYPT_COMMS, KeyFlag.ENCRYPT_STORAGE)
|
|
|
|
})
|
2024-02-12 17:44:44 +01:00
|
|
|
}
|
|
|
|
.build()
|
|
|
|
|
2024-02-13 13:28:01 +01:00
|
|
|
/**
|
|
|
|
* Generate an OpenPGP key consisting of a single RSA key that is used for certification of
|
|
|
|
* third-party keys, signing and encryption of messages.
|
|
|
|
*
|
|
|
|
* @param userId an arbitrary number of UserIDs. The first one will be marked as primary.
|
|
|
|
* @param creationTime creation time of the OpenPGP key
|
|
|
|
* @param length bit-strength of the RSA key
|
|
|
|
*/
|
2024-02-12 17:44:44 +01:00
|
|
|
fun singleRsa(
|
|
|
|
vararg userId: CharSequence,
|
|
|
|
creationTime: Date = Date(),
|
|
|
|
length: RsaLength = RsaLength._4096
|
|
|
|
): PGPSecretKeyRing =
|
|
|
|
buildV4(creationTime = creationTime)
|
|
|
|
.setPrimaryKey(KeyType.RSA(length)) {
|
|
|
|
userId.forEach { addUserId(it) }
|
|
|
|
addDirectKeySignature(
|
|
|
|
SelfSignatureSubpackets.applyHashed {
|
|
|
|
setKeyFlags(
|
|
|
|
KeyFlag.CERTIFY_OTHER,
|
|
|
|
KeyFlag.SIGN_DATA,
|
|
|
|
KeyFlag.ENCRYPT_COMMS,
|
|
|
|
KeyFlag.ENCRYPT_STORAGE)
|
|
|
|
})
|
|
|
|
keyPair
|
|
|
|
}
|
|
|
|
.build()
|
2024-02-12 14:43:14 +01:00
|
|
|
}
|
|
|
|
}
|