Skip to content

Commit eac93fc

Browse files
committed
added support for ML-DSA context parameter.
corrected private key encoding to the latest draft.
1 parent e298b5b commit eac93fc

File tree

5 files changed

+294
-66
lines changed

5 files changed

+294
-66
lines changed

pkix/src/test/java/org/bouncycastle/openssl/test/CompositeKeyTest.java

Lines changed: 31 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import java.io.ByteArrayInputStream;
44
import java.io.FileOutputStream;
5+
import java.io.FileWriter;
56
import java.io.IOException;
67
import java.io.StringReader;
78
import java.io.StringWriter;
@@ -473,21 +474,21 @@ public void testMLDSA44andP256()
473474
PrivateKey mldsaPriv = mldsaKp.getPrivate();
474475
PublicKey mldsaPub = mldsaKp.getPublic();
475476

476-
CompositePrivateKey mlecPriv = new CompositePrivateKey(mldsaPriv, ecPriv);
477-
478-
// JcaPEMWriter pWrt = new JcaPEMWriter(new FileWriter("/tmp/mldsa44_ec_p256_priv.pem"));
479-
//
480-
// pWrt.writeObject(mlecPriv);
481-
//
482-
// pWrt.close();
483-
//
484-
// CompositePublicKey mlecPub = new CompositePublicKey(mldsaPub, ecPub);
485-
//
486-
// pWrt = new JcaPEMWriter(new FileWriter("/tmp/mldsa44_ec_p256_pub.pem"));
487-
//
488-
// pWrt.writeObject(mlecPub);
489-
//
490-
// pWrt.close();
477+
CompositePrivateKey mlecPriv = new CompositePrivateKey(MiscObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256, mldsaPriv, ecPriv);
478+
479+
JcaPEMWriter pWrt = new JcaPEMWriter(new FileWriter("/tmp/mldsa44_ec_p256_priv.pem"));
480+
481+
pWrt.writeObject(mlecPriv);
482+
483+
pWrt.close();
484+
485+
CompositePublicKey mlecPub = new CompositePublicKey(mldsaPub, ecPub);
486+
487+
pWrt = new JcaPEMWriter(new FileWriter("/tmp/mldsa44_ec_p256_pub.pem"));
488+
489+
pWrt.writeObject(mlecPub);
490+
491+
pWrt.close();
491492
}
492493

493494
public void testMLDSA87andEd448()
@@ -510,21 +511,21 @@ public void testMLDSA87andEd448()
510511
PrivateKey mldsaPriv = mldsaKp.getPrivate();
511512
PublicKey mldsaPub = mldsaKp.getPublic();
512513

513-
CompositePrivateKey mlecPriv = new CompositePrivateKey(mldsaPriv, ecPriv);
514-
515-
// JcaPEMWriter pWrt = new JcaPEMWriter(new FileWriter("/tmp/mldsa87_ed448_priv.pem"));
516-
//
517-
// pWrt.writeObject(mlecPriv);
518-
//
519-
// pWrt.close();
520-
//
521-
// CompositePublicKey mlecPub = new CompositePublicKey(mldsaPub, ecPub);
522-
//
523-
// pWrt = new JcaPEMWriter(new FileWriter("/tmp/mldsa87_ed448_pub.pem"));
524-
//
525-
// pWrt.writeObject(mlecPub);
526-
//
527-
// pWrt.close();
514+
CompositePrivateKey mlecPriv = new CompositePrivateKey(MiscObjectIdentifiers.id_MLDSA87_Ed448_SHA512, mldsaPriv, ecPriv);
515+
516+
JcaPEMWriter pWrt = new JcaPEMWriter(new FileWriter("/tmp/mldsa87_ed448_priv.pem"));
517+
518+
pWrt.writeObject(mlecPriv);
519+
520+
pWrt.close();
521+
522+
CompositePublicKey mlecPub = new CompositePublicKey(mldsaPub, ecPub);
523+
524+
pWrt = new JcaPEMWriter(new FileWriter("/tmp/mldsa87_ed448_pub.pem"));
525+
526+
pWrt.writeObject(mlecPub);
527+
528+
pWrt.close();
528529
}
529530

530531
private static void doOutput(String fileName, String contents)

