mirror of
https://github.com/pgpainless/pgpainless.git
synced 2025-09-09 18:29:39 +02:00
Implement applying algorithm preferences as extension functions
This commit is contained in:
parent
8b5d9af522
commit
f9c2ade2d0
4 changed files with 130 additions and 109 deletions
|
@ -19,7 +19,7 @@ import org.bouncycastle.openpgp.api.OpenPGPKeyReader
|
||||||
import org.bouncycastle.openpgp.api.bc.BcOpenPGPApi
|
import org.bouncycastle.openpgp.api.bc.BcOpenPGPApi
|
||||||
import org.pgpainless.algorithm.OpenPGPKeyVersion
|
import org.pgpainless.algorithm.OpenPGPKeyVersion
|
||||||
import org.pgpainless.bouncycastle.PolicyAdapter
|
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.decryption_verification.DecryptionBuilder
|
||||||
import org.pgpainless.encryption_signing.EncryptionBuilder
|
import org.pgpainless.encryption_signing.EncryptionBuilder
|
||||||
import org.pgpainless.key.certification.CertifyCertificate
|
import org.pgpainless.key.certification.CertifyCertificate
|
||||||
|
@ -58,24 +58,7 @@ class PGPainless(
|
||||||
): OpenPGPKeyGenerator =
|
): OpenPGPKeyGenerator =
|
||||||
OpenPGPKeyGenerator(
|
OpenPGPKeyGenerator(
|
||||||
implementation, version.numeric, version == OpenPGPKeyVersion.v6, creationTime)
|
implementation, version.numeric, version == OpenPGPKeyVersion.v6, creationTime)
|
||||||
.apply {
|
.setAlgorithmSuite(algorithmPolicy.keyGenerationAlgorithmSuite)
|
||||||
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))
|
|
||||||
}
|
|
||||||
|
|
||||||
fun readKey(): OpenPGPKeyReader = api.readKeyOrCertificate()
|
fun readKey(): OpenPGPKeyReader = api.readKeyOrCertificate()
|
||||||
|
|
||||||
|
|
|
@ -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) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -96,6 +96,8 @@ public class GenerateV6KeyTest {
|
||||||
OpenPGPCertificate certificate = key.toCertificate();
|
OpenPGPCertificate certificate = key.toCertificate();
|
||||||
assertFalse(certificate.isSecretKey());
|
assertFalse(certificate.isSecretKey());
|
||||||
|
|
||||||
|
// CHECKSTYLE:OFF
|
||||||
System.out.println(certificate.toAsciiArmoredString());
|
System.out.println(certificate.toAsciiArmoredString());
|
||||||
|
// CHECKSTYLE:ON
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue