1
votes

We have an issue when upgrading bcprov-jdk15on-160.jar and bctls-jdk15on-160.jar to bcprov-jdk15on-161.jar and bctls-jdk15on-161.jar or higher versions

java.lang.InternalError: unable to open random source at org.bouncycastle.jcajce.provider.drbg.DRBG$URLSeededSecureRandom$1.run(DRBG.java:294) at org.bouncycastle.jcajce.provider.drbg.DRBG$URLSeededSecureRandom$1.run(DRBG.java:285) at java.security.AccessController.doPrivileged(Native Method) at org.bouncycastle.jcajce.provider.drbg.DRBG$URLSeededSecureRandom.(DRBG.java:284) at org.bouncycastle.jcajce.provider.drbg.DRBG.createCoreSecureRandom(DRBG.java:131) at org.bouncycastle.jcajce.provider.drbg.DRBG.createInitialEntropySource(DRBG.java:115) at org.bouncycastle.jcajce.provider.drbg.DRBG.access$400(DRBG.java:29) at org.bouncycastle.jcajce.provider.drbg.DRBG$HybridSecureRandom.(DRBG.java:357) at org.bouncycastle.jcajce.provider.drbg.DRBG.createBaseRandom(DRBG.java:179) at org.bouncycastle.jcajce.provider.drbg.DRBG.access$100(DRBG.java:29) at org.bouncycastle.jcajce.provider.drbg.DRBG$Default.(DRBG.java:193) at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27) at java.lang.reflect.Constructor.newInstance(Constructor.java:513) at java.lang.Class.newInstance0(Class.java:357) at java.lang.Class.newInstance(Class.java:310) at java.security.Provider$Service.newInstance(Provider.java:1221) at sun.security.jca.GetInstance.getInstance(GetInstance.java:220) at sun.security.jca.GetInstance.getInstance(GetInstance.java:147) at java.security.SecureRandom.getInstance(SecureRandom.java:254) at java.security.SecureRandom.getDefaultPRNG(SecureRandom.java:176) at java.security.SecureRandom.(SecureRandom.java:133)

when enabled debug log. It is an error about \dev\urandom

java.io.FileNotFoundException: \dev\urandom (The system cannot find the path specified) at java.io.FileInputStream.open(Native Method) at java.io.FileInputStream.(FileInputStream.java:120) at java.io.FileInputStream.(FileInputStream.java:79) at sun.net.www.protocol.file.FileURLConnection.connect(FileURLConnection.java:70) at sun.net.www.protocol.file.FileURLConnection.getInputStream(FileURLConnection.java:161) at java.net.URL.openStream(URL.java:1010) at org.bouncycastle.jcajce.provider.drbg.DRBG$URLSeededSecureRandom$1.run(DRBG.java:290) at org.bouncycastle.jcajce.provider.drbg.DRBG$URLSeededSecureRandom$1.run(DRBG.java:1) at java.security.AccessController.doPrivileged(Native Method) at org.bouncycastle.jcajce.provider.drbg.DRBG$URLSeededSecureRandom.(DRBG.java:284) at org.bouncycastle.jcajce.provider.drbg.DRBG.createCoreSecureRandom(DRBG.java:131) at org.bouncycastle.jcajce.provider.drbg.DRBG.createInitialEntropySource(DRBG.java:115) at org.bouncycastle.jcajce.provider.drbg.DRBG.access$2(DRBG.java:77) at org.bouncycastle.jcajce.provider.drbg.DRBG$HybridSecureRandom.(DRBG.java:358) at org.bouncycastle.jcajce.provider.drbg.DRBG.createBaseRandom(DRBG.java:179) at org.bouncycastle.jcajce.provider.drbg.DRBG.access$0(DRBG.java:162) at org.bouncycastle.jcajce.provider.drbg.DRBG$Default.(DRBG.java:193)

There is no issue when using the 160 version.

I am using Java 6 32 bit on Windows 10 64 bit.

Could someone help me with this?

Thanks.

public class BCUpgradeTest {

