Skip to content

Commit c6a7a2d

Browse files
committed
updated to use raw seed encodings for ML-KEM, ML-DSA, and SLH-DSA, added code for identifying previous wrapped encodings.
1 parent fa764c6 commit c6a7a2d

File tree

4 files changed

+97
-28
lines changed

4 files changed

+97
-28
lines changed

core/src/main/java/org/bouncycastle/asn1/pkcs/PrivateKeyInfo.java

Lines changed: 74 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import org.bouncycastle.asn1.ASN1BitString;
77
import org.bouncycastle.asn1.ASN1Encodable;
88
import org.bouncycastle.asn1.ASN1EncodableVector;
9+
import org.bouncycastle.asn1.ASN1Encoding;
910
import org.bouncycastle.asn1.ASN1Integer;
1011
import org.bouncycastle.asn1.ASN1Object;
1112
import org.bouncycastle.asn1.ASN1OctetString;
@@ -95,6 +96,27 @@ private static int getVersionValue(ASN1Integer version)
9596
return versionValue;
9697
}
9798

99+
/**
100+
* Construct a PrivateKeyInfo around a raw encoding.
101+
*
102+
* @param privateKeyAlgorithm algorithm identifier for the private key.
103+
* @param privateKey byte encoding of the private key, used as a raw encoding.
104+
*/
105+
public PrivateKeyInfo(
106+
AlgorithmIdentifier privateKeyAlgorithm,
107+
byte[] privateKey)
108+
throws IOException
109+
{
110+
this(privateKeyAlgorithm, privateKey, null, null);
111+
}
112+
113+
/**
114+
* Construct a PrivateKeyInfo around an ASN.1 structure/primitive.
115+
*
116+
* @param privateKeyAlgorithm algorithm identifier for the private key.
117+
* @param privateKey the ASN.1 structure/primitive representing the private key.
118+
* @throws IOException if encoding the privateKey object into an OCTET STRING fails.
119+
*/
98120
public PrivateKeyInfo(
99121
AlgorithmIdentifier privateKeyAlgorithm,
100122
ASN1Encodable privateKey)
@@ -103,6 +125,14 @@ public PrivateKeyInfo(
103125
this(privateKeyAlgorithm, privateKey, null, null);
104126
}
105127

