Skip to content

Commit acc20ad

Browse files
committed
added getPrivateData methods.
added KeySpecs support for ML-DSA and associated factories.
1 parent 8737c41 commit acc20ad

File tree

10 files changed

+326
-16
lines changed

10 files changed

+326
-16
lines changed

prov/src/main/java/org/bouncycastle/jcajce/interfaces/MLDSAPrivateKey.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,18 @@ public interface MLDSAPrivateKey
1111
* @return a ML-DSA Public Key
1212
*/
1313
MLDSAPublicKey getPublicKey();
14+
15+
/**
16+
* Return the long form private data for the ML-DSA private key.
17+
*
18+
* @return long form private data for private key.
19+
*/
20+
byte[] getPrivateData();
21+
22+
/**
23+
* Return the seed the private key was generated from (if available).
24+
*
25+
* @return the seed for the private key, null if not available.
26+
*/
27+
byte[] getSeed();
1428
}

prov/src/main/java/org/bouncycastle/jcajce/interfaces/MLKEMPrivateKey.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,18 @@ public interface MLKEMPrivateKey
1111
* @return a ML-KEM Public Key
1212
*/
1313
MLKEMPublicKey getPublicKey();
14+
15+
/**
16+
* Return the long form private data for the ML-KEM private key.
17+
*
18+
* @return long form private data for private key.
19+
*/
20+
byte[] getPrivateData();
21+
22+
/**
23+
* Return the seed the private key was generated from (if available).
24+
*
25+
* @return the seed for the private key, null if not available.
26+
*/
27+
byte[] getSeed();
1428
}

prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/mldsa/BCMLDSAPrivateKey.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,18 @@ public MLDSAPublicKey getPublicKey()
104104
return new BCMLDSAPublicKey(params.getPublicKeyParameters());
105105
}
106106

107+
@Override
108+
public byte[] getPrivateData()
109+
{
110+
return params.getEncoded();
111+
}
112+
113+
@Override
114+
public byte[] getSeed()
115+
{
116+
return params.getSeed();
117+
}
118+
107119
public MLDSAParameterSpec getParameterSpec()
108120
{
109121
return MLDSAParameterSpec.fromName(params.getParameters().getName());

prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/mldsa/MLDSAKeyFactorySpi.java

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@
1616
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
1717
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
1818
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
19+
import org.bouncycastle.jcajce.spec.MLDSAPrivateKeySpec;
20+
import org.bouncycastle.jcajce.spec.MLDSAPublicKeySpec;
21+
import org.bouncycastle.pqc.crypto.mldsa.MLDSAParameters;
22+
import org.bouncycastle.pqc.crypto.mldsa.MLDSAPrivateKeyParameters;
23+
import org.bouncycastle.pqc.crypto.mldsa.MLDSAPublicKeyParameters;
1924
import org.bouncycastle.pqc.jcajce.provider.util.BaseKeyFactorySpi;
2025

2126
public class MLDSAKeyFactorySpi
@@ -57,13 +62,33 @@ public final KeySpec engineGetKeySpec(Key key, Class keySpec)
5762
{
5863
return new PKCS8EncodedKeySpec(key.getEncoded());
5964
}
65+
if (MLDSAPrivateKeySpec.class.isAssignableFrom(keySpec))
66+
{
67+
BCMLDSAPrivateKey mldsaKey = (BCMLDSAPrivateKey)key;
68+
byte[] seed = mldsaKey.getSeed();
69+
if (seed != null)
70+
{
71+
return new MLDSAPrivateKeySpec(mldsaKey.getParameterSpec(), seed);
72+
}
73+
return new MLDSAPrivateKeySpec(mldsaKey.getParameterSpec(), mldsaKey.getPrivateData(), mldsaKey.getPublicKey().getPublicData());
74+
}
75+
if (MLDSAPublicKeySpec.class.isAssignableFrom(keySpec))
76+
{
77+
BCMLDSAPrivateKey mldsaKey = (BCMLDSAPrivateKey)key;
78+
return new MLDSAPublicKeySpec(mldsaKey.getParameterSpec(), mldsaKey.getPublicKey().getPublicData());
79+
}
6080
}
6181
else if (key instanceof BCMLDSAPublicKey)
6282
{
6383
if (X509EncodedKeySpec.class.isAssignableFrom(keySpec))
6484
{
6585
return new X509EncodedKeySpec(key.getEncoded());
6686
}
87+
if (MLDSAPublicKeySpec.class.isAssignableFrom(keySpec))
88+
{
89+
BCMLDSAPublicKey mldsaKey = (BCMLDSAPublicKey)key;
90+
return new MLDSAPublicKeySpec(mldsaKey.getParameterSpec(), mldsaKey.getPublicData());
91+
}
6792
}
6893
else
6994
{
@@ -86,6 +111,57 @@ public final Key engineTranslateKey(Key key)
86111
throw new InvalidKeyException("Unsupported key type");
87112
}
88113

