Skip to content

Commit 93007c4

Browse files
committed
added raw encoding for composite private keys.
1 parent ee7336f commit 93007c4

File tree

4 files changed

+63
-15
lines changed

4 files changed

+63
-15
lines changed

docs/releasenotes.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ <h3>2.1.2 Defects Fixed</h3>
2828
<h3>2.2.3 Additional Features and Functionality</h3>
2929
<ul>
3030
<li>CompositeSignatures now updated to draft-ietf-lamps-pq-composite-sigs-03.</li>
31+
<li>ML-KEM, ML-DSA, SLH-DSA, and Composite private keys now use raw encodings as per the latest drafts from IETF 121: draft-ietf-lamps-kyber-certificates-06, draft-ietf-lamps-dilithium-certificates-05, and draft-ietf-lamps-x509-slhdsa.</li>
3132
</ul>
3233

3334
<a id="r1rv79"><h3>2.2.1 Version</h3></a>

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

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

33
import java.io.ByteArrayInputStream;
44
import java.io.FileOutputStream;
5-
import java.io.FileWriter;
65
import java.io.IOException;
76
import java.io.StringReader;
87
import java.io.StringWriter;
@@ -49,6 +48,7 @@
4948
import org.bouncycastle.jce.provider.BouncyCastleProvider;
5049
import org.bouncycastle.jce.spec.ECNamedCurveGenParameterSpec;
5150
import org.bouncycastle.openssl.PEMParser;
51+
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
5252
import org.bouncycastle.openssl.jcajce.JcaPEMWriter;
5353
import org.bouncycastle.operator.ContentSigner;
5454
import org.bouncycastle.operator.ContentVerifierProvider;
@@ -476,19 +476,27 @@ public void testMLDSA44andP256()
476476

477477
CompositePrivateKey mlecPriv = new CompositePrivateKey(MiscObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256, mldsaPriv, ecPriv);
478478

479-
JcaPEMWriter pWrt = new JcaPEMWriter(new FileWriter("/tmp/mldsa44_ec_p256_priv.pem"));
479+
StringWriter sWrt = new StringWriter();
480+
JcaPEMWriter pWrt = new JcaPEMWriter(sWrt);
480481

481482
pWrt.writeObject(mlecPriv);
482483

483484
pWrt.close();
484485

485486
CompositePublicKey mlecPub = new CompositePublicKey(mldsaPub, ecPub);
486487

487-
pWrt = new JcaPEMWriter(new FileWriter("/tmp/mldsa44_ec_p256_pub.pem"));
488+
pWrt = new JcaPEMWriter(sWrt);
488489

489490
pWrt.writeObject(mlecPub);
490491

491492
pWrt.close();
493+
494+
PEMParser pPrs = new PEMParser(new StringReader(sWrt.toString()));
495+
496+
JcaPEMKeyConverter keyConverter = new JcaPEMKeyConverter().setProvider("BC");
497+
CompositePrivateKey prKey = (CompositePrivateKey)keyConverter.getPrivateKey((PrivateKeyInfo)pPrs.readObject());
498+
499+
CompositePublicKey puKey = (CompositePublicKey)keyConverter.getPublicKey((SubjectPublicKeyInfo)pPrs.readObject());
492500
}
493501

494502
public void testMLDSA87andEd448()
@@ -513,19 +521,27 @@ public void testMLDSA87andEd448()
513521

514522
CompositePrivateKey mlecPriv = new CompositePrivateKey(MiscObjectIdentifiers.id_MLDSA87_Ed448_SHA512, mldsaPriv, ecPriv);
515523

516-
JcaPEMWriter pWrt = new JcaPEMWriter(new FileWriter("/tmp/mldsa87_ed448_priv.pem"));
524+
StringWriter sWrt = new StringWriter();
525+
JcaPEMWriter pWrt = new JcaPEMWriter(sWrt);
517526

518527
pWrt.writeObject(mlecPriv);
519528

520529
pWrt.close();
521530

522531
CompositePublicKey mlecPub = new CompositePublicKey(mldsaPub, ecPub);
523532

524-
pWrt = new JcaPEMWriter(new FileWriter("/tmp/mldsa87_ed448_pub.pem"));
533+
pWrt = new JcaPEMWriter(sWrt);
525534

526535
pWrt.writeObject(mlecPub);
527536

528537
pWrt.close();
538+
539+
PEMParser pPrs = new PEMParser(new StringReader(sWrt.toString()));
540+
541+
JcaPEMKeyConverter keyConverter = new JcaPEMKeyConverter().setProvider("BC");
542+
CompositePrivateKey prKey = (CompositePrivateKey)keyConverter.getPrivateKey((PrivateKeyInfo)pPrs.readObject());
543+
544+
CompositePublicKey puKey = (CompositePublicKey)keyConverter.getPublicKey((SubjectPublicKeyInfo)pPrs.readObject());
529545
}
530546

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

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

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import org.bouncycastle.jcajce.provider.asymmetric.compositesignatures.CompositeIndex;
1717
import org.bouncycastle.jcajce.provider.asymmetric.compositesignatures.KeyFactorySpi;
1818
import org.bouncycastle.jcajce.provider.util.AsymmetricKeyInfoConverter;
19+
import org.bouncycastle.util.Arrays;
1920
import org.bouncycastle.util.Exceptions;
2021