128+
/**
129+
* Construct a PrivateKeyInfo around an ASN.1 structure/primitive with attributes.
130+
*
131+
* @param privateKeyAlgorithm algorithm identifier for the private key.
132+
* @param privateKey the ASN.1 structure/primitive representing the private key.
133+
* @param attributes attributes associated with private key.
134+
* @throws IOException if encoding the privateKey object into an OCTET STRING fails.
135+
*/
106136
public PrivateKeyInfo(
107137
AlgorithmIdentifier privateKeyAlgorithm,
108138
ASN1Encodable privateKey,
@@ -112,12 +142,55 @@ public PrivateKeyInfo(
112142
this(privateKeyAlgorithm, privateKey, attributes, null);
113143
}
114144

145+
/**
146+
* Construct a PrivateKeyInfo around an ASN.1 structure/primitive with attributes.
147+
*
148+
* @param privateKeyAlgorithm algorithm identifier for the private key.
149+
* @param privateKey byte encoding of the private key, used as a raw encoding.
150+
* @param attributes attributes associated with private key.
151+
* @throws IOException if encoding the privateKey object into an OCTET STRING fails.
152+
*/
153+
public PrivateKeyInfo(
154+
AlgorithmIdentifier privateKeyAlgorithm,
155+
byte[] privateKey,
156+
ASN1Set attributes)
157+
throws IOException
158+
{
159+
this(privateKeyAlgorithm, privateKey, attributes, null);
160+
}
161+
162+
/**
163+
* Construct a PrivateKeyInfo around an ASN.1 structure/primitive with attributes and the public key.
164+
*
165+
* @param privateKeyAlgorithm algorithm identifier for the private key.
166+
* @param privateKey the ASN.1 structure/primitive representing the private key.
167+
* @param attributes attributes associated with private key.
168+
* @param publicKey public key encoding.
169+
* @throws IOException if encoding the privateKey object into an OCTET STRING fails.
170+
*/
115171
public PrivateKeyInfo(
116172
AlgorithmIdentifier privateKeyAlgorithm,
117173
ASN1Encodable privateKey,
118174
ASN1Set attributes,
119175
byte[] publicKey)
120176
throws IOException
177+
{
178+
this(privateKeyAlgorithm, privateKey.toASN1Primitive().getEncoded(ASN1Encoding.DER), attributes, publicKey);
179+
}
180+
181+
/**
182+
* Construct a PrivateKeyInfo around a raw encoding with attributes and the public key.
183+
*
184+
* @param privateKeyAlgorithm algorithm identifier for the private key.
185+
* @param privateKey byte encoding of the private key, used as a raw encoding.
186+
* @param attributes attributes associated with private key.
187+
* @param publicKey public key encoding.
188+
*/
189+
public PrivateKeyInfo(
190+
AlgorithmIdentifier privateKeyAlgorithm,
191+
byte[] privateKey,
192+
ASN1Set attributes,
193+
byte[] publicKey)
121194
{
122195
this.version = new ASN1Integer(publicKey != null ? BigIntegers.ONE : BigIntegers.ZERO);
123196
this.privateKeyAlgorithm = privateKeyAlgorithm;
@@ -222,7 +295,7 @@ public boolean hasPublicKey()
222295
*
223296
* @return the public key as an ASN.1 primitive.
224297
* @throws IOException - if the bit string doesn't represent a DER
225-
* encoded object.
298+
* encoded object.
226299
*/
227300
public ASN1Encodable parsePublicKey()
228301
throws IOException

core/src/main/java/org/bouncycastle/pqc/crypto/slhdsa/SLHDSAParameters.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ public int getType()
9696
return preHashDigest;
9797
}
9898

99-
int getN()
99+
public int getN()
100100
{
101101
return engineProvider.getN();
102102
}

core/src/main/java/org/bouncycastle/pqc/crypto/util/PrivateKeyFactory.java

Lines changed: 17 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
import org.bouncycastle.asn1.ASN1OctetString;
1313
import org.bouncycastle.asn1.ASN1Primitive;
1414
import org.bouncycastle.asn1.ASN1Sequence;
15-
import org.bouncycastle.asn1.ASN1TaggedObject;
1615
import org.bouncycastle.asn1.BERTags;
1716
import org.bouncycastle.asn1.DEROctetString;
1817
import org.bouncycastle.asn1.bc.BCObjectIdentifiers;
@@ -200,8 +199,8 @@ else if (algOID.on(BCObjectIdentifiers.sphincsPlus) || algOID.on(BCObjectIdentif
200199
}
201200
else if (Utils.shldsaParams.containsKey(algOID))
202201
{
203-
ASN1OctetString slhdsaKey = parseOctetString(keyInfo.getPrivateKey());
204202
SLHDSAParameters spParams = Utils.slhdsaParamsLookup(algOID);
203+
ASN1OctetString slhdsaKey = parseOctetString(keyInfo.getPrivateKey(), spParams.getN() * 4);
205204

206205
return new SLHDSAPrivateKeyParameters(spParams, slhdsaKey.getOctets());
207206
}
@@ -244,7 +243,7 @@ else if (algOID.equals(NISTObjectIdentifiers.id_alg_ml_kem_512) ||
244243
algOID.equals(NISTObjectIdentifiers.id_alg_ml_kem_768) ||
245244
algOID.equals(NISTObjectIdentifiers.id_alg_ml_kem_1024))
246245
{
247-
ASN1OctetString mlkemKey = parseOctetString(keyInfo.getPrivateKey());
246+
ASN1OctetString mlkemKey = parseOctetString(keyInfo.getPrivateKey(), 64);
248247
MLKEMParameters mlkemParams = Utils.mlkemParamsLookup(algOID);
249248

250249
return new MLKEMPrivateKeyParameters(mlkemParams, mlkemKey.getOctets());
@@ -276,7 +275,7 @@ else if (algOID.on(BCObjectIdentifiers.pqc_kem_sntruprime))
276275
}
277276
else if (Utils.mldsaParams.containsKey(algOID))
278277
{
279-
ASN1Encodable keyObj = parseOctetString(keyInfo.getPrivateKey());
278+
ASN1Encodable keyObj = parseOctetString(keyInfo.getPrivateKey(), 32);
280279
MLDSAParameters spParams = Utils.mldsaParamsLookup(algOID);
281280

282281
if (keyObj instanceof DEROctetString)
@@ -466,31 +465,28 @@ else if (algOID.equals(PQCObjectIdentifiers.mcElieceCca2))
466465
/**
467466
* So it seems for the new PQC algorithms, there's a couple of approaches to what goes in the OCTET STRING
468467
*/
469-
private static ASN1OctetString parseOctetString(ASN1OctetString octStr)
468+
private static ASN1OctetString parseOctetString(ASN1OctetString octStr, int expectedLength)
470469
{
471-
ByteArrayInputStream bIn = new ByteArrayInputStream(octStr.getOctets());
470+
byte[] data = octStr.getOctets();
471+
//
472+
// it's the right length for a RAW encoding, just return it.
473+
//
474+
if (data.length == expectedLength)
475+
{
476+
return octStr;
477+
}
478+
479+
//
480+
// possible internal OCTET STRING, possibly long form with or without the internal OCTET STRING
481+
ByteArrayInputStream bIn = new ByteArrayInputStream(data);
472482

473483
int tag = bIn.read();
474484
int len = readLen(bIn);
475485
if (tag == BERTags.OCTET_STRING)
476486
{
477487
if (len == bIn.available())
478488
{
479-
return ASN1OctetString.getInstance(octStr.getOctets());
480-
}
481-
}
482-
if (tag == BERTags.CONTEXT_SPECIFIC)
483-
{
484-
if (len == bIn.available())
485-
{
486-
return ASN1OctetString.getInstance(ASN1TaggedObject.getInstance(octStr.getOctets()), false);
487-
}
488-
}
489-
if (tag == (BERTags.CONTEXT_SPECIFIC | BERTags.CONSTRUCTED))
490-
{
491-
if (len == bIn.available())
492-
{
493-
return ASN1OctetString.getInstance(ASN1TaggedObject.getInstance(octStr.getOctets()), true);
489+
return ASN1OctetString.getInstance(data);
494490
}
495491
}
496492

core/src/main/java/org/bouncycastle/pqc/crypto/util/PrivateKeyInfoFactory.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ else if (privateKey instanceof SLHDSAPrivateKeyParameters)
150150

151151
AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(Utils.slhdsaOidLookup(params.getParameters()));
152152

153-
return new PrivateKeyInfo(algorithmIdentifier, new DEROctetString(params.getEncoded()), attributes, params.getPublicKey());
153+
return new PrivateKeyInfo(algorithmIdentifier, params.getEncoded(), attributes, params.getPublicKey());
154154
}
155155
else if (privateKey instanceof PicnicPrivateKeyParameters)
156156
{
@@ -250,11 +250,11 @@ else if (privateKey instanceof MLKEMPrivateKeyParameters)
250250
byte[] seed = params.getSeed();
251251
if (seed == null)
252252
{
253-
return new PrivateKeyInfo(algorithmIdentifier, new DEROctetString(params.getEncoded()), attributes);
253+
return new PrivateKeyInfo(algorithmIdentifier, params.getEncoded(), attributes);
254254
}
255255
else
256256
{
257-
return new PrivateKeyInfo(algorithmIdentifier, new DEROctetString(seed), attributes);
257+
return new PrivateKeyInfo(algorithmIdentifier, seed, attributes);
258258
}
259259
}
260260
else if (privateKey instanceof NTRULPRimePrivateKeyParameters)
@@ -299,13 +299,13 @@ else if (privateKey instanceof MLDSAPrivateKeyParameters)
299299
{
300300
MLDSAPublicKeyParameters pubParams = params.getPublicKeyParameters();
301301

302-
return new PrivateKeyInfo(algorithmIdentifier, new DEROctetString(params.getEncoded()), attributes, pubParams.getEncoded());
302+
return new PrivateKeyInfo(algorithmIdentifier, params.getEncoded(), attributes, pubParams.getEncoded());
303303
}
304304
else
305305
{
306306
MLDSAPublicKeyParameters pubParams = params.getPublicKeyParameters();
307307

308-
return new PrivateKeyInfo(algorithmIdentifier, new DEROctetString(params.getSeed()), attributes);
308+
return new PrivateKeyInfo(algorithmIdentifier, params.getSeed(), attributes);
309309
}
310310
}
311311
else if (privateKey instanceof DilithiumPrivateKeyParameters)

0 commit comments

Comments
 (0)