Skip to content

Commit 1c274da

Browse files
author
gefeili
committed
Merge remote-tracking branch 'origin/rfc-6508-sakke' into rfc-6508-sakke
# Conflicts: # core/src/main/java/org/bouncycastle/crypto/generators/ECCSIKeyPairGenerator.java # core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMSGenerator.java # core/src/main/java/org/bouncycastle/crypto/params/ECCSIKeyGenerationParameters.java # core/src/main/java/org/bouncycastle/crypto/signers/ECCSISigner.java
2 parents 4bfc1d7 + cd39549 commit 1c274da

File tree

108 files changed

+1599
-2576
lines changed

Some content is hidden

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

108 files changed

+1599
-2576
lines changed

HOWTO.md

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
# Bouncy Castle Java API How To
2+
## Using Bouncy Castle with GraalVM Native Image
3+
### Problem: Provider Not Registered at Build Time with `UnsupportedFeatureError` Exception
4+
#### Error message
5+
```text
6+
Trying to verify a provider that was not registered at build time: BC version...
7+
```
8+
#### Cause:
9+
Bouncy Castle security provider isn't properly registered during GraalVM native image build process.
10+
11+
### Solution 1: Static Initializer Approach (No GraalVM SDK)
12+
#### Step 1. Create Initializer Class
13+
```java
14+
package com.yourpackage.crypto; // ← Replace with your actual package
15+
16+
import org.bouncycastle.jce.provider.BouncyCastleProvider;
17+
import java.security.Security;
18+
19+
public class BCInitializer {
20+
static {
21+
// Force provider registration during image build
22+
Security.addProvider(new BouncyCastleProvider());
23+
}
24+
}
25+
```
26+
27+
#### Step 2. And then in the native-image build configuration
28+
For Maven (`pom.xml`)
29+
```xml
30+
<plugin>
31+
<groupId>org.graalvm.buildtools</groupId>
32+
<artifactId>native-maven-plugin</artifactId>
33+
<version>0.9.28</version>
34+
<configuration>
35+
<buildArgs>
36+
<!-- Initialize Bouncy Castle and our initializer -->
37+
<arg>--initialize-at-build-time=org.bouncycastle,com.yourpackage.crypto.BCInitializer</arg>
38+
<!-- Required for SecureRandom components -->
39+
<arg>--initialize-at-run-time=org.bouncycastle.jcajce.provider.drbg.DRBG$Default,org.bouncycastle.jcajce.provider.drbg.DRBG$NonceAndIV</arg>
40+
</buildArgs>
41+
</configuration>
42+
</plugin>
43+
```
44+
45+
For Gradle (`build.gradle`),
46+
```gradle
47+
buildArgs.add('--initialize-at-build-time=com.yourpackage.crypto.BCInitializer')
48+
buildArgs.add("--initialize-at-run-time=org.bouncycastle.jcajce.provider.drbg.DRBG\$Default,org.bouncycastle.jcajce.provider.drbg.DRBG\$NonceAndIV")
49+
```
50+
# Key Configuration
51+
52+
| Argument | Purpose |
53+
| ------------------------------- |-----------------------------------------------------------------|
54+
| `--initialize-at-build-time` | Forces inclusion of BC classes and triggers static initializer. |
55+
| `--initialize-at-run-time` | Solves stateful SecureRandom initialization issues. |
56+
|`--enable-all-security-services` | (optional) Enables JCE security infrastructure |
57+
58+
59+
### Solution 2: GraalVM Feature Approach (With SDK)
60+
61+
#### Step 1: Create a Native Image Feature
62+
```java
63+
package com.yourpackage.crypto; // ← Replace with your actual package
64+
65+
import org.bouncycastle.jce.provider.BouncyCastleProvider;
66+
import org.graalvm.nativeimage.hosted.Feature;
67+
68+
import java.security.Security;
69+
70+
/**
71+
* A GraalVM Feature that registers the Bouncy Castle provider.
72+
* This is required so that native image builds verify and include the provider.
73+
*/
74+
public class BouncyCastleFeature implements Feature {
75+
76+
@Override
77+
public void afterRegistration(AfterRegistrationAccess access) {
78+
// Register the Bouncy Castle provider
79+
Security.addProvider(new BouncyCastleProvider());
80+
}
81+
}
82+
```
83+
84+
#### Step 2: Configure Dependencies and Build
85+
##### 2.1 add dependency
86+
```xml
87+
<dependency>
88+
<groupId>org.graalvm.sdk</groupId>
89+
<artifactId>graal-sdk</artifactId>
90+
<version>21.0.0</version> <!-- Match your GraalVM version -->
91+
<scope>provided</scope>
92+
</dependency>
93+
```
94+
##### 2.2 add plugin
95+
```xml
96+
<plugin>
97+
<groupId>org.graalvm.buildtools</groupId>
98+
<artifactId>native-maven-plugin</artifactId>
99+
<version>0.9.28</version>
100+
<configuration>
101+
<buildArgs>
102+
<arg>--features=com.yourpackage.crypto.BouncyCastleFeature</arg> <!-- replace with correct package path -->
103+
<arg>--initialize-at-build-time=org.bouncycastle</arg>
104+
<arg>--initialize-at-run-time=org.bouncycastle.jcajce.provider.drbg.DRBG$Default,org.bouncycastle.jcajce.provider.drbg.DRBG$NonceAndIV</arg>
105+
</buildArgs>
106+
</configuration>
107+
</plugin>
108+
```
109+
Key Configuration Explanations:
110+
`--features=...`
111+
- Registers custom feature class that adds BouncyCastle provider at build time
112+
- Required for JCE security provider verification
113+
114+
### Troubleshooting
115+
#### Common Issues
116+
##### Classpath Conflicts:
117+
118+
```text
119+
Error: Class-path entry contains class from image builder
120+
```
121+
Fix: Add `-H:+AllowDeprecatedBuilderClassesOnImageClasspath` (temporary) or ensure graal-sdk has provided scope
122+
123+
##### Missing Algorithms:
124+
Example of the error message:
125+
```text
126+
No such algorithm: AES/CBC/PKCS5Padding
127+
```
128+
129+
Fix: Verify `--initialize-at-build-time` includes `org.bouncycastle`

