1
0
Fork 0
mirror of https://github.com/pgpainless/pgpainless.git synced 2025-09-09 10:19:39 +02:00

Improve KeyRingInfos getPreferences implementations

This commit is contained in:
Paul Schaub 2025-02-24 13:47:53 +01:00
parent 1379942c07
commit 3030f2af2b
Signed by: vanitasvitae
GPG key ID: 62BEE9264BF17311
8 changed files with 139 additions and 27 deletions

View file

@ -0,0 +1,15 @@
// SPDX-FileCopyrightText: 2025 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package org.pgpainless.algorithm
import org.bouncycastle.bcpg.sig.PreferredAEADCiphersuites.Combination
data class AEADCipherMode(val aeadAlgorithm: AEADAlgorithm, val ciphermode: SymmetricKeyAlgorithm) {
constructor(
combination: Combination
) : this(
AEADAlgorithm.requireFromId(combination.aeadAlgorithm),
SymmetricKeyAlgorithm.requireFromId(combination.symmetricAlgorithm))
}

View file

@ -1,3 +1,7 @@
// SPDX-FileCopyrightText: 2025 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package org.pgpainless.bouncycastle.extensions
import org.bouncycastle.openpgp.PGPOnePassSignature

View file

@ -1,3 +1,7 @@
// SPDX-FileCopyrightText: 2025 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package org.pgpainless.bouncycastle.extensions
import org.bouncycastle.openpgp.PGPPublicKeyEncryptedData

View file

@ -0,0 +1,12 @@
// SPDX-FileCopyrightText: 2025 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package org.pgpainless.bouncycastle.extensions
import org.bouncycastle.bcpg.sig.PreferredAEADCiphersuites
import org.pgpainless.algorithm.AEADCipherMode
fun PreferredAEADCiphersuites?.toAEADCipherModes(): Set<AEADCipherMode> {
return this?.algorithms?.asSequence()?.map { AEADCipherMode(it) }?.toSet() ?: setOf()
}

View file

@ -0,0 +1,25 @@
// SPDX-FileCopyrightText: 2025 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package org.pgpainless.bouncycastle.extensions
import org.bouncycastle.bcpg.sig.PreferredAlgorithms
import org.pgpainless.algorithm.CompressionAlgorithm
import org.pgpainless.algorithm.HashAlgorithm
import org.pgpainless.algorithm.SymmetricKeyAlgorithm
fun PreferredAlgorithms?.toHashAlgorithms(): Set<HashAlgorithm> {
return this?.preferences?.asSequence()?.map { HashAlgorithm.requireFromId(it) }?.toSet()
?: setOf()
}
fun PreferredAlgorithms?.toSymmetricKeyAlgorithms(): Set<SymmetricKeyAlgorithm> {
return this?.preferences?.asSequence()?.map { SymmetricKeyAlgorithm.requireFromId(it) }?.toSet()
?: setOf()
}
fun PreferredAlgorithms?.toCompressionAlgorithms(): Set<CompressionAlgorithm> {
return this?.preferences?.asSequence()?.map { CompressionAlgorithm.requireFromId(it) }?.toSet()
?: setOf()
}

View file