prov/src/main/java/org/bouncycastle/jcajce/CompositePrivateKey.java

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -132,16 +132,21 @@ public byte[] getEncoded()
132132
{
133133
ASN1EncodableVector v = new ASN1EncodableVector();
134134

135-
for (int i = 0; i < keys.size(); i++)
135+
if (algorithmIdentifier.equals(MiscObjectIdentifiers.id_composite_key))
136136
{
137-
ASN1EncodableVector kV = new ASN1EncodableVector();
138-
139-
PrivateKeyInfo info = PrivateKeyInfo.getInstance(keys.get(i).getEncoded());
140-
141-
kV.add(info.getPrivateKeyAlgorithm());
142-
kV.add(info.getPrivateKey());
143-
144-
v.add(new DERSequence(kV));
137+
for (int i = 0; i < keys.size(); i++)
138+
{
139+
PrivateKeyInfo info = PrivateKeyInfo.getInstance(keys.get(i).getEncoded());
140+
v.add(info);
141+
}
142+
}
143+
else
144+
{
145+
for (int i = 0; i < keys.size(); i++)
146+
{
147+
PrivateKeyInfo info = PrivateKeyInfo.getInstance(keys.get(i).getEncoded());
148+
v.add(info.getPrivateKey());
149+
}
145150
}
146151

147152
try

prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/COMPOSITE.java

Lines changed: 106 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,27 @@
88
import java.util.HashMap;
99
import java.util.Map;
1010

11+
import org.bouncycastle.asn1.ASN1Encodable;
1112
import org.bouncycastle.asn1.ASN1EncodableVector;
13+
import org.bouncycastle.asn1.ASN1Integer;
14+
import org.bouncycastle.asn1.ASN1OctetString;
1215
import org.bouncycastle.asn1.ASN1Sequence;
16+
import org.bouncycastle.asn1.DERNull;
1317
import org.bouncycastle.asn1.DERSequence;
18+
import org.bouncycastle.asn1.bc.BCObjectIdentifiers;
19+
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
20+
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
1421
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
22+
import org.bouncycastle.asn1.sec.SECObjectIdentifiers;
23+
import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
24+
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
1525
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
26+
import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
27+
import org.bouncycastle.internal.asn1.edec.EdECObjectIdentifiers;
1628
import org.bouncycastle.internal.asn1.misc.MiscObjectIdentifiers;
1729
import org.bouncycastle.jcajce.CompositePrivateKey;
1830
import org.bouncycastle.jcajce.CompositePublicKey;
31+
import org.bouncycastle.jcajce.provider.asymmetric.compositesignatures.CompositeSignaturesConstants;
1932
import org.bouncycastle.jcajce.provider.asymmetric.util.BaseKeyFactorySpi;
2033
import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
2134
import org.bouncycastle.jcajce.provider.util.AsymmetricAlgorithmProvider;
@@ -89,35 +102,112 @@ public PrivateKey generatePrivate(PrivateKeyInfo keyInfo)
89102
ASN1Sequence keySeq = ASN1Sequence.getInstance(keyInfo.parsePrivateKey());
90103
PrivateKey[] privKeys = new PrivateKey[keySeq.size()];
91104

92-
for (int i = 0; i != keySeq.size(); i++)
93-
{
94-
ASN1Sequence kSeq = ASN1Sequence.getInstance(keySeq.getObjectAt(i));
105+
ASN1Encodable firstKey = keySeq.getObjectAt(0);
95106

96-
if (kSeq.size() == 2)
107+
if (firstKey instanceof ASN1OctetString)
108+
{
109+
System.err.println(keyInfo.getPrivateKeyAlgorithm().getAlgorithm());
110+
CompositeSignaturesConstants.CompositeName name = CompositeSignaturesConstants.ASN1IdentifierCompositeNameMap.get(keyInfo.getPrivateKeyAlgorithm().getAlgorithm());
111+
switch (name)
97112
{
98-
ASN1EncodableVector v = new ASN1EncodableVector(2);
99-
100-
v.add(keyInfo.getVersion());
101-
v.add(kSeq.getObjectAt(0));
102-
v.add(kSeq.getObjectAt(1));
103-
104-
PrivateKeyInfo privInfo = PrivateKeyInfo.getInstance(new DERSequence(v));
105-
106-
privKeys[i] = provider.getKeyInfoConverter(
107-
privInfo.getPrivateKeyAlgorithm().getAlgorithm()).generatePrivate(privInfo);
113+
case MLDSA44_Ed25519_SHA512:
114+
privKeys[0] = createPrivateKey(new AlgorithmIdentifier(NISTObjectIdentifiers.id_ml_dsa_44), ASN1OctetString.getInstance(keySeq.getObjectAt(0)));
115+
privKeys[1] = createPrivateKey(new AlgorithmIdentifier(EdECObjectIdentifiers.id_Ed25519), ASN1OctetString.getInstance(keySeq.getObjectAt(0)));
116+
break;
117+
case MLDSA65_Ed25519_SHA512:
118+
privKeys[0] = createPrivateKey(new AlgorithmIdentifier(NISTObjectIdentifiers.id_ml_dsa_65), ASN1OctetString.getInstance(keySeq.getObjectAt(0)));
119+
privKeys[1] = createPrivateKey(new AlgorithmIdentifier(EdECObjectIdentifiers.id_Ed25519), ASN1OctetString.getInstance(keySeq.getObjectAt(0)));
120+
break;
121+
case MLDSA87_Ed448_SHA512:
122+
privKeys[0] = createPrivateKey(new AlgorithmIdentifier(NISTObjectIdentifiers.id_ml_dsa_87), ASN1OctetString.getInstance(keySeq.getObjectAt(0)));
123+
privKeys[1] = createPrivateKey(new AlgorithmIdentifier(EdECObjectIdentifiers.id_Ed448), ASN1OctetString.getInstance(keySeq.getObjectAt(0)));
124+
break;
125+
case MLDSA44_RSA2048_PSS_SHA256:
126+
privKeys[0] = createPrivateKey(new AlgorithmIdentifier(NISTObjectIdentifiers.id_ml_dsa_44), ASN1OctetString.getInstance(keySeq.getObjectAt(0)));
127+
privKeys[1] = createPrivateKey(new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE), ASN1OctetString.getInstance(keySeq.getObjectAt(0)));
128+
break;
129+
case MLDSA65_RSA3072_PSS_SHA512:
130+
privKeys[0] = createPrivateKey(new AlgorithmIdentifier(NISTObjectIdentifiers.id_ml_dsa_65), ASN1OctetString.getInstance(keySeq.getObjectAt(0)));
131+
privKeys[1] = createPrivateKey(new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE), ASN1OctetString.getInstance(keySeq.getObjectAt(0)));
132+
break;
133+
case MLDSA44_RSA2048_PKCS15_SHA256:
134+
privKeys[0] = createPrivateKey(new AlgorithmIdentifier(NISTObjectIdentifiers.id_ml_dsa_44), ASN1OctetString.getInstance(keySeq.getObjectAt(0)));
135+
privKeys[1] = createPrivateKey(new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE), ASN1OctetString.getInstance(keySeq.getObjectAt(0)));
136+
break;
137+
case MLDSA65_RSA3072_PKCS15_SHA512:
138+
privKeys[0] = createPrivateKey(new AlgorithmIdentifier(NISTObjectIdentifiers.id_ml_dsa_65), ASN1OctetString.getInstance(keySeq.getObjectAt(0)));
139+
privKeys[1] = createPrivateKey(new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE), ASN1OctetString.getInstance(keySeq.getObjectAt(0)));
140+
break;
141+
case MLDSA44_ECDSA_P256_SHA256:
142+
privKeys[0] = createPrivateKey(new AlgorithmIdentifier(NISTObjectIdentifiers.id_ml_dsa_44), ASN1OctetString.getInstance(keySeq.getObjectAt(0)));
143+
privKeys[1] = createPrivateKey(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, SECObjectIdentifiers.secp256r1), ASN1OctetString.getInstance(keySeq.getObjectAt(0)));
144+
break;
145+
case MLDSA44_ECDSA_brainpoolP256r1_SHA256:
146+
privKeys[0] = createPrivateKey(new AlgorithmIdentifier(NISTObjectIdentifiers.id_ml_dsa_44), ASN1OctetString.getInstance(keySeq.getObjectAt(0)));
147+
break;
148+
case MLDSA65_ECDSA_P256_SHA512:
149+
privKeys[0] = createPrivateKey(new AlgorithmIdentifier(NISTObjectIdentifiers.id_ml_dsa_65), ASN1OctetString.getInstance(keySeq.getObjectAt(0)));
150+
privKeys[1] = createPrivateKey(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, SECObjectIdentifiers.secp256r1), ASN1OctetString.getInstance(keySeq.getObjectAt(0)));
151+
break;
152+
case MLDSA65_ECDSA_brainpoolP256r1_SHA512:
153+
privKeys[0] = createPrivateKey(new AlgorithmIdentifier(NISTObjectIdentifiers.id_ml_dsa_65), ASN1OctetString.getInstance(keySeq.getObjectAt(0)));
154+
privKeys[1] = createPrivateKey(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, TeleTrusTObjectIdentifiers.brainpoolP256r1), ASN1OctetString.getInstance(keySeq.getObjectAt(0)));
155+
break;
156+
case MLDSA87_ECDSA_P384_SHA512:
157+
privKeys[0] = createPrivateKey(new AlgorithmIdentifier(NISTObjectIdentifiers.id_ml_dsa_87), ASN1OctetString.getInstance(keySeq.getObjectAt(0)));
158+
privKeys[1] = createPrivateKey(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, SECObjectIdentifiers.secp384r1), ASN1OctetString.getInstance(keySeq.getObjectAt(0)));
159+
break;
160+
case MLDSA87_ECDSA_brainpoolP384r1_SHA512:
161+
privKeys[0] = createPrivateKey(new AlgorithmIdentifier(NISTObjectIdentifiers.id_ml_dsa_87), ASN1OctetString.getInstance(keySeq.getObjectAt(0)));
162+
privKeys[1] = createPrivateKey(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, TeleTrusTObjectIdentifiers.brainpoolP384r1), ASN1OctetString.getInstance(keySeq.getObjectAt(0)));
163+
break;
164+
case Falcon512_ECDSA_P256_SHA256:
165+
privKeys[0] = createPrivateKey(new AlgorithmIdentifier(BCObjectIdentifiers.falcon_512), ASN1OctetString.getInstance(keySeq.getObjectAt(0)));
166+
privKeys[1] = createPrivateKey(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, SECObjectIdentifiers.secp256r1), ASN1OctetString.getInstance(keySeq.getObjectAt(0)));
167+
break;
168+
case Falcon512_ECDSA_brainpoolP256r1_SHA256:
169+
privKeys[0] = createPrivateKey(new AlgorithmIdentifier(BCObjectIdentifiers.falcon_512), ASN1OctetString.getInstance(keySeq.getObjectAt(0)));
170+
privKeys[1] = createPrivateKey(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, TeleTrusTObjectIdentifiers.brainpoolP256r1), ASN1OctetString.getInstance(keySeq.getObjectAt(0)));
171+
break;
172+
case Falcon512_Ed25519_SHA512:
173+
privKeys[0] = createPrivateKey(new AlgorithmIdentifier(BCObjectIdentifiers.falcon_512), ASN1OctetString.getInstance(keySeq.getObjectAt(0)));
174+
privKeys[1] = createPrivateKey(new AlgorithmIdentifier(EdECObjectIdentifiers.id_Ed25519), ASN1OctetString.getInstance(keySeq.getObjectAt(0)));
175+
break;
176+
default:
177+
throw new IllegalArgumentException("unknown composite algorithm");
108178
}
109-
else
179+
}
180+
else
181+
{
182+
for (int i = 0; i != keySeq.size(); i++)
110183
{
184+
ASN1Sequence kSeq = ASN1Sequence.getInstance(keySeq.getObjectAt(i));
185+
111186
PrivateKeyInfo privInfo = PrivateKeyInfo.getInstance(kSeq);
112187

113188
privKeys[i] = provider.getKeyInfoConverter(
114-
privInfo.getPrivateKeyAlgorithm().getAlgorithm()).generatePrivate(privInfo);
189+
privInfo.getPrivateKeyAlgorithm().getAlgorithm()).generatePrivate(privInfo);
115190
}
116191
}
117192

118193
return new CompositePrivateKey(privKeys);
119194
}
120195

196+
private PrivateKey createPrivateKey(AlgorithmIdentifier algId, ASN1OctetString enc)
197+
throws IOException
198+
{
199+
ASN1EncodableVector v = new ASN1EncodableVector();
200+
201+
v.add(new ASN1Integer(0));
202+
v.add(algId);
203+
v.add(enc);
204+
205+
PrivateKeyInfo privInfo = PrivateKeyInfo.getInstance(new DERSequence(v));
206+
207+
return provider.getKeyInfoConverter(
208+
privInfo.getPrivateKeyAlgorithm().getAlgorithm()).generatePrivate(privInfo);
209+
}
210+
121211
public PublicKey generatePublic(SubjectPublicKeyInfo keyInfo)
122212
throws IOException
123213
{

0 commit comments

Comments
 (0)