ant/jdk14.xml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -196,8 +196,6 @@
196196
<exclude name="**/TlsClientRawKeysTest.java"/>
197197
</fileset>
198198

199-
<fileset dir="tls/src/test/resources" includes="**/*.*"/>
200-
201199
<fileset dir="core/src/test/" includes="**/*.properties"/>
202200
<fileset dir="prov/src/main/resources" includes="**/*.properties"/>
203201
<fileset dir="pkix/src/test/resources" includes="**/*.*"/>

ant/jdk15+.xml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@
4343
<fileset dir="tls/src/main/java" includes="**/*.java" />
4444
<fileset dir="tls/src/main/javadoc" includes="**/*.html" />
4545
<fileset dir="tls/src/test/java" includes="**/*.java" />
46-
<fileset dir="tls/src/test/resources" includes="**/*.*" />
4746

4847
<fileset dir="pkix/src/main/java" includes="**/*.java" />
4948
<fileset dir="pkix/src/main/javadoc" includes="**/*.html" />

ant/jdk18+.xml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@
4343
<fileset dir="tls/src/main/jdk1.5" includes="**/*.java" />
4444
<fileset dir="tls/src/main/javadoc" includes="**/*.html" />
4545
<fileset dir="tls/src/test/java" includes="**/*.java" />
46-
<fileset dir="tls/src/test/resources" includes="**/*.*" />
4746

4847
<fileset dir="pkix/src/main/java" includes="**/*.java" />
4948
<fileset dir="pkix/src/main/javadoc" includes="**/*.html" />

