mirror of
https://github.com/pgpainless/pgpainless.git
synced 2024-12-25 12:27:58 +01:00
Kotlin conversion: SymmetricKeyAlgorithmNegotiator
This commit is contained in:
parent
32aaf59f43
commit
65bd953d65
2 changed files with 77 additions and 105 deletions
|
@ -1,105 +0,0 @@
|
||||||
// SPDX-FileCopyrightText: 2021 Paul Schaub <vanitasvitae@fsfe.org>
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
package org.pgpainless.algorithm.negotiation;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import org.pgpainless.algorithm.SymmetricKeyAlgorithm;
|
|
||||||
import org.pgpainless.policy.Policy;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Interface for symmetric key algorithm negotiation.
|
|
||||||
*/
|
|
||||||
public interface SymmetricKeyAlgorithmNegotiator {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Negotiate a symmetric encryption algorithm.
|
|
||||||
* If the override is non-null, it will be returned instead of performing an actual negotiation.
|
|
||||||
* Otherwise, the list of ordered sets containing the preferences of different recipient keys will be
|
|
||||||
* used to determine a suitable symmetric encryption algorithm.
|
|
||||||
*
|
|
||||||
* @param policy algorithm policy
|
|
||||||
* @param override algorithm override (if not null, return this)
|
|
||||||
* @param keyPreferences list of preferences per key
|
|
||||||
* @return negotiated algorithm
|
|
||||||
*/
|
|
||||||
SymmetricKeyAlgorithm negotiate(
|
|
||||||
Policy.SymmetricKeyAlgorithmPolicy policy,
|
|
||||||
SymmetricKeyAlgorithm override,
|
|
||||||
List<Set<SymmetricKeyAlgorithm>> keyPreferences);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return an instance that negotiates a {@link SymmetricKeyAlgorithm} by selecting the most popular acceptable
|
|
||||||
* algorithm from the list of preferences.
|
|
||||||
*
|
|
||||||
* This negotiator has the best chances to select an algorithm which is understood by all recipients.
|
|
||||||
*
|
|
||||||
* @return negotiator that selects by popularity
|
|
||||||
*/
|
|
||||||
static SymmetricKeyAlgorithmNegotiator byPopularity() {
|
|
||||||
return new SymmetricKeyAlgorithmNegotiator() {
|
|
||||||
@Override
|
|
||||||
public SymmetricKeyAlgorithm negotiate(
|
|
||||||
Policy.SymmetricKeyAlgorithmPolicy policy,
|
|
||||||
SymmetricKeyAlgorithm override,
|
|
||||||
List<Set<SymmetricKeyAlgorithm>> preferences) {
|
|
||||||
if (override == SymmetricKeyAlgorithm.NULL) {
|
|
||||||
throw new IllegalArgumentException("Algorithm override cannot be NULL (plaintext).");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (override != null) {
|
|
||||||
return override;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Count score (occurrences) of each algorithm
|
|
||||||
Map<SymmetricKeyAlgorithm, Integer> supportWeight = new LinkedHashMap<>();
|
|
||||||
for (Set<SymmetricKeyAlgorithm> keyPreferences : preferences) {
|
|
||||||
for (SymmetricKeyAlgorithm preferred : keyPreferences) {
|
|
||||||
if (supportWeight.containsKey(preferred)) {
|
|
||||||
supportWeight.put(preferred, supportWeight.get(preferred) + 1);
|
|
||||||
} else {
|
|
||||||
supportWeight.put(preferred, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pivot the score map
|
|
||||||
Map<Integer, List<SymmetricKeyAlgorithm>> byScore = new HashMap<>();
|
|
||||||
for (SymmetricKeyAlgorithm algorithm : supportWeight.keySet()) {
|
|
||||||
int score = supportWeight.get(algorithm);
|
|
||||||
List<SymmetricKeyAlgorithm> withSameScore = byScore.get(score);
|
|
||||||
if (withSameScore == null) {
|
|
||||||
withSameScore = new ArrayList<>();
|
|
||||||
byScore.put(score, withSameScore);
|
|
||||||
}
|
|
||||||
withSameScore.add(algorithm);
|
|
||||||
}
|
|
||||||
|
|
||||||
List<Integer> scores = new ArrayList<>(byScore.keySet());
|
|
||||||
|
|
||||||
// Sort map and iterate from highest to lowest score
|
|
||||||
Collections.sort(scores);
|
|
||||||
for (int i = scores.size() - 1; i >= 0; i--) {
|
|
||||||
int score = scores.get(i);
|
|
||||||
List<SymmetricKeyAlgorithm> withSameScore = byScore.get(score);
|
|
||||||
// Select best algorithm
|
|
||||||
SymmetricKeyAlgorithm best = policy.selectBest(withSameScore);
|
|
||||||
if (best != null) {
|
|
||||||
return best;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If no algorithm is acceptable, choose fallback
|
|
||||||
return policy.getDefaultSymmetricKeyAlgorithm();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,77 @@
|
||||||
|
// SPDX-FileCopyrightText: 2023 Paul Schaub <vanitasvitae@fsfe.org>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package org.pgpainless.algorithm.negotiation
|
||||||
|
|
||||||
|
import org.pgpainless.algorithm.SymmetricKeyAlgorithm
|
||||||
|
import org.pgpainless.policy.Policy
|
||||||
|
import java.lang.IllegalArgumentException
|
||||||
|
|
||||||
|
interface SymmetricKeyAlgorithmNegotiator {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Negotiate a symmetric encryption algorithm.
|
||||||
|
* If the override is non-null, it will be returned instead of performing an actual negotiation.
|
||||||
|
* Otherwise, the list of ordered sets containing the preferences of different recipient keys will be
|
||||||
|
* used to determine a suitable symmetric encryption algorithm.
|
||||||
|
*
|
||||||
|
* @param policy algorithm policy
|
||||||
|
* @param override algorithm override (if not null, return this)
|
||||||
|
* @param keyPreferences list of preferences per key
|
||||||
|
* @return negotiated algorithm
|
||||||
|
*/
|
||||||
|
fun negotiate(policy: Policy.SymmetricKeyAlgorithmPolicy,
|
||||||
|
override: SymmetricKeyAlgorithm?,
|
||||||
|
keyPreferences: List<Set<SymmetricKeyAlgorithm>>): SymmetricKeyAlgorithm
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
@JvmStatic
|
||||||
|
fun byPopularity(): SymmetricKeyAlgorithmNegotiator {
|
||||||
|
return object: SymmetricKeyAlgorithmNegotiator {
|
||||||
|
override fun negotiate(
|
||||||
|
policy: Policy.SymmetricKeyAlgorithmPolicy,
|
||||||
|
override: SymmetricKeyAlgorithm?,
|
||||||
|
keyPreferences: List<Set<SymmetricKeyAlgorithm>>):
|
||||||
|
SymmetricKeyAlgorithm {
|
||||||
|
if (override == SymmetricKeyAlgorithm.NULL) {
|
||||||
|
throw IllegalArgumentException("Algorithm override cannot be NULL (plaintext).")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (override != null) {
|
||||||
|
return override
|
||||||
|
}
|
||||||
|
|
||||||
|
// algorithm to #occurrences
|
||||||
|
val supportWeight = buildMap {
|
||||||
|
keyPreferences.forEach { keyPreference ->
|
||||||
|
keyPreference.forEach { pref ->
|
||||||
|
put(pref, getOrDefault(pref, 0) as Int + 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pivot map and sort by popularity ascending
|
||||||
|
// score to list(algo)
|
||||||
|
val byScore = supportWeight.toList()
|
||||||
|
.map { e -> e.second to e.first }
|
||||||
|
.groupBy { e -> e.first }
|
||||||
|
.map { e -> e.key to e.value.map { it.second }.toList() }
|
||||||
|
.associate { e -> e }
|
||||||
|
.toSortedMap()
|
||||||
|
|
||||||
|
// iterate in reverse over algorithms
|
||||||
|
for (e in byScore.entries.reversed()) {
|
||||||
|
val best = policy.selectBest(e.value)
|
||||||
|
if (best != null) {
|
||||||
|
return best
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return policy.defaultSymmetricKeyAlgorithm
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue