Further progress

This commit is contained in:
Paul Schaub 2024-01-11 16:44:21 +01:00
parent 92550e35cc
commit 35a68823bd
Signed by: vanitasvitae
GPG Key ID: 62BEE9264BF17311
14 changed files with 458 additions and 128 deletions

View File

@ -100,7 +100,8 @@ abstract class ImplementationFactory {
abstract fun getPGPDataEncryptorBuilder(symmetricKeyAlgorithm: Int): PGPDataEncryptorBuilder
@Throws(PGPException::class)
@Deprecated("Replace with versioned getter method, such as getPGPV4KeyPair()",
@Deprecated(
"Replace with versioned getter method, such as getPGPV4KeyPair()",
replaceWith = ReplaceWith("getPGPV4KeyPair"))
fun getPGPKeyPair(
publicKeyAlgorithm: PublicKeyAlgorithm,

View File

@ -106,15 +106,17 @@ abstract class OpenPgpFingerprint : CharSequence, Comparable<OpenPgpFingerprint>
* @param key key
* @return fingerprint
*/
@JvmStatic fun of(key: PGPPublicKey): OpenPgpFingerprint = of(key.version, key.fingerprint)
@JvmStatic
fun of(key: PGPPublicKey): OpenPgpFingerprint =
when (key.version) {
4 -> OpenPgpV4Fingerprint(key)
5 -> OpenPgpV5Fingerprint(key)
6 -> OpenPgpV6Fingerprint(key)
fun of(keyVersion: Int, binaryFingerprint: ByteArray): OpenPgpFingerprint =
when (keyVersion) {
4 -> OpenPgpV4Fingerprint(binaryFingerprint)
5 -> OpenPgpV5Fingerprint(binaryFingerprint)
6 -> OpenPgpV6Fingerprint(binaryFingerprint)
else ->
throw IllegalArgumentException(
"OpenPGP keys of version ${key.version} are not supported.")
"OpenPGP keys of version $keyVersion are not supported.")
}
/**

View File

@ -1,87 +1,164 @@
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.CertificationType
import org.pgpainless.algorithm.HashAlgorithm
import org.pgpainless.algorithm.SignatureType
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
import org.pgpainless.key.generation.type.rsa.RsaLength
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.PrimaryKeyBindingSignatureBuilder
import org.pgpainless.signature.builder.SelfSignatureBuilder
import org.pgpainless.signature.builder.SubkeyBindingSignatureBuilder
import org.pgpainless.signature.subpackets.SelfSignatureSubpackets
import java.security.KeyPairGenerator
import java.util.*
class OpenPgpKeyBuilder {
fun buildV4Key(
type: KeyType,
creationTime: Date = Date()
): V4PrimaryKeyBuilder = V4PrimaryKeyBuilder(type, creationTime)
creationTime: Date = Date(),
policy: Policy
): V4PrimaryKeyBuilder = V4PrimaryKeyBuilder(type, creationTime, policy)
abstract class V4KeyBuilder<T: V4KeyBuilder<T>>(
abstract class V4KeyBuilder<T : V4KeyBuilder<T>>(
val type: KeyType,
val creationTime: Date,
val certificateCreationTime: Date = Date()
val certificateCreationTime: Date = Date(),
val policy: Policy
) {
internal var key = generateKeyPair()
fun subkey(
type: KeyType,
creationTime: Date = certificateCreationTime
): V4SubkeyBuilder = V4SubkeyBuilder(type, creationTime, primaryKey())
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()
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)
}
.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
): V4KeyBuilder<V4PrimaryKeyBuilder>(type, creationTime) {
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 = HashAlgorithm.SHA512,
hashAlgorithm: HashAlgorithm =
policy.certificationSignatureHashAlgorithmPolicy.defaultHashAlgorithm,
subpacketsCallback: SelfSignatureSubpackets.Callback =
object : SelfSignatureSubpackets.Callback {
}
SelfSignatureSubpackets.defaultCallback()
) = apply {
val sig = SelfSignatureBuilder(
key.privateKey,
key.publicKey,
SignatureType.POSITIVE_CERTIFICATION,
hashAlgorithm)
.applyCallback(subpacketsCallback)
.build(userId)
key = PGPKeyPair(
PGPPublicKey.addCertification(key.publicKey, userId.toString(), sig),
key.privateKey
)
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 {
@ -94,18 +171,51 @@ class OpenPgpKeyBuilder {
class V4SubkeyBuilder(
type: KeyType,
creationTime: Date,
policy: Policy,
private val primaryKeyBuilder: V4PrimaryKeyBuilder
): V4KeyBuilder<V4SubkeyBuilder>(type, creationTime) {
) : V4KeyBuilder<V4SubkeyBuilder>(type, creationTime, policy = policy) {
fun bindingSignature(subpacketCallback: SelfSignatureSubpackets.Callback) = apply {
SubkeyBindingSignatureBuilder(primaryKeyBuilder.key.privateKey, primaryKeyBuilder.key.publicKey)
.applyCallback(subpacketCallback)
.build(key.publicKey)
.let {
key = PGPKeyPair(
PGPPublicKey.addCertification(key.publicKey, it),
key.privateKey)
}
fun 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)
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 {
@ -113,22 +223,14 @@ class OpenPgpKeyBuilder {
val pubkey = keyPair.publicKey
val privkey = keyPair.privateKey
// form subkey packet
val subkey = PublicSubkeyPacket(pubkey.algorithm,
pubkey.creationTime, pubkey.publicKeyPacket.key)
val subkey =
PublicSubkeyPacket(
pubkey.algorithm, pubkey.creationTime, pubkey.publicKeyPacket.key)
return PGPKeyPair(
PGPPublicKey(subkey, fpCalc),
PGPPrivateKey(pubkey.keyID, subkey, privkey.privateKeyDataPacket)
)
PGPPrivateKey(pubkey.keyID, subkey, privkey.privateKeyDataPacket))
}
override fun primaryKey() = primaryKeyBuilder.primaryKey()
fun bindingSignature(
bindingTime: Date = creationTime
): V4SubkeyBuilder = bindingSignature(object : SelfSignatureSubpackets.Callback {
override fun modifyHashedSubpackets(hashedSubpackets: SelfSignatureSubpackets) {
hashedSubpackets.setSignatureCreationTime(bindingTime)
}
})
}
}

View File

@ -1,79 +1,100 @@
package org.pgpainless.key.generation
import java.util.*
import org.bouncycastle.openpgp.PGPSecretKey
import org.bouncycastle.openpgp.PGPSecretKeyRing
import org.pgpainless.algorithm.HashAlgorithm
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
import java.util.*
class OpenPgpV4KeyGenerator(
keyType: KeyType,
private val policy: Policy,
private val referenceTime: Date = Date()
private val referenceTime: Date = Date(),
private val keyGenerationPolicy: AlgorithmSuite = policy.keyGenerationAlgorithmSuite
) {
private val primaryKey = OpenPgpKeyBuilder.V4PrimaryKeyBuilder(keyType, referenceTime)
private val primaryKey = OpenPgpKeyBuilder.V4PrimaryKeyBuilder(keyType, referenceTime, policy)
private val subkeys = mutableListOf<OpenPgpKeyBuilder.V4SubkeyBuilder>()
fun addUserId(
userId: CharSequence,
bindingTime: Date = referenceTime
) = apply {
primaryKey.userId(userId, bindingTime)
}
subpacketsCallback: SelfSignatureSubpackets.Callback =
SelfSignatureSubpackets.defaultCallback()
) = apply { primaryKey.userId(userId, subpacketsCallback = subpacketsCallback) }
fun addSubkey(
keyType: KeyType,
creationTime: Date = referenceTime,
bindingTime: Date = creationTime
) = addSubkey(OpenPgpKeyBuilder.V4SubkeyBuilder(keyType, creationTime, primaryKey), bindingTime)
) =
addSubkey(
OpenPgpKeyBuilder.V4SubkeyBuilder(keyType, creationTime, policy, primaryKey),
bindingTime)
fun addSubkey(
subkeyBuilder: OpenPgpKeyBuilder.V4SubkeyBuilder,
bindingTime: Date = subkeyBuilder.creationTime
) = apply {
subkeys.add(subkeyBuilder)
}
) = apply { subkeys.add(subkeyBuilder) }
fun addEncryptionSubkey(
keyType: KeyType,
creationTime: Date = referenceTime,
bindingTime: Date = creationTime
) = addSubkey(OpenPgpKeyBuilder.V4SubkeyBuilder(keyType, creationTime, primaryKey)
.bindingSignature(object: SelfSignatureSubpackets.Callback {
override fun modifyHashedSubpackets(hashedSubpackets: SelfSignatureSubpackets) {
hashedSubpackets.setSignatureCreationTime(bindingTime)
hashedSubpackets.setKeyFlags(KeyFlag.ENCRYPT_STORAGE, KeyFlag.ENCRYPT_COMMS)
}
})
)
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().getPGPDigestCalculator(HashAlgorithm.SHA1),
true,
protector.getEncryptor(primaryKey.key.keyID)
)
).plus(
subkeys.map {
PGPSecretKey(
it.key.privateKey,
it.key.publicKey,
ImplementationFactory.getInstance().getPGPDigestCalculator(HashAlgorithm.SHA1),
false,
protector.getEncryptor(it.key.keyID)
)
}
)
)
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

@ -64,8 +64,7 @@ abstract class AbstractSignatureBuilder<B : AbstractSignatureBuilder<B>>(
negotiateHashAlgorithm(publicSigningKey),
SignatureType.requireFromCode(archetypeSignature.signatureType),
SignatureSubpackets.refreshHashedSubpackets(publicSigningKey, archetypeSignature),
SignatureSubpackets.refreshUnhashedSubpackets(archetypeSignature)
)
SignatureSubpackets.refreshUnhashedSubpackets(archetypeSignature))
@Throws(PGPException::class)
constructor(

View File

@ -6,11 +6,15 @@ package org.pgpainless.signature.builder
import java.util.function.Predicate
import org.bouncycastle.openpgp.PGPException
import org.bouncycastle.openpgp.PGPPrivateKey
import org.bouncycastle.openpgp.PGPPublicKey
import org.bouncycastle.openpgp.PGPSecretKey
import org.bouncycastle.openpgp.PGPSignature
import org.pgpainless.algorithm.HashAlgorithm
import org.pgpainless.algorithm.SignatureType
import org.pgpainless.key.protection.SecretKeyRingProtector
import org.pgpainless.signature.subpackets.SelfSignatureSubpackets
import org.pgpainless.signature.subpackets.SignatureSubpackets
/**
* [AbstractSignatureBuilder] devoted to direct-key self-signatures. Direct-key self-signatures are
@ -28,6 +32,19 @@ class DirectKeySelfSignatureBuilder : AbstractSignatureBuilder<DirectKeySelfSign
archetypeSignature: PGPSignature
) : super(signingKey, protector, archetypeSignature)
@Throws(PGPException::class)
constructor(
privateSigningKey: PGPPrivateKey,
publicSigningKey: PGPPublicKey,
hashAlgorithm: HashAlgorithm
) : super(
privateSigningKey,
publicSigningKey,
hashAlgorithm,
SignatureType.DIRECT_KEY,
SignatureSubpackets.createHashedSubpackets(publicSigningKey),
SignatureSubpackets.createEmptySubpackets())
@Throws(PGPException::class)
constructor(
signingKey: PGPSecretKey,

View File

@ -6,6 +6,7 @@ package org.pgpainless.signature.builder
import java.util.function.Predicate
import org.bouncycastle.openpgp.PGPException
import org.bouncycastle.openpgp.PGPPrivateKey
import org.bouncycastle.openpgp.PGPPublicKey
import org.bouncycastle.openpgp.PGPSecretKey
import org.bouncycastle.openpgp.PGPSignature
@ -32,6 +33,18 @@ class PrimaryKeyBindingSignatureBuilder :
subkeyProtector: SecretKeyRingProtector
) : super(SignatureType.PRIMARYKEY_BINDING, signingSubkey, subkeyProtector)
constructor(
privateSubkey: PGPPrivateKey,
publicSubkey: PGPPublicKey,
hashAlgorithm: HashAlgorithm
) : super(
privateSubkey,
publicSubkey,
hashAlgorithm,
SignatureType.PRIMARYKEY_BINDING,
SignatureSubpackets.createHashedSubpackets(publicSubkey),
SignatureSubpackets.createEmptySubpackets())
@Throws(PGPException::class)
constructor(
signingSubkey: PGPSecretKey,

View File

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

View File

@ -29,13 +29,14 @@ class SubkeyBindingSignatureBuilder : AbstractSignatureBuilder<SubkeyBindingSign
constructor(
signingKey: PGPPrivateKey,
publicSigningKey: PGPPublicKey,
) : super(signingKey,
hashAlgorithm: HashAlgorithm = negotiateHashAlgorithm(publicSigningKey)
) : super(
signingKey,
publicSigningKey,
negotiateHashAlgorithm(publicSigningKey),
hashAlgorithm,
SignatureType.SUBKEY_BINDING,
SignatureSubpackets.createHashedSubpackets(publicSigningKey),
SignatureSubpackets.createEmptySubpackets()
)
SignatureSubpackets.createEmptySubpackets())
@Throws(PGPException::class)
constructor(

View File

@ -7,11 +7,13 @@ package org.pgpainless.signature.subpackets
import java.io.IOException
import java.net.URL
import java.util.*
import openpgp.plusSeconds
import org.bouncycastle.bcpg.sig.*
import org.bouncycastle.openpgp.PGPPublicKey
import org.bouncycastle.openpgp.PGPSignature
import org.pgpainless.algorithm.HashAlgorithm
import org.pgpainless.algorithm.PublicKeyAlgorithm
import org.pgpainless.key.OpenPgpFingerprint
interface BaseSignatureSubpackets {
@ -33,18 +35,31 @@ interface BaseSignatureSubpackets {
fun setIssuerKeyId(issuerKeyID: IssuerKeyID?): BaseSignatureSubpackets
fun getIssuerKeyId(): Long? = getIssuerKeyIdPacket()?.keyID
fun getIssuerKeyIdPacket(): IssuerKeyID?
fun setIssuerFingerprint(isCritical: Boolean, issuer: PGPPublicKey): BaseSignatureSubpackets
fun setIssuerFingerprint(issuer: PGPPublicKey): BaseSignatureSubpackets
fun setIssuerFingerprint(fingerprint: IssuerFingerprint?): BaseSignatureSubpackets
fun getIssuerFingerprint(): OpenPgpFingerprint? =
getIssuerFingerprintPacket()?.let { OpenPgpFingerprint.of(it.keyVersion, it.fingerprint) }
fun getIssuerFingerprintPacket(): IssuerFingerprint?
fun setSignatureCreationTime(creationTime: Date): BaseSignatureSubpackets
fun setSignatureCreationTime(isCritical: Boolean, creationTime: Date): BaseSignatureSubpackets
fun setSignatureCreationTime(creationTime: SignatureCreationTime?): BaseSignatureSubpackets
fun getSignatureCreationTime(): Date? = getSignatureCreationTimePacket()?.time
fun getSignatureCreationTimePacket(): SignatureCreationTime?
fun setSignatureExpirationTime(
creationTime: Date,
expirationTime: Date?
@ -62,12 +77,29 @@ interface BaseSignatureSubpackets {
expirationTime: SignatureExpirationTime?
): BaseSignatureSubpackets
fun getSignatureExpirationTimeInSeconds(): Long? = getSignatureExpirationTimePacket()?.time
fun getSignatureExpirationTime(creationTime: Date): Date? =
getSignatureExpirationTimeInSeconds()?.let {
if (it == 0L) {
null
} else {
creationTime.plusSeconds(it)
}
}
fun getSignatureExpirationTimePacket(): SignatureExpirationTime?
fun setSignerUserId(userId: CharSequence): BaseSignatureSubpackets
fun setSignerUserId(isCritical: Boolean, userId: CharSequence): BaseSignatureSubpackets
fun setSignerUserId(signerUserID: SignerUserID?): BaseSignatureSubpackets
fun getSignerUserId(): CharSequence? = getSignerUserIdPacket()?.id
fun getSignerUserIdPacket(): SignerUserID?
fun addNotationData(
isCritical: Boolean,
notationName: String,
@ -83,6 +115,8 @@ interface BaseSignatureSubpackets {
fun addNotationData(notationData: NotationData): BaseSignatureSubpackets
fun getNotationDataPackets(): List<NotationData>
fun clearNotationData(): BaseSignatureSubpackets
fun addIntendedRecipientFingerprint(recipientKey: PGPPublicKey): BaseSignatureSubpackets
@ -96,6 +130,13 @@ interface BaseSignatureSubpackets {
intendedRecipient: IntendedRecipientFingerprint
): BaseSignatureSubpackets
fun getIntendedRecipientFingerprints(): List<OpenPgpFingerprint> =
getIntendedRecipientFingerprintPackets().map {
OpenPgpFingerprint.of(it.keyVersion, it.fingerprint)
}
fun getIntendedRecipientFingerprintPackets(): List<IntendedRecipientFingerprint>
fun clearIntendedRecipientFingerprints(): BaseSignatureSubpackets
fun setExportable(): BaseSignatureSubpackets
@ -106,18 +147,30 @@ interface BaseSignatureSubpackets {
fun setExportable(exportable: Exportable?): BaseSignatureSubpackets
fun getExportable(): Boolean? = getExportablePacket()?.isExportable
fun getExportablePacket(): Exportable?
fun setPolicyUrl(policyUrl: URL): BaseSignatureSubpackets
fun setPolicyUrl(isCritical: Boolean, policyUrl: URL): BaseSignatureSubpackets
fun setPolicyUrl(policyUrl: PolicyURI?): BaseSignatureSubpackets
fun getPolicyUrl(): CharSequence? = getPolicyUrlPacket()?.uri
fun getPolicyUrlPacket(): PolicyURI?
fun setRegularExpression(regex: CharSequence): BaseSignatureSubpackets
fun setRegularExpression(isCritical: Boolean, regex: CharSequence): BaseSignatureSubpackets
fun setRegularExpression(regex: RegularExpression?): BaseSignatureSubpackets
fun getRegularExpression(): CharSequence? = getRegularExpressionPacket()?.regex
fun getRegularExpressionPacket(): RegularExpression?
fun setRevocable(): BaseSignatureSubpackets
fun setRevocable(isRevocable: Boolean): BaseSignatureSubpackets
@ -126,6 +179,10 @@ interface BaseSignatureSubpackets {
fun setRevocable(revocable: Revocable?): BaseSignatureSubpackets
fun getRevocable(): Boolean? = getRevocablePacket()?.isRevocable
fun getRevocablePacket(): Revocable?
fun setSignatureTarget(
keyAlgorithm: PublicKeyAlgorithm,
hashAlgorithm: HashAlgorithm,
@ -141,12 +198,16 @@ interface BaseSignatureSubpackets {
fun setSignatureTarget(signatureTarget: SignatureTarget?): BaseSignatureSubpackets
fun getSignatureTargetPacket(): SignatureTarget?
fun setTrust(depth: Int, amount: Int): BaseSignatureSubpackets
fun setTrust(isCritical: Boolean, depth: Int, amount: Int): BaseSignatureSubpackets
fun setTrust(trust: TrustSignature?): BaseSignatureSubpackets
fun getTrustPacket(): TrustSignature?
@Throws(IOException::class)
fun addEmbeddedSignature(signature: PGPSignature): BaseSignatureSubpackets
@ -155,6 +216,8 @@ interface BaseSignatureSubpackets {
fun addEmbeddedSignature(embeddedSignature: EmbeddedSignature): BaseSignatureSubpackets
fun getEmbeddedSignaturePackets(): List<EmbeddedSignature>
fun clearEmbeddedSignatures(): BaseSignatureSubpackets
companion object {

View File

@ -5,6 +5,7 @@
package org.pgpainless.signature.subpackets
import java.util.*
import openpgp.plusSeconds
import org.bouncycastle.bcpg.sig.Features
import org.bouncycastle.bcpg.sig.KeyExpirationTime
import org.bouncycastle.bcpg.sig.KeyFlags
@ -41,12 +42,20 @@ interface SelfSignatureSubpackets : BaseSignatureSubpackets {
fun setKeyFlags(keyFlags: KeyFlags?): SelfSignatureSubpackets
fun getKeyFlags(): List<KeyFlag>? = getKeyFlagsPacket()?.let { KeyFlag.fromBitmask(it.flags) }
fun getKeyFlagsPacket(): KeyFlags?
fun setPrimaryUserId(): SelfSignatureSubpackets
fun setPrimaryUserId(isCritical: Boolean): SelfSignatureSubpackets
fun setPrimaryUserId(primaryUserID: PrimaryUserID?): SelfSignatureSubpackets
fun getPrimaryUserId(): Boolean? = getPrimaryUserIdPacket()?.isPrimaryUserID
fun getPrimaryUserIdPacket(): PrimaryUserID?
fun setKeyExpirationTime(key: PGPPublicKey, keyExpirationTime: Date?): SelfSignatureSubpackets
fun setKeyExpirationTime(
@ -67,6 +76,17 @@ interface SelfSignatureSubpackets : BaseSignatureSubpackets {
fun setKeyExpirationTime(keyExpirationTime: KeyExpirationTime?): SelfSignatureSubpackets
fun getKeyExpirationTime(keyCreationTime: Date): Date? =
getKeyExpirationTimePacket()?.let {
if (it.time == 0L) {
null
} else {
keyCreationTime.plusSeconds(it.time)
}
}
fun getKeyExpirationTimePacket(): KeyExpirationTime?
fun setPreferredCompressionAlgorithms(
vararg algorithms: CompressionAlgorithm
): SelfSignatureSubpackets
@ -84,6 +104,12 @@ interface SelfSignatureSubpackets : BaseSignatureSubpackets {
preferredAlgorithms: PreferredAlgorithms?
): SelfSignatureSubpackets
fun getPreferredCompressionAlgorithms(): Set<CompressionAlgorithm> =
SignatureSubpacketsUtil.parsePreferredCompressionAlgorithms(
getPreferredCompressionAlgorithmsPacket())
fun getPreferredCompressionAlgorithmsPacket(): PreferredAlgorithms?
fun setPreferredSymmetricKeyAlgorithms(
vararg algorithms: SymmetricKeyAlgorithm
): SelfSignatureSubpackets
@ -101,6 +127,12 @@ interface SelfSignatureSubpackets : BaseSignatureSubpackets {
algorithms: PreferredAlgorithms?
): SelfSignatureSubpackets
fun getPreferredSymmetricKeyAlgorithms(): Set<SymmetricKeyAlgorithm> =
SignatureSubpacketsUtil.parsePreferredSymmetricKeyAlgorithms(
getPreferredSymmetricKeyAlgorithmsPacket())
fun getPreferredSymmetricKeyAlgorithmsPacket(): PreferredAlgorithms?
fun setPreferredHashAlgorithms(vararg algorithms: HashAlgorithm): SelfSignatureSubpackets
fun setPreferredHashAlgorithms(algorithms: Collection<HashAlgorithm>): SelfSignatureSubpackets
@ -112,6 +144,11 @@ interface SelfSignatureSubpackets : BaseSignatureSubpackets {
fun setPreferredHashAlgorithms(algorithms: PreferredAlgorithms?): SelfSignatureSubpackets
fun getPreferredHashAlgorithms(): Set<HashAlgorithm> =
SignatureSubpacketsUtil.parsePreferredHashAlgorithms(getPreferredHashAlgorithmsPacket())
fun getPreferredHashAlgorithmsPacket(): PreferredAlgorithms?
fun addRevocationKey(revocationKey: PGPPublicKey): SelfSignatureSubpackets
fun addRevocationKey(isCritical: Boolean, revocationKey: PGPPublicKey): SelfSignatureSubpackets
@ -124,6 +161,8 @@ interface SelfSignatureSubpackets : BaseSignatureSubpackets {
fun addRevocationKey(revocationKey: RevocationKey): SelfSignatureSubpackets
fun getRevocationKeyPackets(): List<RevocationKey>
fun clearRevocationKeys(): SelfSignatureSubpackets
fun setFeatures(vararg features: Feature): SelfSignatureSubpackets
@ -178,5 +217,7 @@ interface SelfSignatureSubpackets : BaseSignatureSubpackets {
}
}
}
@JvmStatic fun defaultCallback() = object : Callback {}
}
}

View File

@ -177,6 +177,8 @@ class SignatureSubpackets :
this.keyFlagsSubpacket = keyFlags
}
override fun getKeyFlagsPacket(): KeyFlags? = keyFlagsSubpacket
override fun setPrimaryUserId(): SignatureSubpackets = apply { setPrimaryUserId(true) }
override fun setPrimaryUserId(isCritical: Boolean): SignatureSubpackets = apply {
@ -187,6 +189,8 @@ class SignatureSubpackets :
this.primaryUserIdSubpacket = primaryUserID
}
override fun getPrimaryUserIdPacket(): PrimaryUserID? = primaryUserIdSubpacket
override fun setKeyExpirationTime(
key: PGPPublicKey,
keyExpirationTime: Date?
@ -224,6 +228,8 @@ class SignatureSubpackets :
this.keyExpirationTimeSubpacket = keyExpirationTime
}
override fun getKeyExpirationTimePacket(): KeyExpirationTime? = keyExpirationTimeSubpacket
override fun setPreferredCompressionAlgorithms(
vararg algorithms: CompressionAlgorithm
): SignatureSubpackets = apply { setPreferredCompressionAlgorithms(setOf(*algorithms)) }
@ -253,6 +259,9 @@ class SignatureSubpackets :
this.preferredCompressionAlgorithmsSubpacket = algorithms
}
override fun getPreferredCompressionAlgorithmsPacket(): PreferredAlgorithms? =
preferredCompressionAlgorithmsSubpacket
override fun setPreferredSymmetricKeyAlgorithms(
vararg algorithms: SymmetricKeyAlgorithm
): SignatureSubpackets = apply { setPreferredSymmetricKeyAlgorithms(setOf(*algorithms)) }
@ -282,6 +291,9 @@ class SignatureSubpackets :
this.preferredSymmetricKeyAlgorithmsSubpacket = algorithms
}
override fun getPreferredSymmetricKeyAlgorithmsPacket(): PreferredAlgorithms? =
preferredSymmetricKeyAlgorithmsSubpacket
override fun setPreferredHashAlgorithms(vararg algorithms: HashAlgorithm): SignatureSubpackets =
apply {
setPreferredHashAlgorithms(setOf(*algorithms))
@ -312,6 +324,9 @@ class SignatureSubpackets :
this.preferredHashAlgorithmsSubpacket = algorithms
}
override fun getPreferredHashAlgorithmsPacket(): PreferredAlgorithms? =
preferredHashAlgorithmsSubpacket
override fun addRevocationKey(revocationKey: PGPPublicKey): SignatureSubpackets = apply {
addRevocationKey(true, revocationKey)
}
@ -335,6 +350,8 @@ class SignatureSubpackets :
(this.revocationKeySubpackets as MutableList).add(revocationKey)
}
override fun getRevocationKeyPackets(): List<RevocationKey> = revocationKeySubpackets
override fun clearRevocationKeys(): SignatureSubpackets = apply {
(this.revocationKeySubpackets as MutableList).clear()
}
@ -352,6 +369,8 @@ class SignatureSubpackets :
this.featuresSubpacket = features
}
override fun getFeaturesPacket(): Features? = featuresSubpacket
override fun setIssuerFingerprintAndKeyId(key: PGPPublicKey): SignatureSubpackets = apply {
setIssuerKeyId(key.keyID)
setIssuerFingerprint(key)
@ -369,6 +388,8 @@ class SignatureSubpackets :
this.issuerKeyIdSubpacket = issuerKeyID
}
override fun getIssuerKeyIdPacket(): IssuerKeyID? = issuerKeyIdSubpacket
override fun setIssuerFingerprint(
isCritical: Boolean,
issuer: PGPPublicKey
@ -385,6 +406,8 @@ class SignatureSubpackets :
this.issuerFingerprintSubpacket = fingerprint
}
override fun getIssuerFingerprintPacket(): IssuerFingerprint? = issuerFingerprintSubpacket
override fun setSignatureCreationTime(creationTime: Date): SignatureSubpackets = apply {
setSignatureCreationTime(true, creationTime)
}
@ -400,6 +423,9 @@ class SignatureSubpackets :
creationTime: SignatureCreationTime?
): SignatureSubpackets = apply { this.signatureCreationTimeSubpacket = creationTime }
override fun getSignatureCreationTimePacket(): SignatureCreationTime? =
signatureCreationTimeSubpacket
override fun setSignatureExpirationTime(
creationTime: Date,
expirationTime: Date?
@ -449,6 +475,9 @@ class SignatureSubpackets :
expirationTime: SignatureExpirationTime?
): SignatureSubpackets = apply { this.signatureExpirationTimeSubpacket = expirationTime }
override fun getSignatureExpirationTimePacket(): SignatureExpirationTime? =
signatureExpirationTimeSubpacket
override fun setSignerUserId(userId: CharSequence): SignatureSubpackets = apply {
setSignerUserId(false, userId)
}
@ -462,6 +491,8 @@ class SignatureSubpackets :
this.signerUserIdSubpacket = signerUserID
}
override fun getSignerUserIdPacket(): SignerUserID? = signerUserIdSubpacket
override fun addNotationData(
isCritical: Boolean,
notationName: String,
@ -483,6 +514,8 @@ class SignatureSubpackets :
(this.notationDataSubpackets as MutableList).add(notationData)
}
override fun getNotationDataPackets(): List<NotationData> = notationDataSubpackets
override fun clearNotationData(): SignatureSubpackets = apply {
(this.notationDataSubpackets as MutableList).clear()
}
@ -507,6 +540,9 @@ class SignatureSubpackets :
(this.intendedRecipientFingerprintSubpackets as MutableList).add(intendedRecipient)
}
override fun getIntendedRecipientFingerprintPackets(): List<IntendedRecipientFingerprint> =
intendedRecipientFingerprintSubpackets
override fun clearIntendedRecipientFingerprints(): SignatureSubpackets = apply {
(this.intendedRecipientFingerprintSubpackets as MutableList).clear()
}
@ -526,6 +562,8 @@ class SignatureSubpackets :
this.exportableSubpacket = exportable
}
override fun getExportablePacket(): Exportable? = exportableSubpacket
override fun setPolicyUrl(policyUrl: URL): SignatureSubpackets = apply {
setPolicyUrl(false, policyUrl)
}
@ -538,6 +576,8 @@ class SignatureSubpackets :
this.policyURISubpacket = policyURISubpacket
}
override fun getPolicyUrlPacket(): PolicyURI? = policyURISubpacket
override fun setRegularExpression(regex: CharSequence): SignatureSubpackets = apply {
setRegularExpression(false, regex)
}
@ -553,6 +593,8 @@ class SignatureSubpackets :
this.regularExpressionSubpacket = regex
}
override fun getRegularExpressionPacket(): RegularExpression? = regularExpressionSubpacket
override fun setRevocable(): SignatureSubpackets = apply { setRevocable(true) }
override fun setRevocable(isRevocable: Boolean): SignatureSubpackets = apply {
@ -568,6 +610,8 @@ class SignatureSubpackets :
this.revocableSubpacket = revocable
}
override fun getRevocablePacket(): Revocable? = revocableSubpacket
override fun setSignatureTarget(
keyAlgorithm: PublicKeyAlgorithm,
hashAlgorithm: HashAlgorithm,
@ -592,6 +636,8 @@ class SignatureSubpackets :
this.signatureTargetSubpacket = signatureTarget
}
override fun getSignatureTargetPacket(): SignatureTarget? = signatureTargetSubpacket
override fun setTrust(depth: Int, amount: Int): SignatureSubpackets = apply {
setTrust(true, depth, amount)
}
@ -605,6 +651,8 @@ class SignatureSubpackets :
this.trustSubpacket = trust
}
override fun getTrustPacket(): TrustSignature? = trustSubpacket
override fun addEmbeddedSignature(signature: PGPSignature): SignatureSubpackets = apply {
addEmbeddedSignature(true, signature)
}
@ -629,6 +677,9 @@ class SignatureSubpackets :
(this.embeddedSignatureSubpackets as MutableList).add(embeddedSignature)
}
override fun getEmbeddedSignaturePackets(): List<EmbeddedSignature> =
embeddedSignatureSubpackets
override fun clearEmbeddedSignatures(): SignatureSubpackets = apply {
(this.embeddedSignatureSubpackets as MutableList).clear()
}

View File

@ -203,7 +203,13 @@ class SignatureSubpacketsUtil {
fun parsePreferredSymmetricKeyAlgorithms(
signature: PGPSignature
): Set<SymmetricKeyAlgorithm> =
getPreferredSymmetricAlgorithms(signature)
parsePreferredSymmetricKeyAlgorithms(getPreferredSymmetricAlgorithms(signature))
@JvmStatic
fun parsePreferredSymmetricKeyAlgorithms(
preferredAlgorithms: PreferredAlgorithms?
): Set<SymmetricKeyAlgorithm> =
preferredAlgorithms
?.preferences
?.map { SymmetricKeyAlgorithm.fromId(it) }
?.filterNotNull()
@ -231,7 +237,13 @@ class SignatureSubpacketsUtil {
*/
@JvmStatic
fun parsePreferredHashAlgorithms(signature: PGPSignature): Set<HashAlgorithm> =
getPreferredHashAlgorithms(signature)
parsePreferredHashAlgorithms(getPreferredHashAlgorithms(signature))
@JvmStatic
fun parsePreferredHashAlgorithms(
preferredAlgorithms: PreferredAlgorithms?
): Set<HashAlgorithm> =
preferredAlgorithms
?.preferences
?.map { HashAlgorithm.fromId(it) }
?.filterNotNull()
@ -262,7 +274,13 @@ class SignatureSubpacketsUtil {
fun parsePreferredCompressionAlgorithms(
signature: PGPSignature
): Set<CompressionAlgorithm> =
getPreferredCompressionAlgorithms(signature)
parsePreferredCompressionAlgorithms(getPreferredCompressionAlgorithms(signature))
@JvmStatic
fun parsePreferredCompressionAlgorithms(
preferredAlgorithms: PreferredAlgorithms?
): Set<CompressionAlgorithm> =
preferredAlgorithms
?.preferences
?.map { CompressionAlgorithm.fromId(it) }
?.filterNotNull()

View File

@ -3,22 +3,24 @@ package org.pgpainless.key.generation
import org.junit.jupiter.api.Test
import org.pgpainless.PGPainless
import org.pgpainless.key.generation.type.KeyType
import org.pgpainless.key.generation.type.ecc.EllipticCurve
import org.pgpainless.key.generation.type.eddsa.EdDSACurve
import org.pgpainless.key.generation.type.rsa.RsaLength
import org.pgpainless.key.generation.type.xdh.XDHSpec
import org.pgpainless.key.protection.SecretKeyRingProtector
import org.pgpainless.policy.Policy
import org.pgpainless.util.DateUtil
class OpenPgpV4KeyGeneratorTest {
@Test
fun test() {
println(PGPainless.asciiArmor(
OpenPgpV4KeyGenerator(KeyType.EDDSA(EdDSACurve._Ed25519), Policy.getInstance())
.addUserId("Alice")
.addEncryptionSubkey(KeyType.XDH(XDHSpec._X25519))
.build(SecretKeyRingProtector.unprotectedKeys())
))
val date = DateUtil.parseUTCDate("2020-04-01 10:00:00 UTC")
val key =
OpenPgpV4KeyGenerator(
KeyType.EDDSA(EdDSACurve._Ed25519), Policy.getInstance(), referenceTime = date)
.addUserId("Alice")
.addEncryptionSubkey(KeyType.XDH(XDHSpec._X25519))
.addSigningSubkey(KeyType.EDDSA(EdDSACurve._Ed25519))
.build(SecretKeyRingProtector.unprotectedKeys())
println(PGPainless.asciiArmor(key))
}
}