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

Implement applying algorithm preferences as extension functions

This commit is contained in:
Paul Schaub 2025-03-06 11:41:36 +01:00
parent deaf9fa404
commit 4dadc7c445
Signed by: vanitasvitae
GPG key ID: 62BEE9264BF17311
4 changed files with 130 additions and 109 deletions

View file

@ -19,7 +19,7 @@ import org.bouncycastle.openpgp.api.OpenPGPKeyReader
import org.bouncycastle.openpgp.api.bc.BcOpenPGPApi
import org.pgpainless.algorithm.OpenPGPKeyVersion
import org.pgpainless.bouncycastle.PolicyAdapter
import org.pgpainless.bouncycastle.helpers.SignatureSubpacketsFunctionHelper
import org.pgpainless.bouncycastle.extensions.setAlgorithmSuite
import org.pgpainless.decryption_verification.DecryptionBuilder
import org.pgpainless.encryption_signing.EncryptionBuilder
import org.pgpainless.key.certification.CertifyCertificate
@ -58,24 +58,7 @@ class PGPainless(
): OpenPGPKeyGenerator =
OpenPGPKeyGenerator(
implementation, version.numeric, version == OpenPGPKeyVersion.v6, creationTime)
.apply {
val genAlgs = algorithmPolicy.keyGenerationAlgorithmSuite
// Set default algorithm preferences from AlgorithmSuite
setDefaultFeatures(
SignatureSubpacketsFunctionHelper.applyFeatures(true, genAlgs.features))
setDefaultSymmetricKeyPreferences(
SignatureSubpacketsFunctionHelper.applySymmetricAlgorithmPreferences(
true, genAlgs.symmetricKeyAlgorithms))
setDefaultHashAlgorithmPreferences(
SignatureSubpacketsFunctionHelper.applyHashAlgorithmPreferences(
true, genAlgs.hashAlgorithms))
setDefaultCompressionAlgorithmPreferences(
SignatureSubpacketsFunctionHelper.applyCompressionAlgorithmPreferences(
true, genAlgs.compressionAlgorithms))
setDefaultAeadAlgorithmPreferences(
SignatureSubpacketsFunctionHelper.applyAEADAlgorithmSuites(
false, genAlgs.aeadAlgorithms))
}
.setAlgorithmSuite(algorithmPolicy.keyGenerationAlgorithmSuite)
fun readKey(): OpenPGPKeyReader = api.readKeyOrCertificate()

View file

@ -0,0 +1,126 @@
// 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.bouncycastle.openpgp.api.OpenPGPKeyGenerator
import org.pgpainless.algorithm.AEADCipherMode
import org.pgpainless.algorithm.AlgorithmSuite
import org.pgpainless.algorithm.CompressionAlgorithm
import org.pgpainless.algorithm.Feature
import org.pgpainless.algorithm.HashAlgorithm
import org.pgpainless.algorithm.SymmetricKeyAlgorithm
/**
* Apply different algorithm preferences (features, symmetric-key-, hash-, compression- and AEAD
* algorithm preferences to the [OpenPGPKeyGenerator] for key generation. The preferences will be
* set on preference-signatures on the generated keys.
*
* @param algorithms algorithm suite
* @return this
*/
fun OpenPGPKeyGenerator.setAlgorithmSuite(algorithms: AlgorithmSuite): OpenPGPKeyGenerator {
setDefaultFeatures(true, algorithms.features)
setDefaultSymmetricKeyPreferences(true, algorithms.symmetricKeyAlgorithms)
setDefaultHashAlgorithmPreferences(true, algorithms.hashAlgorithms)
setDefaultCompressionAlgorithmPreferences(true, algorithms.compressionAlgorithms)
setDefaultAeadAlgorithmPreferences(false, algorithms.aeadAlgorithms)
return this
}
fun OpenPGPKeyGenerator.setDefaultFeatures(
critical: Boolean = true,
features: Set<Feature>
): OpenPGPKeyGenerator {
this.setDefaultFeatures {
val b = Feature.toBitmask(*features.toTypedArray())
it.apply { setFeature(critical, b) }
}
return this
}
/**
* Define [SymmetricKeyAlgorithms][SymmetricKeyAlgorithm] that will be applied as symmetric key
* algorithm preferences to preference-signatures on freshly generated keys.
*
* @param critical whether to mark the preference subpacket as critical
* @param symmetricKeyAlgorithms ordered set of preferred symmetric key algorithms
* @return this
*/
fun OpenPGPKeyGenerator.setDefaultSymmetricKeyPreferences(
critical: Boolean = true,
symmetricKeyAlgorithms: Set<SymmetricKeyAlgorithm>?
): OpenPGPKeyGenerator = apply {
symmetricKeyAlgorithms?.let { algorithms ->
this.setDefaultSymmetricKeyPreferences {
val algorithmIds = algorithms.map { a -> a.algorithmId }.toIntArray()
it.apply { setPreferredSymmetricAlgorithms(critical, algorithmIds) }
}
}
}
/**
* Define [HashAlgorithms][HashAlgorithm] that will be applied as hash algorithm preferences to
* preference-signatures on freshly generated keys.
*
* @param critical whether to mark the preference subpacket as critical
* @param hashAlgorithms ordered set of preferred hash algorithms
* @return this
*/
fun OpenPGPKeyGenerator.setDefaultHashAlgorithmPreferences(
critical: Boolean = true,
hashAlgorithms: Set<HashAlgorithm>?
): OpenPGPKeyGenerator = apply {
hashAlgorithms?.let { algorithms ->
this.setDefaultHashAlgorithmPreferences {
val algorithmIds = algorithms.map { a -> a.algorithmId }.toIntArray()
it.apply { setPreferredHashAlgorithms(critical, algorithmIds) }
}
}
}
/**
* Define [CompressionAlgorithms][CompressionAlgorithm] that will be applied as compression
* algorithm preferences to preference-signatures on freshly generated keys.
*
* @param critical whether to mark the preference subpacket as critical
* @param compressionAlgorithms ordered set of preferred compression algorithms
* @return this
*/
fun OpenPGPKeyGenerator.setDefaultCompressionAlgorithmPreferences(
critical: Boolean = true,
compressionAlgorithms: Set<CompressionAlgorithm>?
): OpenPGPKeyGenerator = apply {
compressionAlgorithms?.let { algorithms ->
this.setDefaultCompressionAlgorithmPreferences {
val algorithmIds = algorithms.map { a -> a.algorithmId }.toIntArray()
it.apply { setPreferredCompressionAlgorithms(critical, algorithmIds) }
}
}
}
/**
* Define [AEADCipherModes][AEADCipherMode] that will be applied as AEAD algorithm preferences to
* preference signatures on freshly generated keys.
*
* @param critical whether to mark the preferences subpacket as critical
* @param aeadAlgorithms ordered set of AEAD preferences
* @return this
*/
fun OpenPGPKeyGenerator.setDefaultAeadAlgorithmPreferences(
critical: Boolean = false,
aeadAlgorithms: Set<AEADCipherMode>?
): OpenPGPKeyGenerator = apply {
aeadAlgorithms?.let { algorithms ->
this.setDefaultAeadAlgorithmPreferences {
val builder = PreferredAEADCiphersuites.builder(critical)
for (ciphermode: AEADCipherMode in algorithms) {
builder.addCombination(
ciphermode.ciphermode.algorithmId, ciphermode.aeadAlgorithm.algorithmId)
}
it.apply { setPreferredAEADCiphersuites(builder) }
}
}
}