ci/check_java.sh

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,12 @@ export JAVA_HOME=`openjdk_21`
1515
export PATH=$JAVA_HOME/bin:$PATH
1616

1717
# Checkstyle
18-
./gradlew check -x test;
18+
./gradlew clean build check -x test;
1919

2020

2121
# OSGI scanner only, no testing
22-
./gradlew clean build -x test
2322
./osgi_scan.sh
2423

24+
25+
# module tester
26+
./run_mtt.sh

core/src/main/j2me/org/bouncycastle/math/ec/ECCurve.java

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -593,9 +593,14 @@ protected AbstractFp(BigInteger q)
593593
super(FiniteFields.getPrimeField(q));
594594
}
595595

596+
public BigInteger getQ()
597+
{
598+
return getField().getCharacteristic();
599+
}
600+
596601
public boolean isValidFieldElement(BigInteger x)
597602
{
598-
return x != null && x.signum() >= 0 && x.compareTo(this.getField().getCharacteristic()) < 0;
603+
return x != null && x.signum() >= 0 && x.compareTo(this.getQ()) < 0;
599604
}
600605

601606
public ECFieldElement randomFieldElement(SecureRandom r)
@@ -604,7 +609,7 @@ public ECFieldElement randomFieldElement(SecureRandom r)
604609
* NOTE: BigInteger comparisons in the rejection sampling are not constant-time, so we
605610
* use the product of two independent elements to mitigate side-channels.
606611
*/
607-
BigInteger p = this.getField().getCharacteristic();
612+
BigInteger p = this.getQ();
608613
ECFieldElement fe1 = this.fromBigInteger(implRandomFieldElement(r, p));
609614
ECFieldElement fe2 = this.fromBigInteger(implRandomFieldElement(r, p));
610615
return fe1.multiply(fe2);
@@ -616,7 +621,7 @@ public ECFieldElement randomFieldElementMult(SecureRandom r)
616621
* NOTE: BigInteger comparisons in the rejection sampling are not constant-time, so we
617622
* use the product of two independent elements to mitigate side-channels.
618623
*/
619-
BigInteger p = this.getField().getCharacteristic();
624+
BigInteger p = this.getQ();
620625
ECFieldElement fe1 = this.fromBigInteger(implRandomFieldElementMult(r, p));
621626
ECFieldElement fe2 = this.fromBigInteger(implRandomFieldElementMult(r, p));
622627
return fe1.multiply(fe2);
@@ -699,12 +704,11 @@ public Fp(BigInteger q, BigInteger a, BigInteger b, BigInteger order, BigInteger
699704

700705
if (isInternal)
701706
{
702-
this.q = q;
703707
knownQs.add(q);
704708
}
705709
else if (knownQs.contains(q) || validatedQs.contains(q))
706710
{
707-
this.q = q;
711+
// No need to validate
708712
}
709713
else
710714
{
@@ -724,10 +728,9 @@ else if (knownQs.contains(q) || validatedQs.contains(q))
724728
}
725729

726730
validatedQs.add(q);
727-
728-
this.q = q;
729731
}
730732

733+
this.q = q;
731734
this.r = ECFieldElement.Fp.calculateResidue(q);
732735
this.infinity = new ECPoint.Fp(this, null, null);
733736

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,11 @@ public interface X509ObjectIdentifiers
9595
*/
9696
static final ASN1ObjectIdentifier id_ecdsa_with_shake256 = pkix_algorithms.branch("33");
9797

98+
/**
99+
* id-alg-noSignature OBJECT IDENTIFIER ::= {id-pkix id-alg(6) 2}
100+
*/
101+
ASN1ObjectIdentifier id_alg_noSignature = pkix_algorithms.branch("2");
102+
98103
/** 1.3.6.1.5.5.7.9 */
99104
static final ASN1ObjectIdentifier id_pda = id_pkix.branch("9");
100105

