Skip to content

Commit ca7c312

Browse files
committed
Refactor composite keys
1 parent 90a3b17 commit ca7c312

3 files changed

Lines changed: 61 additions & 47 deletions

File tree

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

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -267,57 +267,67 @@ public String getFormat()
267267
*/
268268
public byte[] getEncoded()
269269
{
270-
if (this.algorithmIdentifier.getAlgorithm().on(IANAObjectIdentifiers.id_alg))
270+
ASN1ObjectIdentifier algOid = algorithmIdentifier.getAlgorithm();
271+
272+
if (algOid.on(IANAObjectIdentifiers.id_alg))
271273
{
272274
try
273275
{
274276
PrivateKey key0 = keys.get(0);
275277
PrivateKey key1 = keys.get(1);
276278

277-
byte[] mldsaKey = ((MLDSAPrivateKey)key0).getSeed();
279+
byte[] mldsaSeed = ((MLDSAPrivateKey)key0).getSeed();
278280

279-
byte[] key1Encoded = key1.getEncoded();
280-
PrivateKeyInfo pki = PrivateKeyInfo.getInstance(key1Encoded);
281+
PrivateKeyInfo pki = PrivateKeyInfo.getInstance(key1.getEncoded());
281282

282-
byte[] tradKey;
283+
byte[] tradSK;
283284
String key1Algorithm = key1.getAlgorithm();
284285
if (key1Algorithm.contains("Ed"))
285286
{
286-
tradKey = ASN1OctetString.getInstance(pki.parsePrivateKey()).getOctets();
287+
tradSK = ASN1OctetString.getInstance(pki.parsePrivateKey()).getOctets();
287288
}
288289
else if (key1Algorithm.contains("EC"))
289290
{
290291
ECPrivateKey ecPrivateKey = ECPrivateKey.getInstance(pki.parsePrivateKey());
291292

292-
// TODO Do we also want to remove any parameters from the ECPrivateKey?
293+
/*
294+
* TODO
295+
* - Confirm pki.privateKeyAlgorithm is id_ecPublicKey with X9.62 Parameters namedCurve OID.
296+
* - If ecPrivateKey.parameters are present, must match pki.privateKeyAlgorithm
297+
* The private key MUST be encoded as ECPrivateKey specified in [RFC5915] with the 'NamedCurve'
298+
* parameter set to the OID of the curve, but without the 'publicKey' field.
299+
*/
300+
// TODO Also need to ensure that ECPrivateKey.parameters are present
293301
ASN1BitString publicKey = ecPrivateKey.getPublicKey();
294302
if (publicKey != null)
295303
{
296304
ecPrivateKey = new ECPrivateKey(ecPrivateKey.getPrivateKey(), ecPrivateKey.getParametersObject(), null);
297305
}
298306

299-
tradKey = ecPrivateKey.getEncoded();
307+
tradSK = ecPrivateKey.getEncoded(ASN1Encoding.DER);
300308
}
301309
else
302310
{
303-
tradKey = pki.getPrivateKey().getOctets();
311+
tradSK = pki.getPrivateKey().getOctets();
304312
}
305313

306-
return new PrivateKeyInfo(algorithmIdentifier, Arrays.concatenate(mldsaKey, tradKey)).getEncoded();
314+
return new PrivateKeyInfo(algorithmIdentifier, Arrays.concatenate(mldsaSeed, tradSK)).getEncoded();
307315
}
308316
catch (IOException e)
309317
{
310318
throw new IllegalStateException("unable to encode composite public key: " + e.getMessage());
311319
}
312320
}
321+
313322
ASN1EncodableVector v = new ASN1EncodableVector();
314323

315-
if (algorithmIdentifier.getAlgorithm().equals(MiscObjectIdentifiers.id_composite_key))
324+
if (MiscObjectIdentifiers.id_composite_key.equals(algOid))
316325
{
317326
for (int i = 0; i < keys.size(); i++)
318327
{
319-
PrivateKeyInfo info = PrivateKeyInfo.getInstance(keys.get(i).getEncoded());
320-
v.add(info);
328+
PrivateKeyInfo pki = PrivateKeyInfo.getInstance(keys.get(i).getEncoded());
329+
330+
v.add(pki);
321331
}
322332

323333
try
@@ -334,8 +344,9 @@ else if (key1Algorithm.contains("EC"))
334344
byte[] keyEncoding = null;
335345
for (int i = 0; i < keys.size(); i++)
336346
{
337-
PrivateKeyInfo info = PrivateKeyInfo.getInstance(keys.get(i).getEncoded());
338-
keyEncoding = Arrays.concatenate(keyEncoding, info.getPrivateKey().getOctets());
347+
PrivateKeyInfo pki = PrivateKeyInfo.getInstance(keys.get(i).getEncoded());
348+
349+
keyEncoding = Arrays.concatenate(keyEncoding, pki.getPrivateKey().getOctets());
339350
}
340351

341352
try

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

Lines changed: 21 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -246,13 +246,15 @@ public String getFormat()
246246
@Override
247247
public byte[] getEncoded()
248248
{
249-
if (this.algorithmIdentifier.getAlgorithm().on(IANAObjectIdentifiers.id_alg))
249+
ASN1ObjectIdentifier algOid = algorithmIdentifier.getAlgorithm();
250+
251+
if (algOid.on(IANAObjectIdentifiers.id_alg))
250252
{
251253
try
252254
{
253-
byte[] mldsaKey = org.bouncycastle.pqc.crypto.util.SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(org.bouncycastle.pqc.crypto.util.PublicKeyFactory.createKey(keys.get(0).getEncoded())).getPublicKeyData().getBytes();
254-
byte[] tradKey = SubjectPublicKeyInfo.getInstance(keys.get(1).getEncoded()).getPublicKeyData().getBytes();
255-
return new SubjectPublicKeyInfo(getAlgorithmIdentifier(), Arrays.concatenate(mldsaKey, tradKey)).getEncoded();
255+
byte[] mldsaPK = SubjectPublicKeyInfo.getInstance(keys.get(0).getEncoded()).getPublicKeyData().getOctets();
256+
byte[] tradPK = SubjectPublicKeyInfo.getInstance(keys.get(1).getEncoded()).getPublicKeyData().getOctets();
257+
return new SubjectPublicKeyInfo(algorithmIdentifier, Arrays.concatenate(mldsaPK, tradPK)).getEncoded(ASN1Encoding.DER);
256258
}
257259
catch (IOException e)
258260
{
@@ -264,18 +266,20 @@ public byte[] getEncoded()
264266

265267
for (int i = 0; i < keys.size(); i++)
266268
{
267-
if (this.algorithmIdentifier.getAlgorithm().equals(MiscObjectIdentifiers.id_composite_key))
269+
SubjectPublicKeyInfo spki = SubjectPublicKeyInfo.getInstance(keys.get(i).getEncoded());
270+
271+
if (MiscObjectIdentifiers.id_composite_key.equals(algOid))
268272
{
269273
//Legacy, component is the whole SubjectPublicKeyInfo
270-
v.add(SubjectPublicKeyInfo.getInstance(keys.get(i).getEncoded()));
274+
v.add(spki);
271275
}
272276
else
273277
{
274278
//component is the value of subjectPublicKey from SubjectPublicKeyInfo
275-
SubjectPublicKeyInfo keyInfo = SubjectPublicKeyInfo.getInstance(keys.get(i).getEncoded());
276-
v.add(keyInfo.getPublicKeyData());
279+
v.add(spki.getPublicKeyData());
277280
}
278281
}
282+
279283
try
280284
{
281285
return new SubjectPublicKeyInfo(this.algorithmIdentifier, new DERSequence(v)).getEncoded(ASN1Encoding.DER);
@@ -286,31 +290,26 @@ public byte[] getEncoded()
286290
}
287291
}
288292

289-
290293
public int hashCode()
291294
{
292-
return keys.hashCode();
295+
return algorithmIdentifier.hashCode() ^ keys.hashCode();
293296
}
294297

295-
public boolean equals(Object o)
298+
public boolean equals(Object obj)
296299
{
297-
if (o == this)
300+
if (obj == this)
298301
{
299302
return true;
300303
}
301304

302-
if (o instanceof CompositePublicKey)
305+
if (!(obj instanceof CompositePublicKey))
303306
{
304-
boolean isEqual = true;
305-
CompositePublicKey comparedKey = (CompositePublicKey)o;
306-
if (!comparedKey.getAlgorithmIdentifier().equals(this.algorithmIdentifier) || !this.keys.equals(comparedKey.keys))
307-
{
308-
isEqual = false;
309-
}
310-
311-
return isEqual;
307+
return false;
312308
}
313309

314-
return false;
310+
CompositePublicKey that = (CompositePublicKey)obj;
311+
312+
return this.algorithmIdentifier.equals(that.algorithmIdentifier)
313+
&& this.keys.equals(that.keys);
315314
}
316315
}

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

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
import org.bouncycastle.asn1.DERBitString;
2626
import org.bouncycastle.asn1.DEROctetString;
2727
import org.bouncycastle.asn1.DERSequence;
28-
import org.bouncycastle.asn1.bc.BCObjectIdentifiers;
2928
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
3029
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
3130
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
@@ -56,20 +55,24 @@ public class KeyFactorySpi
5655
extends BaseKeyFactorySpi
5756
implements AsymmetricKeyInfoConverter
5857
{
58+
private static AlgorithmIdentifier createECAlgID(ASN1ObjectIdentifier curveOid)
59+
{
60+
return new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, new X962Parameters(curveOid));
61+
}
5962

6063
//Specific algorithm identifiers of all component signature algorithms for SubjectPublicKeyInfo. These do not need to be all initialized here but makes the code more readable IMHO.
6164
private static final AlgorithmIdentifier mlDsa44 = new AlgorithmIdentifier(NISTObjectIdentifiers.id_ml_dsa_44);
6265
private static final AlgorithmIdentifier mlDsa65 = new AlgorithmIdentifier(NISTObjectIdentifiers.id_ml_dsa_65);
6366
private static final AlgorithmIdentifier mlDsa87 = new AlgorithmIdentifier(NISTObjectIdentifiers.id_ml_dsa_87);
64-
private static final AlgorithmIdentifier falcon512Identifier = new AlgorithmIdentifier(BCObjectIdentifiers.falcon_512);
67+
// private static final AlgorithmIdentifier falcon512Identifier = new AlgorithmIdentifier(BCObjectIdentifiers.falcon_512);
6568
private static final AlgorithmIdentifier ed25519 = new AlgorithmIdentifier(EdECObjectIdentifiers.id_Ed25519);
66-
private static final AlgorithmIdentifier ecDsaP256 = new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, new X962Parameters(SECObjectIdentifiers.secp256r1));
67-
private static final AlgorithmIdentifier ecDsaBrainpoolP256r1 = new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, new X962Parameters(TeleTrusTObjectIdentifiers.brainpoolP256r1));
68-
private static final AlgorithmIdentifier rsa = new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption);
6969
private static final AlgorithmIdentifier ed448 = new AlgorithmIdentifier(EdECObjectIdentifiers.id_Ed448);
70-
private static final AlgorithmIdentifier ecDsaP384 = new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, new X962Parameters(SECObjectIdentifiers.secp384r1));
71-
private static final AlgorithmIdentifier ecDsaP521 = new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, new X962Parameters(SECObjectIdentifiers.secp521r1));
72-
private static final AlgorithmIdentifier ecDsaBrainpoolP384r1 = new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, new X962Parameters(TeleTrusTObjectIdentifiers.brainpoolP384r1));
70+
private static final AlgorithmIdentifier ecDsaP256 = createECAlgID(SECObjectIdentifiers.secp256r1);
71+
private static final AlgorithmIdentifier ecDsaP384 = createECAlgID(SECObjectIdentifiers.secp384r1);
72+
private static final AlgorithmIdentifier ecDsaP521 = createECAlgID(SECObjectIdentifiers.secp521r1);
73+
private static final AlgorithmIdentifier ecDsaBrainpoolP256r1 = createECAlgID(TeleTrusTObjectIdentifiers.brainpoolP256r1);
74+
private static final AlgorithmIdentifier ecDsaBrainpoolP384r1 = createECAlgID(TeleTrusTObjectIdentifiers.brainpoolP384r1);
75+
private static final AlgorithmIdentifier rsa = new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption);
7376

