Skip to content

Commit 1ce9479

Browse files
committed
added support for CHOICE private key encoding.
1 parent a3bde4e commit 1ce9479

File tree

4 files changed

+30
-61
lines changed

4 files changed

+30
-61
lines changed

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,10 @@ public interface MLDSAPrivateKey
2727
byte[] getSeed();
2828

2929
/**
30-
* Return the encoding of the key or an encoding of its key generation parameters (the seed).
30+
* Return a privateKey which will encode as seed-only or as an expanded-key.
3131
*
32-
* @param asKeyGenParams return a key gen parameters structure.
33-
* @return a PKCS#8 of the private key encoding, or a PKCS#8 of the seed.
32+
* @param preferSeedOnly if true, return a privateKey which will encode to seed-only if possible.
33+
* @return a new MLDSAPrivateKey which encodes to either seed-only or expanded-key.
3434
*/
35-
byte[] getEncoded(boolean asKeyGenParams);
35+
MLDSAPrivateKey getPrivateKey(boolean preferSeedOnly);
3636
}

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

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -91,19 +91,18 @@ public final String getAlgorithm()
9191
return algorithm;
9292
}
9393

94-
public byte[] getEncoded(boolean asKeyGenParams)
94+
public MLDSAPrivateKey getPrivateKey(boolean preferSeedOnly)
9595
{
96-
if (asKeyGenParams)
96+
if (preferSeedOnly)
9797
{
9898
byte[] seed = params.getSeed();
99-
if (seed == null)
99+
if (seed != null)
100100
{
101-
return null;
101+
return new BCMLDSAPrivateKey(this.params.getParametersWithFormat(MLDSAPrivateKeyParameters.SEED_ONLY));
102102
}
103-
return KeyUtil.getEncodedPrivateKeyInfo(getParameterSpec(), seed, attributes);
104103
}
105104

106-
return getEncoded();
105+
return new BCMLDSAPrivateKey(this.params.getParametersWithFormat(MLDSAPrivateKeyParameters.EXPANDED_KEY));
107106
}
108107

109108
public byte[] getEncoded()

prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/util/KeyUtil.java

Lines changed: 0 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,12 @@
11
package org.bouncycastle.pqc.jcajce.provider.util;
22

3-
import java.security.spec.AlgorithmParameterSpec;
4-
53
import org.bouncycastle.asn1.ASN1Encodable;
64
import org.bouncycastle.asn1.ASN1Encoding;
75
import org.bouncycastle.asn1.ASN1Set;
8-
import org.bouncycastle.asn1.bc.BCObjectIdentifiers;
96
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
107
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
118
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
129
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
13-
import org.bouncycastle.jcajce.spec.MLDSAParameterSpec;
1410
import org.bouncycastle.pqc.crypto.util.PrivateKeyInfoFactory;
1511
import org.bouncycastle.pqc.crypto.util.SubjectPublicKeyInfoFactory;
1612

@@ -95,45 +91,6 @@ public static byte[] getEncodedPrivateKeyInfo(PrivateKeyInfo info)
9591
}
9692
}
9793