    public static void main(String[] args) {
        try {
            Security.insertProviderAt(new BouncyCastleJsseProvider(), 1);
            Security.insertProviderAt(new BouncyCastleProvider(), 1);
            KeyAgreement ka = KeyAgreement.getInstance("ECDH");
            System.out.println(ka.getProvider().getName());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}
2

2 Answers

2
votes

Try adding this code to your program's startup:

import java.lang.reflect.Field;
import java.security.Security;
import java.util.Properties;

try {
    Field propsField = Security.class.getDeclaredField("props");
    propsField.setAccessible(true);
    Properties props = (Properties) propsField.get(null);
    props.remove("securerandom.source");
} catch(Exception e) {
    System.err.println("Unable to modify java.lang.Security properties!");
    System.err.println("BouncyCastle DRBG may fail.");
}

Which should at least give you a different error message. Note that I haven't actually tested this; it's based on the following code analysis.

The FileNotFoundException you posted is thrown from an URLSeededSecureRandom instance constructed with an URL of file:/dev/random. Of course, since you're on Windows, /dev/random does not exist and url.openStream() fails. (The resulting FileNotFoundException is caught and rethrown as an InternalError, of all things; why BouncyCastle uses an Error class designed to "indicate some unexpected internal error has occurred in the Java Virtual Machine", I have no idea.)

But the file:/dev/random part actually isn't hardcoded. It comes from DRBG.createCoreSecureRandom():

private static SecureRandom createCoreSecureRandom()
{
    if (Security.getProperty("securerandom.source") == null)
    {
        return new CoreSecureRandom(findSource());
    }
    else
    {
        try
        {
            String source = Security.getProperty("securerandom.source");

            return new URLSeededSecureRandom(new URL(source));
        }
        catch (Exception e)
        {
            return new SecureRandom();  // we're desperate, it's worth a try.
        }
    }
}

Essentially it calls Security.getProperty("securerandom.source"), and if it's not null, it uses the property to construct a URLSeededSecureRandom. For some reason, on your system securerandom.source must be something like file:/dev/random even though it's a Windows JVM, so BouncyCastle tries to make a CSPRNG out of that.

You need to set securerandom.source to null so that DRBG.createCoreSecureRandom() takes the other code path. Unfortunately, you can't simply use Security.setProperty("securerandom.source", null) because Security's property list is a Properties instance backed by a ConcurrentHashMap which doesn't allow null values. And Security doesn't give you access to the underlying Properties instance so that you can call remove() on it. So you must use the reflection hackery posted at the top.

0
votes

Thanks MultiplyByZer0 your code resolved the issue about

java.lang.InternalError: unable to open random source

Still having another issue with bcprov-jdk15on-162.jar and bctls-jdk15on-162.jar

The error trace:

java.lang.SecurityException: JCE cannot authenticate the provider BC at javax.crypto.SunJCE_b.a(DashoA13*..) at javax.crypto.KeyAgreement.getInstance(DashoA13*..) at bc.test.BCUpgradeTest.main(BCUpgradeTest.java:46) Caused by: java.util.jar.JarException: Cannot parse file:/D:/Eclipse/workspace/BCTestProject/libs/bcprov-jdk15on-162.jar at javax.crypto.SunJCE_c.a(DashoA13*..) at javax.crypto.SunJCE_b.b(DashoA13*..) at javax.crypto.SunJCE_b.a(DashoA13*..)

the updated test program

import java.lang.reflect.Field;
import java.security.Provider;
import java.security.Security;
import java.util.Properties;

import javax.crypto.KeyAgreement;

import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jsse.provider.BouncyCastleJsseProvider;

public class BCUpgradeTest {

    public static void main(String[] args) {
        try {
            Field propsField = Security.class.getDeclaredField("props");
            propsField.setAccessible(true);
            Properties props = (Properties) propsField.get(null);
            props.remove("securerandom.source");
        } catch (Exception e) {
            System.err.println("Unable to modify java.lang.Security properties!");
            System.err.println("BouncyCastle DRBG may fail.");
        }

        try {
            BouncyCastleJsseProvider jsseProvider = new BouncyCastleJsseProvider();
            int jssePos = Security.insertProviderAt(jsseProvider, 1);
            BouncyCastleProvider castleProvider = new BouncyCastleProvider();
            int bcPos = Security.insertProviderAt(castleProvider, 1);

            System.out.println("jssePos = " + jssePos);
            System.out.println("bcPos = " + bcPos);

            System.out.println(castleProvider.getVersion());
            System.out.println(BCUpgradeTest.class.getClassLoader().getResource("org/bouncycastle/LICENSE.class"));

            Provider[] providers = Security.getProviders();
            for (int i = 0; i < providers.length; i++) {
                System.out.println("name : " + providers[i].getName() + "; version = " + providers[i].getVersion());
            }

            KeyAgreement ka = KeyAgreement.getInstance("ECDH", castleProvider);
            System.out.println(ka.getProvider().getName());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Below is the output from Console

jssePos = 1
bcPos = 1
1.62
jar:file:/D:/Eclipse/workspace/BCTestProject/libs/bcprov-jdk15on-162.jar!/org/bouncycastle/LICENSE.class
name : BC; version = 1.62
name : BCJSSE; version = 1.0009
name : SUN; version = 1.6
name : SunRsaSign; version = 1.5
name : SunJSSE; version = 1.6
name : SunJCE; version = 1.6
name : SunJGSS; version = 1.0
name : SunSASL; version = 1.5
name : XMLDSig; version = 1.0
name : SunPCSC; version = 1.6
name : SunMSCAPI; version = 1.6

Note that I use the official jar files without any modification.