7477
private static Map<ASN1ObjectIdentifier, AlgorithmIdentifier[]> pairings = new HashMap<ASN1ObjectIdentifier, AlgorithmIdentifier[]>();
7578
private static Map<ASN1ObjectIdentifier, int[]> componentKeySizes = new HashMap<ASN1ObjectIdentifier, int[]>();
@@ -289,7 +292,7 @@ public PublicKey generatePublic(SubjectPublicKeyInfo keyInfo)
289292

290293
try
291294
{
292-
seq = DERSequence.getInstance(keyInfo.getPublicKeyData().getBytes());
295+
seq = ASN1Sequence.getInstance(keyInfo.getPublicKeyData().getOctets());
293296
}
294297
catch (Exception e)
295298
{
@@ -299,7 +302,8 @@ public PublicKey generatePublic(SubjectPublicKeyInfo keyInfo)
299302
if (MiscObjectIdentifiers.id_alg_composite.equals(keyIdentifier)
300303
|| MiscObjectIdentifiers.id_composite_key.equals(keyIdentifier))
301304
{
302-
ASN1Sequence keySeq = ASN1Sequence.getInstance(keyInfo.getPublicKeyData().getBytes());
305+
// TODO This is redundant with 'seq' calculation above
306+
ASN1Sequence keySeq = ASN1Sequence.getInstance(keyInfo.getPublicKeyData().getOctets());
303307
PublicKey[] pubKeys = new PublicKey[keySeq.size()];
304308

305309
for (int i = 0; i != keySeq.size(); i++)

0 commit comments

Comments
 (0)