98-
public static byte[] getEncodedPrivateKeyInfo(AlgorithmParameterSpec paramSpec, byte[] seed, ASN1Set attributes)
99-
{
100-
byte[] enc = null;
101-
102-
try
103-
{
104-
if (paramSpec instanceof MLDSAParameterSpec)
105-
{
106-
String name = ((MLDSAParameterSpec)paramSpec).getName();
107-
if (name.equals(MLDSAParameterSpec.ml_dsa_44.getName()) || name.equals(MLDSAParameterSpec.ml_dsa_44_with_sha512.getName()))
108-
{
109-
enc = new PrivateKeyInfo(new AlgorithmIdentifier(BCObjectIdentifiers.id_id_alg_ml_dsa_44_seed), seed, attributes).getEncoded();
110-
}
111-
else if (name.equals(MLDSAParameterSpec.ml_dsa_65.getName()) || name.equals(MLDSAParameterSpec.ml_dsa_65_with_sha512.getName()))
112-
{
113-
enc = new PrivateKeyInfo(new AlgorithmIdentifier(BCObjectIdentifiers.id_id_alg_ml_dsa_65_seed), seed, attributes).getEncoded();
114-
}
115-
else if (name.equals(MLDSAParameterSpec.ml_dsa_87.getName()) || name.equals(MLDSAParameterSpec.ml_dsa_87_with_sha512.getName()))
116-
{
117-
enc = new PrivateKeyInfo(new AlgorithmIdentifier(BCObjectIdentifiers.id_id_alg_ml_dsa_87_seed), seed, attributes).getEncoded();
118-
}
119-
else
120-
{
121-
throw new IllegalStateException("unknown ML-DSA algorithm");
122-
}
123-
}
124-
}
125-
catch (IllegalStateException e)
126-
{
127-
throw e;
128-
}
129-
catch (Exception e)
130-
{
131-
return null;
132-
}
133-
134-
return enc;
135-
}
136-
13794
public static byte[] getEncodedPrivateKeyInfo(AsymmetricKeyParameter privateKey, ASN1Set attributes)
13895
{
13996
if (!privateKey.isPrivate())

prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/MLDSATest.java

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,8 @@ private void tryKeyFact(KeyFactory kFact, KeyPair kpValid, KeyPair kpInvalid, St
124124
throws Exception
125125
{
126126
kFact.generatePrivate(new PKCS8EncodedKeySpec(kpValid.getPrivate().getEncoded()));
127-
kFact.generatePrivate(new PKCS8EncodedKeySpec(((MLDSAPrivateKey)kpValid.getPrivate()).getEncoded(true)));
127+
kFact.generatePrivate(new PKCS8EncodedKeySpec(((MLDSAPrivateKey)kpValid.getPrivate()).getPrivateKey(true).getEncoded()));
128+
kFact.generatePrivate(new PKCS8EncodedKeySpec(((MLDSAPrivateKey)kpValid.getPrivate()).getPrivateKey(false).getEncoded()));
128129
kFact.generatePublic(new X509EncodedKeySpec(kpValid.getPublic().getEncoded()));
129130

130131
try
@@ -192,12 +193,11 @@ public void testDefaultPrivateKeyEncoding()
192193

193194
assertTrue(Arrays.areEqual(seq.getOctets(), seed));
194195

195-
ASN1OctetString privData = ASN1OctetString.getInstance((ASN1TaggedObject)ASN1Sequence.getInstance(privInfo.getPrivateKey().getOctets()).getObjectAt(1), false);
196+
ASN1OctetString privData = ASN1OctetString.getInstance(ASN1Sequence.getInstance(privInfo.getPrivateKey().getOctets()).getObjectAt(1));
196197

197198
assertTrue(Arrays.areEqual(privData.getOctets(), ((MLDSAPrivateKey)kp44.getPrivate()).getPrivateData()));
198199
}
199200

200-
201201
public void testSeedPrivateKeyEncoding()
202202
throws Exception
203203
{
@@ -208,14 +208,27 @@ public void testSeedPrivateKeyEncoding()
208208
kpGen44.initialize(MLDSAParameterSpec.ml_dsa_44, new FixedSecureRandom(seed));
209209
KeyPair kp44 = kpGen44.generateKeyPair();
210210

211-
Security.setProperty("org.bouncycastle.mldsa.seedOnly", "true");
212-
213-
PrivateKeyInfo privInfo = PrivateKeyInfo.getInstance(kp44.getPrivate().getEncoded());
211+
PrivateKeyInfo privInfo = PrivateKeyInfo.getInstance(((MLDSAPrivateKey)kp44.getPrivate()).getPrivateKey(true).getEncoded());
214212

215-
Security.setProperty("org.bouncycastle.mldsa.seedOnly", "false");
216213
ASN1OctetString k = privInfo.getPrivateKey();
217214

218-
assertTrue(Arrays.areEqual(k.getOctets(), seed));
215+
assertTrue(Arrays.areEqual(ASN1OctetString.getInstance((ASN1TaggedObject)privInfo.parsePrivateKey(), false).getOctets(), seed));
216+
}
217+
218+
public void testExpandedKeyPrivateKeyEncoding()
219+
throws Exception
220+
{
221+
KeyPairGenerator kpGen44 = KeyPairGenerator.getInstance("ML-DSA-44");
222+
223+
byte[] seed = Hex.decode("000102030405060708090a0b0c0d0e0f" + "100102030405060708090a0b0c0d0e0f");
224+
byte[] expandedKey = Base64.decode("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");
225+
226+
kpGen44.initialize(MLDSAParameterSpec.ml_dsa_44, new FixedSecureRandom(seed));
227+
KeyPair kp44 = kpGen44.generateKeyPair();
228+
229+
PrivateKeyInfo privInfo = PrivateKeyInfo.getInstance(((MLDSAPrivateKey)kp44.getPrivate()).getPrivateKey(false).getEncoded());
230+
231+
assertTrue(Arrays.areEqual(ASN1OctetString.getInstance(privInfo.parsePrivateKey()).getOctets(), expandedKey));
219232
}
220233

221234
public void testPrivateKeyRecoding()

0 commit comments

Comments
 (0)