114+
public PrivateKey engineGeneratePrivate(
115+
KeySpec keySpec)
116+
throws InvalidKeySpecException
117+
{
118+
if (keySpec instanceof MLDSAPrivateKeySpec)
119+
{
120+
MLDSAPrivateKeySpec spec = (MLDSAPrivateKeySpec)keySpec;
121+
MLDSAPrivateKeyParameters params;
122+
MLDSAParameters mldsaParameters = Utils.getParameters(spec.getParameterSpec().getName());
123+
if (spec.isSeed())
124+
{
125+
params = new MLDSAPrivateKeyParameters(
126+
mldsaParameters, spec.getSeed());
127+
}
128+
else
129+
{
130+
byte[] publicData = spec.getPublicData();
131+
if (publicData != null)
132+
{
133+
params = new MLDSAPrivateKeyParameters(
134+
mldsaParameters, spec.getPrivateData(), new MLDSAPublicKeyParameters(mldsaParameters, publicData));
135+
}
136+
else
137+
{
138+
params = new MLDSAPrivateKeyParameters(
139+
mldsaParameters, spec.getPrivateData(), null);
140+
}
141+
}
142+
143+
return new BCMLDSAPrivateKey(params);
144+
}
145+
146+
return super.engineGeneratePrivate(keySpec);
147+
}
148+
149+
public PublicKey engineGeneratePublic(
150+
KeySpec keySpec)
151+
throws InvalidKeySpecException
152+
{
153+
if (keySpec instanceof MLDSAPublicKeySpec)
154+
{
155+
MLDSAPublicKeySpec spec = (MLDSAPublicKeySpec)keySpec;
156+
157+
return new BCMLDSAPublicKey(new MLDSAPublicKeyParameters(
158+
Utils.getParameters(spec.getParameterSpec().getName()),
159+
spec.getPublicData()));
160+
}
161+
162+
return super.engineGeneratePublic(keySpec);
163+
}
164+
89165
public PrivateKey generatePrivate(PrivateKeyInfo keyInfo)
90166
throws IOException
91167
{

prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/mldsa/MLDSAKeyPairGeneratorSpi.java

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@
55
import java.security.NoSuchAlgorithmException;
66
import java.security.SecureRandom;
77
import java.security.spec.AlgorithmParameterSpec;
8-
import java.util.HashMap;
9-
import java.util.Map;
108

119
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
1210
import org.bouncycastle.crypto.CryptoServicesRegistrar;
@@ -23,18 +21,6 @@
2321
public class MLDSAKeyPairGeneratorSpi
2422
extends java.security.KeyPairGenerator
2523
{
26-
private static Map parameters = new HashMap();
27-
28-
static
29-
{
30-
parameters.put(MLDSAParameterSpec.ml_dsa_44.getName(), MLDSAParameters.ml_dsa_44);
31-
parameters.put(MLDSAParameterSpec.ml_dsa_65.getName(), MLDSAParameters.ml_dsa_65);
32-
parameters.put(MLDSAParameterSpec.ml_dsa_87.getName(), MLDSAParameters.ml_dsa_87);
33-
parameters.put(MLDSAParameterSpec.ml_dsa_44_with_sha512.getName(), MLDSAParameters.ml_dsa_44_with_sha512);
34-
parameters.put(MLDSAParameterSpec.ml_dsa_65_with_sha512.getName(), MLDSAParameters.ml_dsa_65_with_sha512);
35-
parameters.put(MLDSAParameterSpec.ml_dsa_87_with_sha512.getName(), MLDSAParameters.ml_dsa_87_with_sha512);
36-
}
37-
3824
private final MLDSAParameters mldsaParameters;
3925
MLDSAKeyGenerationParameters param;
4026
MLDSAKeyPairGenerator engine = new MLDSAKeyPairGenerator();
@@ -51,7 +37,7 @@ public MLDSAKeyPairGeneratorSpi(String name)
5137
protected MLDSAKeyPairGeneratorSpi(MLDSAParameterSpec paramSpec)
5238
{
5339
super(Strings.toUpperCase(paramSpec.getName()));
54-
this.mldsaParameters = (MLDSAParameters)parameters.get(paramSpec.getName());
40+
this.mldsaParameters = Utils.getParameters(paramSpec.getName());
5541

5642
if (param == null)
5743
{
@@ -92,7 +78,7 @@ public void initialize(
9278

9379
if (name != null)
9480
{
95-
MLDSAParameters mldsaParams = (MLDSAParameters)parameters.get(name);
81+
MLDSAParameters mldsaParams = Utils.getParameters(name);
9682
if (mldsaParams == null)
9783
{
9884
throw new InvalidAlgorithmParameterException("unknown parameter set name: " + name);
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package org.bouncycastle.jcajce.provider.asymmetric.mldsa;
2+
3+
import java.util.HashMap;
4+
import java.util.Map;
5+
6+
import org.bouncycastle.jcajce.spec.MLDSAParameterSpec;
7+
import org.bouncycastle.pqc.crypto.mldsa.MLDSAParameters;
8+
9+
class Utils
10+
{
11+
private static Map parameters = new HashMap();
12+
13+
static
14+
{
15+
parameters.put(MLDSAParameterSpec.ml_dsa_44.getName(), MLDSAParameters.ml_dsa_44);
16+
parameters.put(MLDSAParameterSpec.ml_dsa_65.getName(), MLDSAParameters.ml_dsa_65);
17+
parameters.put(MLDSAParameterSpec.ml_dsa_87.getName(), MLDSAParameters.ml_dsa_87);
18+
parameters.put(MLDSAParameterSpec.ml_dsa_44_with_sha512.getName(), MLDSAParameters.ml_dsa_44_with_sha512);
19+
parameters.put(MLDSAParameterSpec.ml_dsa_65_with_sha512.getName(), MLDSAParameters.ml_dsa_65_with_sha512);
20+
parameters.put(MLDSAParameterSpec.ml_dsa_87_with_sha512.getName(), MLDSAParameters.ml_dsa_87_with_sha512);
21+
}
22+
23+
static MLDSAParameters getParameters(String paramName)
24+
{
25+
return (MLDSAParameters)parameters.get(paramName);
26+
}
27+
}

prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/mlkem/BCMLKEMPrivateKey.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,18 @@ public MLKEMPublicKey getPublicKey()
102102
return new BCMLKEMPublicKey(params.getPublicKeyParameters());
103103
}
104104

105+
@Override
106+
public byte[] getPrivateData()
107+
{
108+
return params.getEncoded();
109+
}
110+
111+
@Override
112+
public byte[] getSeed()
113+
{
114+
return params.getSeed();
115+
}
116+
105117
public MLKEMParameterSpec getParameterSpec()
106118
{
107119
return MLKEMParameterSpec.fromName(params.getParameters().getName());
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
package org.bouncycastle.jcajce.spec;
2+
3+
import java.security.spec.KeySpec;
4+
5+
import org.bouncycastle.util.Arrays;
6+
7+
/**
8+
* PrivateKeySpec for ML-DSA.
9+
*/
10+
public class MLDSAPrivateKeySpec
11+
implements KeySpec
12+
{
13+
private final byte[] data;
14+
private final byte[] publicData;
15+
private final MLDSAParameterSpec params;
16+
private final boolean isSeed;
17+
18+
public MLDSAPrivateKeySpec(MLDSAParameterSpec params, byte[] seed)
19+
{
20+
if (seed.length != 32)
21+
{
22+
throw new IllegalArgumentException("incorrect length for seed");
23+
}
24+
25+
this.isSeed = true;
26+
this.params = params;
27+
this.data = Arrays.clone(seed);
28+
this.publicData = null;
29+
}
30+
31+
/**
32+
* Create a KeySpec using the long form private and public data.
33+
*
34+
* @param params the parameter set to use with the encodings.
35+
* @param privateData the long form private key.
36+
* @param publicData the long form public key - may be null.
37+
*/
38+
public MLDSAPrivateKeySpec(MLDSAParameterSpec params, byte[] privateData, byte[] publicData)
39+
{
40+
this.isSeed = false;
41+
this.params = params;
42+
this.data = Arrays.clone(privateData);
43+
this.publicData = Arrays.clone(publicData);
44+
}
45+
46+
public boolean isSeed()
47+
{
48+
return isSeed;
49+
}
50+
51+
public MLDSAParameterSpec getParameterSpec()
52+
{
53+
return params;
54+
}
55+
56+
public byte[] getSeed()
57+
{
58+
if (isSeed())
59+
{
60+
return Arrays.clone(data);
61+
}
62+
63+
throw new IllegalStateException("KeySpec represents long form");
64+
}
65+
66+
public byte[] getPrivateData()
67+
{
68+
if (!isSeed())
69+
{
70+
return Arrays.clone(data);
71+
}
72+
73+
throw new IllegalStateException("KeySpec represents seed");
74+
}
75+
76+
public byte[] getPublicData()
77+
{
78+
if (!isSeed())
79+
{
80+
return Arrays.clone(publicData);
81+
}
82+
83+
throw new IllegalStateException("KeySpec represents long form");
84+
}
85+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package org.bouncycastle.jcajce.spec;
2+
3+
import java.security.spec.KeySpec;
4+
5+
import org.bouncycastle.util.Arrays;
6+
7+
/**
8+
* PublicKeySpec for ML-DSA.
9+
*/
10+
public class MLDSAPublicKeySpec
11+
implements KeySpec
12+
{
13+
private final MLDSAParameterSpec params;
14+
private final byte[] publicData;
15+
16+
/**
17+
* Base constructor.
18+
*
19+
* @param params the parameters to use with the passed in encoding.
20+
* @param publicData the long form encoding of the public key.
21+
*/
22+
public MLDSAPublicKeySpec(MLDSAParameterSpec params, byte[] publicData)
23+
{
24+
this.params = params;
25+
this.publicData = publicData;
26+
}
27+
28+
public MLDSAParameterSpec getParameterSpec()
29+
{
30+
return params;
31+
}
32+
33+
public byte[] getPublicData()
34+
{
35+
return Arrays.clone(publicData);
36+
}
37+
}

0 commit comments

Comments
 (0)