View file

@ -1,90 +0,0 @@
// SPDX-FileCopyrightText: 2025 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package org.pgpainless.bouncycastle.helpers
import org.bouncycastle.bcpg.sig.PreferredAEADCiphersuites
import org.bouncycastle.openpgp.api.SignatureSubpacketsFunction
import org.pgpainless.algorithm.AEADCipherMode
import org.pgpainless.algorithm.CompressionAlgorithm
import org.pgpainless.algorithm.Feature
import org.pgpainless.algorithm.HashAlgorithm
import org.pgpainless.algorithm.SymmetricKeyAlgorithm
class SignatureSubpacketsFunctionHelper {
companion object {
@JvmStatic
fun applySymmetricAlgorithmPreferences(
critical: Boolean = true,
symmetricAlgorithms: Set<SymmetricKeyAlgorithm>?
): SignatureSubpacketsFunction {
return symmetricAlgorithms?.let { algorithms ->
val algorithmIds = algorithms.map { it.algorithmId }.toIntArray()
SignatureSubpacketsFunction {
it.apply { setPreferredSymmetricAlgorithms(critical, algorithmIds) }
}
}
?: SignatureSubpacketsFunction { it }
}
@JvmStatic
fun applyHashAlgorithmPreferences(
critical: Boolean = true,
hashAlgorithms: Set<HashAlgorithm>?
): SignatureSubpacketsFunction {
return hashAlgorithms?.let { algorithms ->
val algorithmIds = algorithms.map { it.algorithmId }.toIntArray()
SignatureSubpacketsFunction {
it.apply { setPreferredHashAlgorithms(critical, algorithmIds) }
}
}
?: SignatureSubpacketsFunction { it }
}
@JvmStatic
fun applyCompressionAlgorithmPreferences(
critical: Boolean = true,
compressionAlgorithms: Set<CompressionAlgorithm>?
): SignatureSubpacketsFunction {
return compressionAlgorithms?.let { algorithms ->
val algorithmIds = algorithms.map { it.algorithmId }.toIntArray()
SignatureSubpacketsFunction {
it.apply { setPreferredCompressionAlgorithms(critical, algorithmIds) }
}
}
?: SignatureSubpacketsFunction { it }
}
@JvmStatic
fun applyAEADAlgorithmSuites(
critical: Boolean = true,
aeadAlgorithms: Set<AEADCipherMode>?
): SignatureSubpacketsFunction {
return aeadAlgorithms?.let { algorithms ->
SignatureSubpacketsFunction {
val builder = PreferredAEADCiphersuites.builder(critical)
for (ciphermode: AEADCipherMode in algorithms) {
builder.addCombination(
ciphermode.ciphermode.algorithmId, ciphermode.aeadAlgorithm.algorithmId)
}
it.apply { setPreferredAEADCiphersuites(builder) }
}
}
?: SignatureSubpacketsFunction { it }
}
@JvmStatic
fun applyFeatures(
critical: Boolean = true,
features: Set<Feature>
): SignatureSubpacketsFunction {
return SignatureSubpacketsFunction {
val b = Feature.toBitmask(*features.toTypedArray())
it.apply { setFeature(critical, b) }
}
}
}
}

View file

@ -96,6 +96,8 @@ public class GenerateV6KeyTest {
OpenPGPCertificate certificate = key.toCertificate();
assertFalse(certificate.isSecretKey());
// CHECKSTYLE:OFF
System.out.println(certificate.toAsciiArmoredString());
// CHECKSTYLE:ON
}
}