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

WIP: EncryptionMechanismPolicy

This commit is contained in:
Paul Schaub 2025-05-20 15:05:24 +02:00
parent de7c2ea633
commit 5c0cdfd494
Signed by: vanitasvitae
GPG key ID: 62BEE9264BF17311
4 changed files with 241 additions and 29 deletions

View file

@ -92,7 +92,8 @@ class PolicyAdapter(val policy: Policy) : OpenPGPPolicy {
* @return boolean indicating, whether the encryption algorithm is acceptable
*/
override fun isAcceptableSymmetricKeyAlgorithm(algorithmId: Int): Boolean {
return policy.symmetricKeyEncryptionAlgorithmPolicy.isAcceptable(algorithmId)
return policy.messageEncryptionAlgorithmPolicy.symmetricAlgorithmPolicy.isAcceptable(
algorithmId)
}
/**
* Return the default symmetric encryption algorithm. This algorithm is used as fallback to
@ -101,7 +102,9 @@ class PolicyAdapter(val policy: Policy) : OpenPGPPolicy {
* @return default symmetric encryption algorithm
*/
override fun getDefaultSymmetricKeyAlgorithm(): Int {
return policy.symmetricKeyEncryptionAlgorithmPolicy.defaultSymmetricKeyAlgorithm.algorithmId
return policy.messageEncryptionAlgorithmPolicy.symmetricAlgorithmPolicy
.defaultSymmetricKeyAlgorithm
.algorithmId
}
/**

View file

@ -739,7 +739,8 @@ class OpenPgpMessageInputStream(
}
private fun isAcceptable(algorithm: SymmetricKeyAlgorithm): Boolean =
api.algorithmPolicy.symmetricKeyDecryptionAlgorithmPolicy.isAcceptable(algorithm)
api.algorithmPolicy.messageDecryptionAlgorithmPolicy.symmetricAlgorithmPolicy.isAcceptable(
algorithm)
private fun throwIfUnacceptable(algorithm: SymmetricKeyAlgorithm) {
if (!isAcceptable(algorithm)) {

View file

@ -404,8 +404,8 @@ class EncryptionOptions(private val purpose: EncryptionPurpose, private val api:
fun overrideEncryptionMechanism(encryptionMechanism: MessageEncryptionMechanism) = apply {
require(
api.algorithmPolicy.symmetricKeyEncryptionAlgorithmPolicy.isAcceptable(
encryptionMechanism.symmetricKeyAlgorithm)) {
api.algorithmPolicy.messageEncryptionAlgorithmPolicy.isAcceptable(
encryptionMechanism)) {
"Provided symmetric encryption algorithm is not acceptable."
}
_encryptionMechanismOverride = encryptionMechanism
@ -431,7 +431,7 @@ class EncryptionOptions(private val purpose: EncryptionPurpose, private val api:
val algorithm =
byPopularity()
.negotiate(
api.algorithmPolicy.symmetricKeyEncryptionAlgorithmPolicy,
api.algorithmPolicy.messageEncryptionAlgorithmPolicy.symmetricAlgorithmPolicy,
encryptionAlgorithmOverride,
preferences)
return algorithm

View file

@ -5,23 +5,77 @@
package org.pgpainless.policy
import java.util.*
import org.bouncycastle.openpgp.api.EncryptedDataPacketType
import org.bouncycastle.openpgp.api.MessageEncryptionMechanism
import org.pgpainless.algorithm.*
import org.pgpainless.key.protection.KeyRingProtectionSettings
import org.pgpainless.util.DateUtil
import org.pgpainless.util.NotationRegistry
class Policy(
val certificationSignatureHashAlgorithmPolicy: HashAlgorithmPolicy,
val revocationSignatureHashAlgorithmPolicy: HashAlgorithmPolicy,
val dataSignatureHashAlgorithmPolicy: HashAlgorithmPolicy,
val symmetricKeyEncryptionAlgorithmPolicy: SymmetricKeyAlgorithmPolicy,
val symmetricKeyDecryptionAlgorithmPolicy: SymmetricKeyAlgorithmPolicy,
val compressionAlgorithmPolicy: CompressionAlgorithmPolicy,
val publicKeyAlgorithmPolicy: PublicKeyAlgorithmPolicy,
val keyProtectionSettings: KeyRingProtectionSettings,
val notationRegistry: NotationRegistry,
class Policy {
val certificationSignatureHashAlgorithmPolicy: HashAlgorithmPolicy
val revocationSignatureHashAlgorithmPolicy: HashAlgorithmPolicy
val dataSignatureHashAlgorithmPolicy: HashAlgorithmPolicy
val messageEncryptionAlgorithmPolicy: MessageEncryptionMechanismPolicy
val messageDecryptionAlgorithmPolicy: MessageEncryptionMechanismPolicy
val compressionAlgorithmPolicy: CompressionAlgorithmPolicy
val publicKeyAlgorithmPolicy: PublicKeyAlgorithmPolicy
val keyProtectionSettings: KeyRingProtectionSettings
val notationRegistry: NotationRegistry
val keyGenerationAlgorithmSuite: AlgorithmSuite
) {
constructor(
certificationSignatureHashAlgorithmPolicy: HashAlgorithmPolicy,
revocationSignatureHashAlgorithmPolicy: HashAlgorithmPolicy,
dataSignatureHashAlgorithmPolicy: HashAlgorithmPolicy,
messageEncryptionMechanismPolicy: MessageEncryptionMechanismPolicy,
messageDecryptionMechanismPolicy: MessageEncryptionMechanismPolicy,
compressionAlgorithmPolicy: CompressionAlgorithmPolicy,
publicKeyAlgorithmPolicy: PublicKeyAlgorithmPolicy,
keyProtectionSettings: KeyRingProtectionSettings,
notationRegistry: NotationRegistry,
keyGenerationAlgorithmSuite: AlgorithmSuite
) {
this.certificationSignatureHashAlgorithmPolicy = certificationSignatureHashAlgorithmPolicy
this.revocationSignatureHashAlgorithmPolicy = revocationSignatureHashAlgorithmPolicy
this.dataSignatureHashAlgorithmPolicy = dataSignatureHashAlgorithmPolicy
this.messageEncryptionAlgorithmPolicy = messageEncryptionMechanismPolicy
this.messageDecryptionAlgorithmPolicy = messageDecryptionMechanismPolicy
this.compressionAlgorithmPolicy = compressionAlgorithmPolicy
this.publicKeyAlgorithmPolicy = publicKeyAlgorithmPolicy
this.keyProtectionSettings = keyProtectionSettings
this.notationRegistry = notationRegistry
this.keyGenerationAlgorithmSuite = keyGenerationAlgorithmSuite
}
constructor(
certificationSignatureHashAlgorithmPolicy: HashAlgorithmPolicy,
revocationSignatureHashAlgorithmPolicy: HashAlgorithmPolicy,
dataSignatureHashAlgorithmPolicy: HashAlgorithmPolicy,
symmetricKeyEncryptionAlgorithmPolicy: SymmetricKeyAlgorithmPolicy,
symmetricKeyDecryptionAlgorithmPolicy: SymmetricKeyAlgorithmPolicy,
compressionAlgorithmPolicy: CompressionAlgorithmPolicy,
publicKeyAlgorithmPolicy: PublicKeyAlgorithmPolicy,
keyProtectionSettings: KeyRingProtectionSettings,
notationRegistry: NotationRegistry,
keyGenerationAlgorithmSuite: AlgorithmSuite
) {
this.certificationSignatureHashAlgorithmPolicy = certificationSignatureHashAlgorithmPolicy
this.revocationSignatureHashAlgorithmPolicy = revocationSignatureHashAlgorithmPolicy
this.dataSignatureHashAlgorithmPolicy = dataSignatureHashAlgorithmPolicy
this.messageEncryptionAlgorithmPolicy =
MessageEncryptionMechanismPolicy.rfc4880Plus9580PlusLibrePGP(
symmetricKeyEncryptionAlgorithmPolicy)
this.messageDecryptionAlgorithmPolicy =
MessageEncryptionMechanismPolicy.rfc4880Plus9580PlusLibrePGP(
symmetricKeyDecryptionAlgorithmPolicy)
this.compressionAlgorithmPolicy = compressionAlgorithmPolicy
this.publicKeyAlgorithmPolicy = publicKeyAlgorithmPolicy
this.keyProtectionSettings = keyProtectionSettings
this.notationRegistry = notationRegistry
this.keyGenerationAlgorithmSuite = keyGenerationAlgorithmSuite
}
constructor() :
this(
@ -36,6 +90,14 @@ class Policy(
NotationRegistry(),
AlgorithmSuite.defaultAlgorithmSuite)
@Deprecated("Deprecated in favor of messageEncryptionAlgorithmPolicy")
val symmetricKeyEncryptionAlgorithmPolicy
get() = messageEncryptionAlgorithmPolicy.symmetricAlgorithmPolicy
@Deprecated("Deprecated in favor of messageDecryptionAlgorithmPolicy")
val symmetricKeyDecryptionAlgorithmPolicy
get() = messageDecryptionAlgorithmPolicy.symmetricAlgorithmPolicy
/**
* Decide, whether to sanitize public key parameters when unlocking OpenPGP secret keys. OpenPGP
* v4 keys are susceptible to a class of attacks, where an attacker with access to the locked
@ -189,6 +251,138 @@ class Policy(
}
}
abstract class MessageEncryptionMechanismPolicy(
val symmetricAlgorithmPolicy: SymmetricKeyAlgorithmPolicy,
val asymmetricFallbackMechanism: MessageEncryptionMechanism,
val symmetricFallbackMechanism: MessageEncryptionMechanism = asymmetricFallbackMechanism
) {
abstract fun isAcceptable(encryptionMechanism: MessageEncryptionMechanism): Boolean
companion object {
@JvmStatic
fun rfc4880(
symAlgPolicy: SymmetricKeyAlgorithmPolicy
): MessageEncryptionMechanismPolicy {
return object :
MessageEncryptionMechanismPolicy(
symAlgPolicy,
MessageEncryptionMechanism.integrityProtected(
symAlgPolicy.defaultSymmetricKeyAlgorithm.algorithmId)) {
override fun isAcceptable(
encryptionMechanism: MessageEncryptionMechanism
): Boolean {
return encryptionMechanism.mode == EncryptedDataPacketType.SEIPDv1 &&
symAlgPolicy.isAcceptable(encryptionMechanism.symmetricKeyAlgorithm)
}
}
}
@JvmStatic
fun rfc9580(
symAlgPolicy: SymmetricKeyAlgorithmPolicy
): MessageEncryptionMechanismPolicy {
return object :
MessageEncryptionMechanismPolicy(
symAlgPolicy,
MessageEncryptionMechanism.aead(
symAlgPolicy.defaultSymmetricKeyAlgorithm.algorithmId,
AEADAlgorithm.OCB.algorithmId)) {
val acceptableAEADAlgorithms =
listOf(AEADAlgorithm.OCB, AEADAlgorithm.GCM, AEADAlgorithm.EAX).map {
it.algorithmId
}
override fun isAcceptable(
encryptionMechanism: MessageEncryptionMechanism
): Boolean {
return when (encryptionMechanism.mode) {
EncryptedDataPacketType.SEIPDv1 ->
symAlgPolicy.isAcceptable(encryptionMechanism.symmetricKeyAlgorithm)
EncryptedDataPacketType.SEIPDv2 ->
symAlgPolicy.isAcceptable(
encryptionMechanism.symmetricKeyAlgorithm) &&
acceptableAEADAlgorithms.contains(
encryptionMechanism.aeadAlgorithm)
else -> false
}
}
}
}
@JvmStatic
fun librePgp(
symAlgPolicy: SymmetricKeyAlgorithmPolicy
): MessageEncryptionMechanismPolicy {
return object :
MessageEncryptionMechanismPolicy(
symAlgPolicy,
MessageEncryptionMechanism.integrityProtected(
symAlgPolicy.defaultSymmetricKeyAlgorithm.algorithmId)) {
val acceptableAEADAlgorithms = listOf(AEADAlgorithm.OCB).map { it.algorithmId }
override fun isAcceptable(
encryptionMechanism: MessageEncryptionMechanism
): Boolean {
return when (encryptionMechanism.mode) {
EncryptedDataPacketType.SEIPDv1 ->
symAlgPolicy.isAcceptable(encryptionMechanism.symmetricKeyAlgorithm)
EncryptedDataPacketType.LIBREPGP_OED ->
symAlgPolicy.isAcceptable(
encryptionMechanism.symmetricKeyAlgorithm) &&
acceptableAEADAlgorithms.contains(
encryptionMechanism.aeadAlgorithm)
else -> false
}
}
}
}
@JvmStatic
fun rfc4880Plus9580(
symAlgPolicy: SymmetricKeyAlgorithmPolicy
): MessageEncryptionMechanismPolicy {
val rfc4880 = rfc4880(symAlgPolicy)
val rfc9580 = rfc9580(symAlgPolicy)
return object :
MessageEncryptionMechanismPolicy(
symAlgPolicy,
rfc4880.asymmetricFallbackMechanism,
rfc4880.symmetricFallbackMechanism) {
override fun isAcceptable(
encryptionMechanism: MessageEncryptionMechanism
): Boolean {
return rfc9580.isAcceptable(encryptionMechanism) ||
rfc4880.isAcceptable(encryptionMechanism)
}
}
}
@JvmStatic
fun rfc4880Plus9580PlusLibrePGP(
symAlgPolicy: SymmetricKeyAlgorithmPolicy
): MessageEncryptionMechanismPolicy {
return object :
MessageEncryptionMechanismPolicy(
symAlgPolicy,
MessageEncryptionMechanism.integrityProtected(
symAlgPolicy.defaultSymmetricKeyAlgorithm.algorithmId)) {
override fun isAcceptable(
encryptionMechanism: MessageEncryptionMechanism
): Boolean {
val rfc4480 = rfc4880(symAlgPolicy)
val rfc9580 = rfc9580(symAlgPolicy)
val librePgp = librePgp(symAlgPolicy)
return rfc4480.isAcceptable(encryptionMechanism) ||
rfc9580.isAcceptable(encryptionMechanism) ||
librePgp.isAcceptable(encryptionMechanism)
}
}
}
}
}
class SymmetricKeyAlgorithmPolicy(
val defaultSymmetricKeyAlgorithm: SymmetricKeyAlgorithm,
val acceptableSymmetricKeyAlgorithms: List<SymmetricKeyAlgorithm>
@ -440,10 +634,10 @@ class Policy(
origin.revocationSignatureHashAlgorithmPolicy
private var dataSignatureHashAlgorithmPolicy: HashAlgorithmPolicy =
origin.dataSignatureHashAlgorithmPolicy
private var symmetricKeyEncryptionAlgorithmPolicy: SymmetricKeyAlgorithmPolicy =
origin.symmetricKeyEncryptionAlgorithmPolicy
private var symmetricKeyDecryptionAlgorithmPolicy: SymmetricKeyAlgorithmPolicy =
origin.symmetricKeyDecryptionAlgorithmPolicy
private var messageEncryptionMechanismPolicy: MessageEncryptionMechanismPolicy =
origin.messageEncryptionAlgorithmPolicy
private var messageDecryptionMechanismPolicy: MessageEncryptionMechanismPolicy =
origin.messageDecryptionAlgorithmPolicy
private var compressionAlgorithmPolicy: CompressionAlgorithmPolicy =
origin.compressionAlgorithmPolicy
private var publicKeyAlgorithmPolicy: PublicKeyAlgorithmPolicy =
@ -469,17 +663,31 @@ class Policy(
dataSignatureHashAlgorithmPolicy: HashAlgorithmPolicy
) = apply { this.dataSignatureHashAlgorithmPolicy = dataSignatureHashAlgorithmPolicy }
@Deprecated(
"Usage of SymmetricKeyAlgorithmPolicy is deprecated in favor of MessageEncryptionMechanismPolicy.")
fun withSymmetricKeyEncryptionAlgorithmPolicy(
symmetricKeyEncryptionAlgorithmPolicy: SymmetricKeyAlgorithmPolicy
) = apply {
this.symmetricKeyEncryptionAlgorithmPolicy = symmetricKeyEncryptionAlgorithmPolicy
}
) =
withMessageEncryptionAlgorithmPolicy(
MessageEncryptionMechanismPolicy.rfc4880Plus9580PlusLibrePGP(
symmetricKeyEncryptionAlgorithmPolicy))
@Deprecated(
"Usage of SymmetricKeyAlgorithmPolicy is deprecated in favor of MessageEncryptionMechanismPolicy.")
fun withSymmetricKeyDecryptionAlgorithmPolicy(
symmetricKeyDecryptionAlgorithmPolicy: SymmetricKeyAlgorithmPolicy
) = apply {
this.symmetricKeyDecryptionAlgorithmPolicy = symmetricKeyDecryptionAlgorithmPolicy
}
) =
withMessageDecryptionAlgorithmPolicy(
MessageEncryptionMechanismPolicy.rfc4880Plus9580PlusLibrePGP(
symmetricKeyDecryptionAlgorithmPolicy))
fun withMessageEncryptionAlgorithmPolicy(
encryptionMechanismPolicy: MessageEncryptionMechanismPolicy
) = apply { messageEncryptionMechanismPolicy = encryptionMechanismPolicy }
fun withMessageDecryptionAlgorithmPolicy(
decryptionMechanismPolicy: MessageEncryptionMechanismPolicy
) = apply { messageDecryptionMechanismPolicy = decryptionMechanismPolicy }
fun withCompressionAlgorithmPolicy(compressionAlgorithmPolicy: CompressionAlgorithmPolicy) =
apply {
@ -508,8 +716,8 @@ class Policy(
certificationSignatureHashAlgorithmPolicy,
revocationSignatureHashAlgorithmPolicy,
dataSignatureHashAlgorithmPolicy,
symmetricKeyEncryptionAlgorithmPolicy,
symmetricKeyDecryptionAlgorithmPolicy,
messageEncryptionMechanismPolicy,
messageDecryptionMechanismPolicy,
compressionAlgorithmPolicy,
publicKeyAlgorithmPolicy,
keyProtectionSettings,