Skip to content

Commit 6e67c1a

Browse files
author
gefeili
committed
Merge branch 'main' into 1958-aead-parameters
2 parents aba4b59 + bee6734 commit 6e67c1a

File tree

49 files changed

+1113
-1417
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+1113
-1417
lines changed

core/src/main/java/org/bouncycastle/asn1/x509/CertificateList.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,11 @@ public Time getNextUpdate()
117117
return tbsCertList.getNextUpdate();
118118
}
119119

120+
public Extensions getExtensions()
121+
{
122+
return tbsCertList.getExtensions();
123+
}
124+
120125
public ASN1Primitive toASN1Primitive()
121126
{
122127
ASN1EncodableVector v = new ASN1EncodableVector(3);

core/src/main/java/org/bouncycastle/asn1/x509/Extensions.java

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import org.bouncycastle.asn1.ASN1EncodableVector;
99
import org.bouncycastle.asn1.ASN1Object;
1010
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
11+
import org.bouncycastle.asn1.ASN1OctetString;
1112
import org.bouncycastle.asn1.ASN1Primitive;
1213
import org.bouncycastle.asn1.ASN1Sequence;
1314
import org.bouncycastle.asn1.ASN1TaggedObject;
@@ -40,6 +41,11 @@ public static ASN1Encodable getExtensionParsedValue(Extensions extensions, ASN1O
4041
return null == extensions ? null : extensions.getExtensionParsedValue(oid);
4142
}
4243

44+
public static ASN1OctetString getExtensionValue(Extensions extensions, ASN1ObjectIdentifier oid)
45+
{
46+
return null == extensions ? null : extensions.getExtensionValue(oid);
47+
}
48+
4349
public static Extensions getInstance(
4450
ASN1TaggedObject obj,
4551
boolean explicit)
@@ -141,8 +147,7 @@ public Enumeration oids()
141147
*
142148
* @return the extension if it's present, null otherwise.
143149
*/
144-
public Extension getExtension(
145-
ASN1ObjectIdentifier oid)
150+
public Extension getExtension(ASN1ObjectIdentifier oid)
146151
{
147152
return (Extension)extensions.get(oid);
148153
}
@@ -155,14 +160,19 @@ public Extension getExtension(
155160
*/
156161
public ASN1Encodable getExtensionParsedValue(ASN1ObjectIdentifier oid)
157162
{
158-
Extension ext = this.getExtension(oid);
159-
160-
if (ext != null)
161-
{
162-
return ext.getParsedValue();
163-
}
163+
Extension ext = getExtension(oid);
164+
return ext == null ? null : ext.getParsedValue();
165+
}
164166

165-
return null;
167+
/**
168+
* return the value of the extension represented by the object identifier passed in.
169+
*
170+
* @return the value of the extension if it's present, null otherwise.
171+
*/
172+
public ASN1OctetString getExtensionValue(ASN1ObjectIdentifier oid)
173+
{
174+
Extension ext = getExtension(oid);
175+
return ext == null ? null : ext.getExtnValue();
166176
}
167177

168178
/**
@@ -229,6 +239,21 @@ public ASN1ObjectIdentifier[] getCriticalExtensionOIDs()
229239
return getExtensionOIDs(true);
230240
}
231241

242+
public boolean hasAnyCriticalExtensions()
243+
{
244+
for (int i = 0; i != ordering.size(); i++)
245+
{
246+
Object oid = ordering.elementAt(i);
247+
248+
if (((Extension)extensions.get(oid)).isCritical())
249+
{
250+
return true;
251+
}
252+
}
253+
254+
return false;
255+
}
256+
232257
private ASN1ObjectIdentifier[] getExtensionOIDs(boolean isCritical)
233258
{
234259
Vector oidVec = new Vector();
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package org.bouncycastle.crypto.agreement;
2+
3+
import java.math.BigInteger;
4+
5+
import org.bouncycastle.crypto.BasicAgreement;
6+
import org.bouncycastle.crypto.CipherParameters;
7+
import org.bouncycastle.crypto.RawAgreement;
8+
import org.bouncycastle.util.BigIntegers;
9+
10+
public final class BasicRawAgreement
11+
implements RawAgreement
12+
{
13+
public final BasicAgreement basicAgreement;
14+
15+
public BasicRawAgreement(BasicAgreement basicAgreement)
16+
{
17+
if (basicAgreement == null)
18+
{
19+
throw new NullPointerException("'basicAgreement' cannot be null");
20+
}
21+
22+
this.basicAgreement = basicAgreement;
23+
}
24+
25+
public void init(CipherParameters parameters)
26+
{
27+
basicAgreement.init(parameters);
28+
}
29+
30+
public int getAgreementSize()
31+
{
32+
return basicAgreement.getFieldSize();
33+
}
34+
35+
public void calculateAgreement(CipherParameters publicKey, byte[] buf, int off)
36+
{
37+
BigInteger z = basicAgreement.calculateAgreement(publicKey);
38+
BigIntegers.asUnsignedByteArray(z, buf, off, getAgreementSize());
39+
}
40+
}

core/src/main/java/org/bouncycastle/crypto/hpke/DHKEM.java

Lines changed: 98 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@
55

66
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
77
import org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator;
8-
import org.bouncycastle.crypto.BasicAgreement;
98
import org.bouncycastle.crypto.CryptoServicesRegistrar;
9+
import org.bouncycastle.crypto.RawAgreement;
10+
import org.bouncycastle.crypto.agreement.BasicRawAgreement;
1011
import org.bouncycastle.crypto.agreement.ECDHCBasicAgreement;
11-
import org.bouncycastle.crypto.agreement.XDHBasicAgreement;
12+
import org.bouncycastle.crypto.agreement.X25519Agreement;
13+
import org.bouncycastle.crypto.agreement.X448Agreement;
1214
import org.bouncycastle.crypto.ec.CustomNamedCurves;
1315
import org.bouncycastle.crypto.generators.ECKeyPairGenerator;
1416
import org.bouncycastle.crypto.generators.X25519KeyPairGenerator;
@@ -27,6 +29,8 @@
2729
import org.bouncycastle.math.ec.ECPoint;
2830
import org.bouncycastle.math.ec.FixedPointCombMultiplier;
2931
import org.bouncycastle.math.ec.WNafUtil;
32+
import org.bouncycastle.math.ec.rfc7748.X25519;
33+
import org.bouncycastle.math.ec.rfc7748.X448;
3034
import org.bouncycastle.util.Arrays;
3135
import org.bouncycastle.util.BigIntegers;
3236
import org.bouncycastle.util.Pack;
@@ -37,7 +41,7 @@ class DHKEM
3741
{
3842
private AsymmetricCipherKeyPairGenerator kpGen;
3943

40-
private BasicAgreement agreement;
44+
private RawAgreement rawAgreement;
4145

4246
// kem ids
4347
private final short kemId;
@@ -59,7 +63,7 @@ protected DHKEM(short kemid)
5963
case HPKE.kem_P256_SHA256:
6064
this.hkdf = new HKDF(HPKE.kdf_HKDF_SHA256);
6165
domainParams = getDomainParameters("P-256");
62-
this.agreement = new ECDHCBasicAgreement();
66+
rawAgreement = new BasicRawAgreement(new ECDHCBasicAgreement());
6367
bitmask = (byte)0xff;
6468
Nsk = 32;
6569
Nsecret = 32;
@@ -72,7 +76,7 @@ protected DHKEM(short kemid)
7276
case HPKE.kem_P384_SHA348:
7377
this.hkdf = new HKDF(HPKE.kdf_HKDF_SHA384);
7478
domainParams = getDomainParameters("P-384");
75-
this.agreement = new ECDHCBasicAgreement();
79+
rawAgreement = new BasicRawAgreement(new ECDHCBasicAgreement());
7680
bitmask = (byte)0xff;
7781
Nsk = 48;
7882
Nsecret = 48;
@@ -85,7 +89,7 @@ protected DHKEM(short kemid)
8589
case HPKE.kem_P521_SHA512:
8690
this.hkdf = new HKDF(HPKE.kdf_HKDF_SHA512);
8791
domainParams = getDomainParameters("P-521");
88-
this.agreement = new ECDHCBasicAgreement();
92+
rawAgreement = new BasicRawAgreement(new ECDHCBasicAgreement());
8993
bitmask = 0x01;
9094
Nsk = 66;
9195
Nsecret = 64;
@@ -97,7 +101,7 @@ protected DHKEM(short kemid)
97101
break;
98102
case HPKE.kem_X25519_SHA256:
99103
this.hkdf = new HKDF(HPKE.kdf_HKDF_SHA256);
100-
this.agreement = new XDHBasicAgreement();
104+
rawAgreement = new X25519Agreement();
101105
Nsecret = 32;
102106
Nsk = 32;
103107
Nenc = 32;
@@ -108,7 +112,7 @@ protected DHKEM(short kemid)
108112
break;
109113
case HPKE.kem_X448_SHA512:
110114
this.hkdf = new HKDF(HPKE.kdf_HKDF_SHA512);
111-
this.agreement = new XDHBasicAgreement();
115+
rawAgreement = new X448Agreement();
112116
Nsecret = 64;
113117
Nsk = 56;
114118
Nenc = 56;
@@ -129,6 +133,10 @@ public byte[] SerializePublicKey(AsymmetricKeyParameter key)
129133
case HPKE.kem_P256_SHA256:
130134
case HPKE.kem_P384_SHA348:
131135
case HPKE.kem_P521_SHA512:
136+
/*
137+
* RFC 9180 7.1.1. For P-256, P-384, and P-521, the SerializePublicKey() function of the KEM performs
138+
* the uncompressed Elliptic-Curve-Point-to-Octet-String conversion according to [SECG].
139+
*/
132140
return ((ECPublicKeyParameters)key).getQ().getEncoded(false);
133141
case HPKE.kem_X448_SHA512:
134142
return ((X448PublicKeyParameters)key).getEncoded();
@@ -146,30 +154,74 @@ public byte[] SerializePrivateKey(AsymmetricKeyParameter key)
146154
case HPKE.kem_P256_SHA256:
147155
case HPKE.kem_P384_SHA348:
148156
case HPKE.kem_P521_SHA512:
157+
{
158+
/*
159+
* RFC 9180 7.1.2. For P-256, P-384, and P-521, the SerializePrivateKey() function of the KEM
160+
* performs the Field-Element-to-Octet-String conversion according to [SECG].
161+
*/
149162
return BigIntegers.asUnsignedByteArray(Nsk, ((ECPrivateKeyParameters)key).getD());
163+
}
150164
case HPKE.kem_X448_SHA512:
151-
return ((X448PrivateKeyParameters)key).getEncoded();
165+
{
166+
/*
167+
* RFC 9180 7.1.2. For [..] X448 [..]. The SerializePrivateKey() function MUST clamp its output
168+
* [..].
169+
*
170+
* NOTE: Our X448 implementation clamps generated keys, but de-serialized keys are preserved as is
171+
* (clamping applied only during usage).
172+
*/
173+
byte[] encoded = ((X448PrivateKeyParameters)key).getEncoded();
174+
X448.clampPrivateKey(encoded);
175+
return encoded;
176+
}
152177
case HPKE.kem_X25519_SHA256:
153-
return ((X25519PrivateKeyParameters)key).getEncoded();
178+
{
179+
/*
180+
* RFC 9180 7.1.2. For X25519 [..]. The SerializePrivateKey() function MUST clamp its output [..].
181+
*
182+
* NOTE: Our X25519 implementation clamps generated keys, but de-serialized keys are preserved as
183+
* is (clamping applied only during usage).
184+
*/
185+
byte[] encoded = ((X25519PrivateKeyParameters)key).getEncoded();
186+
X25519.clampPrivateKey(encoded);
187+
return encoded;
188+
}
154189
default:
155190
throw new IllegalStateException("invalid kem id");
156191
}
157192
}
158193