@ -5,6 +5,7 @@
package org.pgpainless.key.info
import org.bouncycastle.openpgp.PGPSignature
import org.pgpainless.algorithm.AEADCipherMode
import org.pgpainless.algorithm.CompressionAlgorithm
import org.pgpainless.algorithm.HashAlgorithm
import org.pgpainless.algorithm.SymmetricKeyAlgorithm
@ -40,6 +41,9 @@ abstract class KeyAccessor(protected val info: KeyRingInfo, protected val key: S
get() =
SignatureSubpacketsUtil.parsePreferredCompressionAlgorithms(signatureWithPreferences)
val preferredAEADCipherSuites: Set<AEADCipherMode>
get() = SignatureSubpacketsUtil.parsePreferredAEADCipherSuites(signatureWithPreferences)
/**
* Address the key via a user-id (e.g. `Alice <alice@wonderland.lit>`). In this case we are
* sourcing preferred algorithms from the user-id certification first.

View file

@ -5,6 +5,7 @@
package org.pgpainless.key.info
import java.util.*
import kotlin.NoSuchElementException
import openpgp.openPgpKeyId
import org.bouncycastle.bcpg.KeyIdentifier
import org.bouncycastle.openpgp.*
@ -249,6 +250,11 @@ class KeyRingInfo(
primaryUserId?.let { getPreferredCompressionAlgorithms(it) }
?: getPreferredCompressionAlgorithms(keyIdentifier)
val preferredAEADCipherSuites: Set<AEADCipherMode>
get() =
primaryUserId?.let { getPreferredAEADCipherSuites(it) }
?: getPreferredAEADCipherSuites(keyIdentifier)
/**
* Return the expiration date of the subkey with the provided fingerprint.
*
@ -649,70 +655,103 @@ class KeyRingInfo(
/** [HashAlgorithm] preferences of the given user-ID. */
fun getPreferredHashAlgorithms(userId: CharSequence): Set<HashAlgorithm> {
return getKeyAccessor(userId, keyIdentifier).preferredHashAlgorithms
return keys
.getUserId(userId.toString())
?.getHashAlgorithmPreferences(referenceDate)
?.toHashAlgorithms()
?: throw NoSuchElementException("No user-id '$userId' found on this key.")
}
fun getPreferredHashAlgorithms(keyIdentifier: KeyIdentifier): Set<HashAlgorithm> {
return getPreferredHashAlgorithms(keyIdentifier.keyId)
return keys
.getKey(keyIdentifier)
?.getHashAlgorithmPreferences(referenceDate)
?.toHashAlgorithms()
?: throw NoSuchElementException(
"No subkey with key-id $keyIdentifier found on this key.")
}
/** [HashAlgorithm] preferences of the given key. */
@Deprecated("Pass KeyIdentifier instead.")
fun getPreferredHashAlgorithms(keyId: Long): Set<HashAlgorithm> {
return KeyAccessor.SubKey(this, SubkeyIdentifier(keys.pgpKeyRing, keyId))
.preferredHashAlgorithms
return getPreferredHashAlgorithms(KeyIdentifier(keyId))
}
/** [SymmetricKeyAlgorithm] preferences of the given user-ID. */
fun getPreferredSymmetricKeyAlgorithms(userId: CharSequence): Set<SymmetricKeyAlgorithm> {
return getKeyAccessor(userId, keyIdentifier).preferredSymmetricKeyAlgorithms
return keys
.getUserId(userId.toString())
?.getSymmetricCipherPreferences(referenceDate)
?.toSymmetricKeyAlgorithms()
?: throw NoSuchElementException("No user-id '$userId' found on this key.")
}
fun getPreferredSymmetricKeyAlgorithms(
keyIdentifier: KeyIdentifier
): Set<SymmetricKeyAlgorithm> {
return getPreferredSymmetricKeyAlgorithms(keyIdentifier.keyId)
return keys
.getKey(keyIdentifier)
?.getSymmetricCipherPreferences(referenceDate)
?.toSymmetricKeyAlgorithms()
?: throw NoSuchElementException(
"No subkey with key-id $keyIdentifier found on this key.")
}
/** [SymmetricKeyAlgorithm] preferences of the given key. */
@Deprecated("Pass KeyIdentifier instead.")
fun getPreferredSymmetricKeyAlgorithms(keyId: Long): Set<SymmetricKeyAlgorithm> {
return KeyAccessor.SubKey(this, SubkeyIdentifier(keys.pgpKeyRing, keyId))
.preferredSymmetricKeyAlgorithms
return getPreferredSymmetricKeyAlgorithms(KeyIdentifier(keyId))
}
/** [CompressionAlgorithm] preferences of the given user-ID. */
fun getPreferredCompressionAlgorithms(userId: CharSequence): Set<CompressionAlgorithm> {
return getKeyAccessor(userId, keyIdentifier).preferredCompressionAlgorithms
return keys
.getUserId(userId.toString())
?.getCompressionAlgorithmPreferences(referenceDate)
?.toCompressionAlgorithms()
?: throw NoSuchElementException("No user-id '$userId' found on this key.")
}
fun getPreferredCompressionAlgorithms(keyIdentifier: KeyIdentifier): Set<CompressionAlgorithm> {
return getPreferredCompressionAlgorithms(keyIdentifier.keyId)
return keys
.getKey(keyIdentifier)
?.getCompressionAlgorithmPreferences(referenceDate)
?.toCompressionAlgorithms()
?: throw NoSuchElementException(
"No subkey with key-id $keyIdentifier found on this key.")
}
/** [CompressionAlgorithm] preferences of the given key. */
fun getPreferredCompressionAlgorithms(keyId: Long): Set<CompressionAlgorithm> {
return KeyAccessor.SubKey(this, SubkeyIdentifier(keys.pgpKeyRing, keyId))
.preferredCompressionAlgorithms
return getPreferredCompressionAlgorithms(KeyIdentifier(keyId))
}
fun getPreferredAEADCipherSuites(userId: CharSequence): Set<AEADCipherMode> {
return keys
.getUserId(userId.toString())
?.getAEADCipherSuitePreferences(referenceDate)
?.toAEADCipherModes()
?: throw NoSuchElementException("No user-id '$userId' found on this key.")
}
fun getPreferredAEADCipherSuites(keyIdentifier: KeyIdentifier): Set<AEADCipherMode> {
return keys
.getKey(keyIdentifier)
?.getAEADCipherSuitePreferences(referenceDate)
?.toAEADCipherModes()
?: throw NoSuchElementException(
"No subkey with key-id $keyIdentifier found on this key.")
}
@Deprecated("Pass KeyIdentifier instead.")
fun getPreferredAEADCipherSuites(keyId: Long): Set<AEADCipherMode> {
return getPreferredAEADCipherSuites(KeyIdentifier(keyId))
}
val isUsableForThirdPartyCertification: Boolean =
isKeyValidlyBound(keyIdentifier) &&
getKeyFlagsOf(keyIdentifier).contains(KeyFlag.CERTIFY_OTHER)
private fun getKeyAccessor(userId: CharSequence?, keyIdentifier: KeyIdentifier): KeyAccessor {
if (getPublicKey(keyIdentifier) == null) {
throw NoSuchElementException("No subkey with key-id $keyIdentifier found on this key.")
}
if (userId != null && !userIds.contains(userId)) {
throw NoSuchElementException("No user-id '$userId' found on this key.")
}
return if (userId != null) {
KeyAccessor.ViaUserId(
this, SubkeyIdentifier(keys.pgpKeyRing, keyIdentifier.keyId), userId)
} else {
KeyAccessor.ViaKeyId(this, SubkeyIdentifier(keys.pgpKeyRing, keyIdentifier.keyId))
}
}
companion object {
/** Evaluate the key for the given signature. */

View file

@ -269,6 +269,15 @@ class SignatureSubpacketsUtil {
?.toSet()
?: setOf()
@JvmStatic
fun parsePreferredAEADCipherSuites(signature: PGPSignature): Set<AEADCipherMode> =
getPreferredAeadAlgorithms(signature)
?.algorithms
?.asSequence()
?.map { AEADCipherMode(it) }
?.toSet()
?: setOf()
@JvmStatic
fun getPreferredAeadAlgorithms(signature: PGPSignature): PreferredAEADCiphersuites? =
hashed(signature, SignatureSubpacket.preferredAEADAlgorithms)