Issue-973 (part1) - Removing direct dependency on BouncyCastle library and using JCE.

- This is first change towards removing direct dependency on BouncyCastle.
- Removed the imports org.bouncycastle.crypto.prng.RandomGenerator and
  org.bouncycastle.crypto.prng.VMPCRandomGenerator from the file
  BouncyCastleRandom.java, eliminating the direct dependency on BouncyCastle.
  Now using JCE with a provider, allowing SecureRandom to utilize the BC provider.
- Added a new class, BouncyCastleFipsRandom, similar to BouncyCastleRandom.java,
  which leverages the BCFIPS provider to create SecureRandom instances.
- Upgraded gradle plugin, groovy and Mockito versions to ensure compatibility with Java 21.
  from org.spockframework:spock-core:2.3-groovy-3.0 to org.spockframework:spock-core:2.4-M5-groovy-4.0
  from org.mockito:mockito-core:4.11.0 to org.mockito:mockito-core:5.15.2
  from gradle-8.2-bin.zip to gradle-8.11-bin.zip
 Testing: I have run gradle clean build with java 11 and Java 21 and works.
Test Gradle Test Executor 2; Executed: 470/469/0
✓ Test Gradle Test Run :test; Executed: 470/469/0
This commit is contained in:
Uttam Gupta
2025-01-13 14:08:04 -08:00
committed by Uttam Gupta
parent 31ed35407c
commit bfa82b4e44
5 changed files with 110 additions and 18 deletions

View File

@@ -86,8 +86,8 @@ testing {
useJUnitJupiter() useJUnitJupiter()
dependencies { dependencies {
implementation "org.slf4j:slf4j-api:2.0.13" implementation "org.slf4j:slf4j-api:2.0.13"
implementation 'org.spockframework:spock-core:2.3-groovy-3.0' implementation "org.spockframework:spock-core:2.4-M5-groovy-4.0"
implementation "org.mockito:mockito-core:4.11.0" implementation "org.mockito:mockito-core:5.15.2"
implementation "org.assertj:assertj-core:3.24.2" implementation "org.assertj:assertj-core:3.24.2"
implementation "ru.vyarus:spock-junit5:1.2.0" implementation "ru.vyarus:spock-junit5:1.2.0"
implementation "org.apache.sshd:sshd-core:$sshdVersion" implementation "org.apache.sshd:sshd-core:$sshdVersion"

View File

@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-8.11-bin.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists

View File

@@ -59,7 +59,8 @@ import java.util.Properties;
* net.schmizz.sshj.transport.mac.HMACMD596}</li> * net.schmizz.sshj.transport.mac.HMACMD596}</li>
* <li>{@link net.schmizz.sshj.ConfigImpl#setCompressionFactories Compression}: {@link net.schmizz.sshj.transport.compression.NoneCompression}</li> * <li>{@link net.schmizz.sshj.ConfigImpl#setCompressionFactories Compression}: {@link net.schmizz.sshj.transport.compression.NoneCompression}</li>
* <li>{@link net.schmizz.sshj.ConfigImpl#setKeyAlgorithms KeyAlgorithm}: {@link net.schmizz.sshj.signature.SignatureRSA}, {@link net.schmizz.sshj.signature.SignatureDSA}</li> * <li>{@link net.schmizz.sshj.ConfigImpl#setKeyAlgorithms KeyAlgorithm}: {@link net.schmizz.sshj.signature.SignatureRSA}, {@link net.schmizz.sshj.signature.SignatureDSA}</li>
* <li>{@link net.schmizz.sshj.ConfigImpl#setRandomFactory PRNG}: {@link net.schmizz.sshj.transport.random.BouncyCastleRandom}* or {@link net.schmizz.sshj.transport.random.JCERandom}</li> * <li>{@link net.schmizz.sshj.ConfigImpl#setRandomFactory BC}: {@link net.schmizz.sshj.transport.random.BouncyCastleRandom}* or {@link net.schmizz.sshj.transport.random.JCERandom}</li>
* <li>{@link net.schmizz.sshj.ConfigImpl#setRandomFactory BCFIPS}: {@link net.schmizz.sshj.transport.random.BouncyCastleFipsRandom}* or {@link net.schmizz.sshj.transport.random.JCERandom}</li>
* <li>{@link net.schmizz.sshj.ConfigImpl#setFileKeyProviderFactories Key file support}: {@link net.schmizz.sshj.userauth.keyprovider.PKCS8KeyFile}*, {@link * <li>{@link net.schmizz.sshj.ConfigImpl#setFileKeyProviderFactories Key file support}: {@link net.schmizz.sshj.userauth.keyprovider.PKCS8KeyFile}*, {@link
* net.schmizz.sshj.userauth.keyprovider.OpenSSHKeyFile}*</li> * net.schmizz.sshj.userauth.keyprovider.OpenSSHKeyFile}*</li>
* <li>{@link net.schmizz.sshj.ConfigImpl#setVersion Client version}: {@code "NET_3_0"}</li> * <li>{@link net.schmizz.sshj.ConfigImpl#setVersion Client version}: {@code "NET_3_0"}</li>

View File

@@ -0,0 +1,78 @@
/*
* Copyright (C)2009 - SSHJ Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.schmizz.sshj.transport.random;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;
/**
* BouncyCastle <code>Random</code>. This pseudo random number generator uses BouncyCastle fips.
* The JRE random will be used when creating a new generator to add some random data to the seed.
*/
public class BouncyCastleFipsRandom
implements Random {
private static final Logger logger = LoggerFactory.getLogger(BouncyCastleFipsRandom.class);
/** Named factory for the BouncyCastle <code>Random</code> */
public static class Factory
implements net.schmizz.sshj.common.Factory<Random> {
@Override
public Random create() {
return new BouncyCastleFipsRandom();
}
}
private byte[] tmp = new byte[16];
private final SecureRandom random;
public BouncyCastleFipsRandom() {
logger.info("Generating random seed from SecureRandom of BCFIPS.");
long t = System.currentTimeMillis();
try {
// Use SecureRandom with the BCFIPS provider
random = SecureRandom.getInstance("DEFAULT", "BCFIPS");
} catch (NoSuchProviderException e) {
throw new RuntimeException("BCFIPS provider is not available", e);
} catch (Exception e) {
throw new RuntimeException("Failed to initialize SecureRandom with BCFIPS provider", e);
}
logger.debug("Creating random seed took {} ms", System.currentTimeMillis() - t);
}
@Override
public synchronized void fill(byte[] bytes, int start, int len) {
if (start == 0 && len == bytes.length) {
random.nextBytes(bytes);
} else {
synchronized (this) {
if (len > tmp.length) tmp = new byte[len];
random.nextBytes(tmp);
System.arraycopy(tmp, 0, bytes, start, len);
}
}
}
@Override
public void fill(byte[] bytes) {
random.nextBytes(bytes);
}
}

View File

@@ -15,15 +15,14 @@
*/ */
package net.schmizz.sshj.transport.random; package net.schmizz.sshj.transport.random;
import org.bouncycastle.crypto.prng.RandomGenerator;
import org.bouncycastle.crypto.prng.VMPCRandomGenerator;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.security.NoSuchProviderException;
import java.security.SecureRandom; import java.security.SecureRandom;
/** /**
* BouncyCastle <code>Random</code>. This pseudo random number generator uses the a very fast PRNG from BouncyCastle. * BouncyCastle <code>Random</code>. This pseudo random number generator uses BouncyCastle non fips.
* The JRE random will be used when creating a new generator to add some random data to the seed. * The JRE random will be used when creating a new generator to add some random data to the seed.
*/ */
public class BouncyCastleRandom public class BouncyCastleRandom
@@ -41,20 +40,34 @@ public class BouncyCastleRandom
} }
} }
private byte[] tmp = new byte[16];
private final RandomGenerator random = new VMPCRandomGenerator(); private final SecureRandom random;
public BouncyCastleRandom() { public BouncyCastleRandom() {
logger.info("Generating random seed from SecureRandom."); logger.info("Generating random seed from SecureRandom of BC.");
long t = System.currentTimeMillis(); long t = System.currentTimeMillis();
byte[] seed = new SecureRandom().generateSeed(8); try {
// Use SecureRandom with the BC provider
random = SecureRandom.getInstance("DEFAULT", "BC");
} catch (NoSuchProviderException e) {
throw new RuntimeException("BC provider is not in the classpath", e);
} catch (Exception e) {
throw new RuntimeException("Failed to initialize SecureRandom with BC provider", e);
}
logger.debug("Creating random seed took {} ms", System.currentTimeMillis() - t); logger.debug("Creating random seed took {} ms", System.currentTimeMillis() - t);
random.addSeedMaterial(seed);
} }
@Override @Override
public void fill(byte[] bytes, int start, int len) { public synchronized void fill(byte[] bytes, int start, int len) {
random.nextBytes(bytes, start, len); if (start == 0 && len == bytes.length) {
random.nextBytes(bytes);
} else {
synchronized (this) {
if (len > tmp.length) tmp = new byte[len];
random.nextBytes(tmp);
System.arraycopy(tmp, 0, bytes, start, len);
}
}
} }
@Override @Override