Add generic ML-DSA KeyFactory and Signature - #1667
Conversation
0bcff82 to
96a9583
Compare
| } | ||
|
|
||
| /** | ||
| * Returns the family name for a known PQC algorithm, or the param-set name |
There was a problem hiding this comment.
I don't think the param-set name is ever returned from this method. Am I missing some scenario?
There was a problem hiding this comment.
Yes agreed. I updated the javadoc here to state that we always return the family name.
| } | ||
|
|
||
| /** | ||
| * Returns the family name for a known PQC algorithm, or the param-set name |
There was a problem hiding this comment.
Yes agreed. I updated the javadoc here to state that we always return the family name.
| // The generic "ML-DSA" instance accepts any ML-DSA parameter-set key. | ||
| String keyParam = keyPrivate.getParamSetName(); | ||
| boolean paramMatches = keyParam.equalsIgnoreCase(this.alg) | ||
| || ("ML-DSA".equals(this.alg) && keyParam.startsWith("ML-DSA")); |
There was a problem hiding this comment.
Should this be keyParam.startsWith("ML-DSA-")? Notice the last - in the comparing string.
There was a problem hiding this comment.
Yes agreed its best to compare using the - at the end to ensure its the param name not family name being matched upon. Updated this code to reflect this.
|
|
||
| try { | ||
| this.signature.initialize(keyPrivate.getPQCKey(), keyPrivate.getAlgorithm().replace('_', '-')); | ||
| this.signature.initialize(keyPrivate.getPQCKey(), keyPrivate.getParamSetName().replace('_', '-')); |
There was a problem hiding this comment.
Can the name ever have a _? Do we need the replace here?
There was a problem hiding this comment.
You are right, getParamSetName() returns an already formatted param set name so i dont think we need to do this. I've removed the .replace('_', '-') call here and in engineInitVerify.
| // The generic "ML-DSA" instance accepts any ML-DSA parameter-set key. | ||
| String keyParam = keyPublic.getParamSetName(); | ||
| boolean paramMatches = keyParam.equalsIgnoreCase(this.alg) | ||
| || ("ML-DSA".equals(this.alg) && keyParam.startsWith("ML-DSA")); |
There was a problem hiding this comment.
Yes agreed its best to compare using the - at the end to ensure its the param name not family name being matched upon. Updated this code to reflect this.
| // The original and new keys are the same | ||
| same = Arrays.equals(publicKeyBytesInterop, pub.getEncoded()); | ||
| assertTrue(same); | ||
| assertTrue(same, "Public key bytes differ for " + pqcAlgorithm); |
There was a problem hiding this comment.
Yes agreed we should be using assertArrayEquals() through this entire test. I converted all asserts dealing with byte arrays to use this method.
| @ParameterizedTest | ||
| @CsvSource({"ML-DSA", "ML-DSA-44", "ML-DSA-65", "ML-DSA-87"}) | ||
| public void testGenericMLDSAKeyFactoryImportsInteropKeys(String paramSetName) throws Exception { | ||
| assumeFalse("OpenJCEPlusFIPS".equals(getProviderName())); |
There was a problem hiding this comment.
Do we need the assumeFalse here?
There was a problem hiding this comment.
Yes agreed that these assumes for the OpenJCEPlusFIPS provider are redundant since we currently do not run these with that provider set in our test paramaters. I removed these redundant checks throughout the BaseTestPQCKeyInterop class
| // BC private-key encoding differs; only compare against SunJCE | ||
| if (getInteropProviderName().equals(Utils.PROVIDER_SunJCE)) { | ||
| PrivateKey priv = genericKF.generatePrivate(new PKCS8EncodedKeySpec(pkcs8Bytes)); | ||
| assertTrue(Arrays.equals(pkcs8Bytes, priv.getEncoded()), |
There was a problem hiding this comment.
Why not assertArrayEquals()?
There was a problem hiding this comment.
Yes agreed we should be using assertArrayEquals() through this entire test. I converted all asserts dealing with byte arrays to use this method.
| PublicKey pubInterop = kfInterop.generatePublic( | ||
| new X509EncodedKeySpec(keyPairPlus.getPublic().getEncoded())); | ||
|
|
||
| assertTrue(Arrays.equals(keyPairPlus.getPublic().getEncoded(), pubInterop.getEncoded()), |
There was a problem hiding this comment.
Yes agreed we should be using assertArrayEquals() through this entire test. I converted all asserts dealing with byte arrays to use this method.
| System.out.println("FIPS does not support plain keys. Returning to caller."); | ||
| return; | ||
| } | ||
| assumeFalse("OpenJCEPlusFIPS".equals(getProviderName())); |
There was a problem hiding this comment.
Yes agreed that these assumes for the OpenJCEPlusFIPS provider are redundant since we currently do not run these with that provider set in our test paramaters. I removed these redundant checks throughout the BaseTestPQCSignatureWithAliases class
Register a family-level `ML-DSA` `KeyFactory` and `Signature` service so that callers can use the algorithm name `ML-DSA` without specifying a parameter set, matching the JEP 497 / JDK 24+ API contract. - Register `PQCKeyFactory$MLDSA` and `PQCSignatureImpl$MLDSA` as the `ML-DSA` service. Remove the `ML-DSA` alias from `ML-DSA-65` (it was a mis-mapping that silently directed all generic lookups to ML-DSA-65). - Split the single `name` field into `familyName` (returned by `getAlgorithm()` such as `ML-DSA`) and `paramSetName` (the concrete parameter set such as `ML-DSA-65`). Add getters and setters for these values such that other code can act accordingly. - Add tests to `BaseTestPQCKeyInterop`. These tests cover all three `ML-DSA` parameter sets via `@ParameterizedTest`. - Add tests to `BaseTestPQCKeys`. Expand alias coverage to include case variants, OID aliases, and bare OID strings. Added tests for `getAlgorithm()` family-name correctness for all ML-DSA and ML-KEM aliases - Add tests to `BaseTestPQCSignature` for generic `ML-DSA` sign/verify tests to all three parameter sets. Fixes: IBM#1567 Signed-off-by: Jason Katonica <katonica@us.ibm.com>
bb7ac47 to
9427647
Compare
Signed-off-by: Jason Katonica <katonica@us.ibm.com>
Signed-off-by: Jason Katonica <katonica@us.ibm.com>
5b0d00a to
a6e6bdd
Compare
Signed-off-by: Jason Katonica <katonica@us.ibm.com>
a6e6bdd to
f391d23
Compare
Register a family-level
ML-DSAKeyFactoryandSignatureservice so that callers can use the algorithm nameML-DSAwithout specifying a parameter set, matching the JEP 497 / JDK 24+ API contract.PQCKeyFactory$MLDSAandPQCSignatureImpl$MLDSAas theML-DSAservice. Remove theML-DSAalias fromML-DSA-65(it was amis-mapping that silently directed all generic lookups to ML-DSA-65).
namefield intofamilyName(returned bygetAlgorithm()such asML-DSA) andparamSetName(the concrete parameter set such asML-DSA-65). Add getters and setters for these values such that other code can act accordingly.BaseTestPQCKeyInterop. These tests cover all threeML-DSAparameter sets via@ParameterizedTest.BaseTestPQCKeys. Expand alias coverage to include case variants, OID aliases, and bare OID strings. Added tests forgetAlgorithm()family-name correctness for all ML-DSA and ML-KEM aliasesBaseTestPQCSignaturefor genericML-DSAsign/verify tests to all three parameter sets.Fixes: #1567
Signed-off-by: Jason Katonica katonica@us.ibm.com