159-
public AsymmetricKeyParameter DeserializePublicKey(byte[] encoded)
194+
public AsymmetricKeyParameter DeserializePublicKey(byte[] pkEncoded)
160195
{
196+
if (pkEncoded == null)
197+
{
198+
throw new NullPointerException("'pkEncoded' cannot be null");
199+
}
200+
if (pkEncoded.length != Nenc)
201+
{
202+
throw new IllegalArgumentException("'pkEncoded' has invalid length");
203+
}
204+
161205
switch (kemId)
162206
{
163207
case HPKE.kem_P256_SHA256:
164208
case HPKE.kem_P384_SHA348:
165209
case HPKE.kem_P521_SHA512:
166-
// TODO Does the encoding have to be uncompressed? (i.e. encoded.length MUST be Nenc?)
167-
ECPoint G = domainParams.getCurve().decodePoint(encoded);
210+
/*
211+
* RFC 9180 7.1.1. For P-256, P-384, and P-521 [..]. DeserializePublicKey() performs the
212+
* uncompressed Octet-String-to-Elliptic-Curve-Point conversion.
213+
*/
214+
if (pkEncoded[0] != 0x04) // "0x04" is the marker for an uncompressed encoding
215+
{
216+
throw new IllegalArgumentException("'pkEncoded' has invalid format");
217+
}
218+
219+
ECPoint G = domainParams.getCurve().decodePoint(pkEncoded);
168220
return new ECPublicKeyParameters(G, domainParams);
169221
case HPKE.kem_X448_SHA512:
170-
return new X448PublicKeyParameters(encoded);
222+
return new X448PublicKeyParameters(pkEncoded);
171223
case HPKE.kem_X25519_SHA256:
172-
return new X25519PublicKeyParameters(encoded);
224+
return new X25519PublicKeyParameters(pkEncoded);
173225
default:
174226
throw new IllegalStateException("invalid kem id");
175227
}
@@ -198,6 +250,10 @@ public AsymmetricCipherKeyPair DeserializePrivateKey(byte[] skEncoded, byte[] pk
198250
case HPKE.kem_P256_SHA256:
199251
case HPKE.kem_P384_SHA348:
200252
case HPKE.kem_P521_SHA512:
253+
/*
254+
* RFC 9180 7.1.2. For P-256, P-384, and P-521 [..]. DeserializePrivateKey() performs the Octet-
255+
* String-to-Field-Element conversion according to [SECG].
256+
*/
201257
BigInteger d = new BigInteger(1, skEncoded);
202258
ECPrivateKeyParameters ec = new ECPrivateKeyParameters(d, domainParams);
203259

@@ -317,7 +373,7 @@ protected byte[][] Encap(AsymmetricKeyParameter pkR, AsymmetricCipherKeyPair kpE
317373
byte[][] output = new byte[2][];
318374

319375
// DH
320-
byte[] secret = calculateAgreement(agreement, kpE.getPrivate(), pkR);
376+
byte[] secret = calculateRawAgreement(rawAgreement, kpE.getPrivate(), pkR);
321377

322378
byte[] enc = SerializePublicKey(kpE.getPublic());
323379
byte[] pkRm = SerializePublicKey(pkR);
@@ -335,7 +391,7 @@ protected byte[] Decap(byte[] enc, AsymmetricCipherKeyPair kpR)
335391
AsymmetricKeyParameter pkE = DeserializePublicKey(enc);
336392

337393
// DH
338-
byte[] secret = calculateAgreement(agreement, kpR.getPrivate(), pkE);
394+
byte[] secret = calculateRawAgreement(rawAgreement, kpR.getPrivate(), pkE);
339395

340396
byte[] pkRm = SerializePublicKey(kpR.getPublic());
341397
byte[] KEMContext = Arrays.concatenate(enc, pkRm);
@@ -350,12 +406,22 @@ protected byte[][] AuthEncap(AsymmetricKeyParameter pkR, AsymmetricCipherKeyPair
350406
AsymmetricCipherKeyPair kpE = kpGen.generateKeyPair(); // todo: can be replaced with deriveKeyPair(random)
351407

352408
// DH(skE, pkR)
353-
byte[] secret1 = calculateAgreement(agreement, kpE.getPrivate(), pkR);
409+
rawAgreement.init(kpE.getPrivate());
410+
int agreementSize = rawAgreement.getAgreementSize();
411+
412+
byte[] secret = new byte[agreementSize * 2];
413+
414+
rawAgreement.calculateAgreement(pkR, secret, 0);
354415

355416
// DH(skS, pkR)
356-
byte[] secret2 = calculateAgreement(agreement, kpS.getPrivate(), pkR);
417+
rawAgreement.init(kpS.getPrivate());
418+
if (agreementSize != rawAgreement.getAgreementSize())
419+
{
420+
throw new IllegalStateException();
421+
}
422+
423+
rawAgreement.calculateAgreement(pkR, secret, agreementSize);
357424

358-
byte[] secret = Arrays.concatenate(secret1, secret2);
359425
byte[] enc = SerializePublicKey(kpE.getPublic());
360426

361427
byte[] pkRm = SerializePublicKey(pkR);
@@ -373,13 +439,16 @@ protected byte[] AuthDecap(byte[] enc, AsymmetricCipherKeyPair kpR, AsymmetricKe
373439
{
374440
AsymmetricKeyParameter pkE = DeserializePublicKey(enc);
375441

442+
rawAgreement.init(kpR.getPrivate());
443+
444+
int agreementSize = rawAgreement.getAgreementSize();
445+
byte[] secret = new byte[agreementSize * 2];
446+
376447
// DH(skR, pkE)
377-
byte[] secret1 = calculateAgreement(agreement, kpR.getPrivate(), pkE);
448+
rawAgreement.calculateAgreement(pkE, secret, 0);
378449

379450
// DH(skR, pkS)
380-
byte[] secret2 = calculateAgreement(agreement, kpR.getPrivate(), pkS);
381-
382-
byte[] secret = Arrays.concatenate(secret1, secret2);
451+
rawAgreement.calculateAgreement(pkS, secret, agreementSize);
383452

384453
byte[] pkRm = SerializePublicKey(kpR.getPublic());
385454
byte[] pkSm = SerializePublicKey(pkS);
@@ -397,12 +466,13 @@ private byte[] ExtractAndExpand(byte[] dh, byte[] kemContext)
397466
return hkdf.LabeledExpand(eae_prk, suiteID, "shared_secret", kemContext, Nsecret);
398467
}
399468

400-
private static byte[] calculateAgreement(BasicAgreement agreement, AsymmetricKeyParameter privateKey,
469+
private static byte[] calculateRawAgreement(RawAgreement rawAgreement, AsymmetricKeyParameter privateKey,
401470
AsymmetricKeyParameter publicKey)
402471
{
403-
agreement.init(privateKey);
404-
BigInteger z = agreement.calculateAgreement(publicKey);
405-
return BigIntegers.asUnsignedByteArray(agreement.getFieldSize(), z);
472+
rawAgreement.init(privateKey);
473+
byte[] z = new byte[rawAgreement.getAgreementSize()];
474+
rawAgreement.calculateAgreement(publicKey, z, 0);
475+
return z;
406476
}
407477

408478
private static ECDomainParameters getDomainParameters(String curveName)

0 commit comments

Comments
 (0)