2122
/**
@@ -138,23 +139,33 @@ public byte[] getEncoded()
138139
PrivateKeyInfo info = PrivateKeyInfo.getInstance(keys.get(i).getEncoded());
139140
v.add(info);
140141
}
142+
143+
try
144+
{
145+
return new PrivateKeyInfo(new AlgorithmIdentifier(this.algorithmIdentifier), new DERSequence(v)).getEncoded(ASN1Encoding.DER);
146+
}
147+
catch (IOException e)
148+
{
149+
throw new IllegalStateException("unable to encode composite private key: " + e.getMessage());
150+
}
141151
}
142152
else
143153
{
154+
byte[] keyEncoding = null;
144155
for (int i = 0; i < keys.size(); i++)
145156
{
146157
PrivateKeyInfo info = PrivateKeyInfo.getInstance(keys.get(i).getEncoded());
147-
v.add(info.getPrivateKey());
158+
keyEncoding = Arrays.concatenate(keyEncoding, info.getPrivateKey().getOctets());
148159
}
149-
}
150160

151-
try
152-
{
153-
return new PrivateKeyInfo(new AlgorithmIdentifier(this.algorithmIdentifier), new DERSequence(v)).getEncoded(ASN1Encoding.DER);
154-
}
155-
catch (IOException e)
156-
{
157-
throw new IllegalStateException("unable to encode composite private key: " + e.getMessage());
161+
try
162+
{
163+
return new PrivateKeyInfo(new AlgorithmIdentifier(this.algorithmIdentifier), keyEncoding).getEncoded(ASN1Encoding.DER);
164+
}
165+
catch (IOException e)
166+
{
167+
throw new IllegalStateException("unable to encode composite private key: " + e.getMessage());
168+
}
158169
}
159170
}
160171

prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/compositesignatures/KeyFactorySpi.java

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import org.bouncycastle.jcajce.provider.util.AsymmetricKeyInfoConverter;
4444
import org.bouncycastle.jcajce.util.BCJcaJceHelper;
4545
import org.bouncycastle.jcajce.util.JcaJceHelper;
46+
import org.bouncycastle.util.Arrays;
4647
import org.bouncycastle.util.Exceptions;
4748

4849
/**
@@ -157,12 +158,13 @@ public PrivateKey generatePrivate(PrivateKeyInfo keyInfo)
157158
helper = new BCJcaJceHelper();
158159
}
159160

160-
ASN1Sequence seq = DERSequence.getInstance(keyInfo.parsePrivateKey());
161161
ASN1ObjectIdentifier keyIdentifier = keyInfo.getPrivateKeyAlgorithm().getAlgorithm();
162162

163163
if (MiscObjectIdentifiers.id_alg_composite.equals(keyIdentifier)
164164
|| MiscObjectIdentifiers.id_composite_key.equals(keyIdentifier))
165165
{
166+
ASN1Sequence seq = DERSequence.getInstance(keyInfo.parsePrivateKey());
167+
166168
PrivateKey[] privKeys = new PrivateKey[seq.size()];
167169

168170
for (int i = 0; i != seq.size(); i++)
@@ -186,6 +188,24 @@ public PrivateKey generatePrivate(PrivateKeyInfo keyInfo)
186188
}
187189
try
188190
{
191+
ASN1Sequence seq;
192+
// TODO: backwards compatibility code - should be deleted after 1.84.
193+
try
194+
{
195+
seq = DERSequence.getInstance(keyInfo.parsePrivateKey());
196+
}
197+
catch (Exception e)
198+
{
199+
// new raw encoding - we capitalise on the fact initial key is first 32 bytes.
200+
ASN1EncodableVector v = new ASN1EncodableVector();
201+
byte[] data = keyInfo.getPrivateKey().getOctets();
202+
203+
v.add(new DEROctetString(Arrays.copyOfRange(data, 0, 32)));
204+
v.add(new DEROctetString(Arrays.copyOfRange(data, 32, data.length)));
205+
206+
seq = new DERSequence(v);
207+
}
208+
189209
List<KeyFactory> factories = getKeyFactoriesFromIdentifier(keyIdentifier); //Get key factories for each component algorithm.
190210
PrivateKey[] privateKeys = new PrivateKey[seq.size()];
191211
AlgorithmIdentifier[] algIds = pairings.get(keyIdentifier);

0 commit comments

Comments
 (0)