From 2b4559884f3c076fe2b34fe48fc2f92cfb24eea4 Mon Sep 17 00:00:00 2001 From: Leo Galambos Date: Thu, 25 Dec 2025 17:43:00 +0100 Subject: [PATCH] fix: add SLH-DSA security strength estimation for policy enforcement Extend SecurityStrengthAdvisor to recognize SLH-DSA keys and map their parameter sets (128/192/256) to NIST security strengths. This enables CryptoPolicy.minStrength(...) to enforce SLH-DSA profiles consistently with other PQC algorithms. Signed-off-by: Leo Galambos --- .../core/policy/SecurityStrengthAdvisor.java | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/lib/src/main/java/zeroecho/core/policy/SecurityStrengthAdvisor.java b/lib/src/main/java/zeroecho/core/policy/SecurityStrengthAdvisor.java index dcf9aed..6dc2b7f 100644 --- a/lib/src/main/java/zeroecho/core/policy/SecurityStrengthAdvisor.java +++ b/lib/src/main/java/zeroecho/core/policy/SecurityStrengthAdvisor.java @@ -70,6 +70,8 @@ import javax.crypto.SecretKey; * {@code key.getAlgorithm()} (for example, 512, 768, 1024 for ML-KEM; * 640/976/1344 for FrodoKEM) or from NIST security levels labeled as L1/L3/L5. * If neither is present, defaults to 128. + *
  • SLH-DSA: parse 128/192/256 from {@code key.getAlgorithm()} + * similarly to SPHINCS+; else default 128.
  • *
  • SPHINCS+: parses the parameter size 128/192/256 from the algorithm * string; otherwise defaults to 128.
  • *
  • EdDSA: returns fixed strengths (Ed25519 -> 128, Ed448 -> @@ -122,6 +124,7 @@ public final class SecurityStrengthAdvisor { // NOPMD private static final Pattern SPHINCS_STRENGTH_PATTERN = Pattern.compile("(128|192|256)"); private static final Pattern HMAC_SHA_PATTERN = Pattern.compile("HMAC(?:-)?SHA(?:-)?(1|224|256|384|512)", Pattern.CASE_INSENSITIVE); + private static final Pattern SLHDSA_STRENGTH_PATTERN = Pattern.compile("(128|192|256)"); private SecurityStrengthAdvisor() { } @@ -161,6 +164,7 @@ public final class SecurityStrengthAdvisor { // NOPMD case "NTRU" -> ntruStrength(key); case "SNTRUPRIME" -> sntruPrimeStrength(key); case "NTRULPRIME" -> ntruLPrimeStrength(key); + case "SLH-DSA", "SLHDSA" -> slhDsaStrength(key); case "SPHINCS+", "SPHINCSPLUS" -> sphincsPlusStrength(key); case "DIGEST" -> 128; default -> 128; @@ -356,6 +360,31 @@ public final class SecurityStrengthAdvisor { // NOPMD return 128; } + private static int slhDsaStrength(Key key) { + // Provider strings observed: "SLH-DSA-SHAKE-128S", "slh-dsa-sha2-192f", + // sometimes with separators or additional tokens. We normalize and then parse. + String a = safeAlgo(key); + String normalized = a.toLowerCase(Locale.ROOT).replace('_', '-'); + + // Prefer explicit numeric strength markers (128/192/256) in the algorithm name. + Matcher m = SLHDSA_STRENGTH_PATTERN.matcher(normalized); + if (m.find()) { + int v = parseIntSafe(m.group(1)); + if (v == 128 || v == 192 || v == 256) { + return v; + } + } + + // Fall back to L1/L3/L5 markers when present. + int byLevel = mapByNistLevel(key, 128, 192, 256); + if (byLevel != 0) { + return byLevel; + } + + // Conservative default. + return 128; + } + private static int mapByNistLevel(Key key, int l1, int l3, int l5) { String a = safeAlgo(key);