core/src/main/java/org/bouncycastle/asn1/x9/X9ECParameters.java

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import org.bouncycastle.math.ec.ECAlgorithms;
1313
import org.bouncycastle.math.ec.ECCurve;
1414
import org.bouncycastle.math.ec.ECPoint;
15+
import org.bouncycastle.math.field.FiniteField;
1516
import org.bouncycastle.math.field.PolynomialExtensionField;
1617
import org.bouncycastle.util.Arrays;
1718

@@ -112,14 +113,15 @@ public X9ECParameters(
112113
this.h = h;
113114
this.seed = Arrays.clone(seed);
114115

115-
if (ECAlgorithms.isFpCurve(curve))
116+
FiniteField field = curve.getField();
117+
if (ECAlgorithms.isFpField(field))
116118
{
117-
this.fieldID = new X9FieldID(curve.getField().getCharacteristic());
119+
this.fieldID = new X9FieldID(field.getCharacteristic());
118120
}
119-
else if (ECAlgorithms.isF2mCurve(curve))
121+
else if (ECAlgorithms.isF2mField(field))
120122
{
121-
PolynomialExtensionField field = (PolynomialExtensionField)curve.getField();
122-
int[] exponents = field.getMinimalPolynomial().getExponentsPresent();
123+
PolynomialExtensionField f2mField = (PolynomialExtensionField)field;
124+
int[] exponents = f2mField.getMinimalPolynomial().getExponentsPresent();
123125
if (exponents.length == 3)
124126
{
125127
this.fieldID = new X9FieldID(exponents[2], exponents[1]);

core/src/main/java/org/bouncycastle/crypto/agreement/ecjpake/ECJPAKECurve.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ public BigInteger getH()
159159

160160
public BigInteger getQ()
161161
{
162-
return curve.getField().getCharacteristic();
162+
return curve.getQ();
163163
}
164164

165165
private static BigInteger calculateDeterminant(BigInteger q, BigInteger a, BigInteger b)

core/src/main/java/org/bouncycastle/crypto/digests/ParallelHash.java

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@ public class ParallelHash
3838
* Base constructor.
3939
*
4040
* @param bitLength security strength (bits) of the underlying SHAKE function, 128 or 256.
41-
* @param S the customization string - available for local use.
42-
* @param B the blocksize (in bytes) for hashing.
41+
* @param S the customization string - available for local use.
42+
* @param B the blocksize (in bytes) for hashing.
4343
*/
4444
public ParallelHash(int bitLength, byte[] S, int B)
4545
{
@@ -50,12 +50,18 @@ public ParallelHash(int bitLength, byte[] S, int B, int outputSize)
5050
{
5151
this(bitLength, S, B, outputSize, CryptoServicePurpose.ANY);
5252
}
53+
5354
public ParallelHash(int bitLength, byte[] S, int B, int outputSize, CryptoServicePurpose purpose)
5455
{
56+
if (B <= 0)
57+
{
58+
throw new IllegalArgumentException("block size should be greater than 0");
59+
}
5560
this.cshake = new CSHAKEDigest(bitLength, N_PARALLEL_HASH, S);
5661
this.compressor = new CSHAKEDigest(bitLength, new byte[0], new byte[0]);
5762
this.bitLength = bitLength;
5863
this.B = B;
64+
5965
this.outputLength = (outputSize + 7) / 8;
6066
this.buffer = new byte[B];
6167
this.compressorBuffer = new byte[bitLength * 2 / 8];
@@ -112,7 +118,7 @@ public void update(byte in)
112118
public void update(byte[] in, int inOff, int len)
113119
throws DataLengthException, IllegalStateException
114120
{
115-
len = Math.max(0, len);
121+
len = Math.max(0, len);
116122

117123
//
118124
// fill the current word
@@ -198,7 +204,7 @@ public int doFinal(byte[] out, int outOff, int outLen)
198204
{
199205
wrapUp(outputLength);
200206
}
201-
207+
202208
int rv = cshake.doFinal(out, outOff, outLen);
203209

204210
reset();

0 commit comments

Comments
 (0)