In windows Java SecureRandom.generateSeed failed:

2019-06-20 05:26发布

问题:

In production environment(Windows 2008 R2, AMD 64, 8 GB RAM), the application sometimes throws the following exception - restart the application solves the problem.

Caused by: java.lang.InternalError: Unexpected CryptoAPI failure generating seed
at sun.security.provider.NativeSeedGenerator.getSeedBytes(NativeSeedGenerator.java:43)
at sun.security.provider.SeedGenerator.generateSeed(SeedGenerator.java:117)
at sun.security.provider.SecureRandom.engineGenerateSeed(SecureRandom.java:114)
at java.security.SecureRandom.generateSeed(SecureRandom.java:475)

The code should have no problem :

    public void generateToken ()
    {
        SecureRandom secureRandom = new SecureRandom();
        int seedByteCount = 20;
        byte[] seed = secureRandom.generateSeed(seedByteCount);
        secureRandom.setSeed(seed);
        String random = String.valueOf(secureRandom.nextLong());
        setToken(random);
    }

Took a look at JDK code, find out that the error is because Java_sun_security_provider_NativeSeedGenerator_nativeGenerateSeed returns false :

openjdk-7u2-fcs-src-b13-17_nov_2011\jdk\src\windows\native\sun\security\provider\WinCAPISeedGenerator.c :

    JNIEXPORT jboolean JNICALL Java_sun_security_provider_NativeSeedGenerator_nativeGenerateSeed(JNIEnv *env, jclass clazz, jbyteArray randArray)
    {
        HCRYPTPROV hCryptProv;
        jboolean result = JNI_FALSE;
        jsize numBytes;
        jbyte* randBytes;

        if (CryptAcquireContextA(&hCryptProv, "J2SE", NULL, PROV_RSA_FULL, 0) == FALSE) {
            /* If CSP context hasn't been created, create one. */
            if (CryptAcquireContextA(&hCryptProv, "J2SE", NULL, PROV_RSA_FULL,
                    CRYPT_NEWKEYSET) == FALSE) {
                return result;
            }
        }

        numBytes = (*env)->GetArrayLength(env, randArray);
        randBytes = (*env)->GetByteArrayElements(env, randArray, NULL);
        if (CryptGenRandom(hCryptProv, numBytes, randBytes)) {
            result = JNI_TRUE;
        }
        (*env)->ReleaseByteArrayElements(env, randArray, randBytes, 0);

        CryptReleaseContext(hCryptProv, 0);

        return result;
    }

CryptGenRandom or CryptAcquireContextA returns false, but I don't know why it fails, and how to work around it.

Anyone knows why this happens, the work around or how to continue to investigate this problem?

Thanks for any advice or reply. Thanks...

Btw - I found the following resources - but not quite useful to this problem.

  • https://forums.oracle.com/forums/thread.jspa?threadID=2231037

  • http://bugs.sun.com/view_bug.do?bug_id=6202721

  • Proper use of Java’s SecureRandom

  • Secure Random Number Generation in JAVA

回答1:

While your problem smells like a concurrent access problem, I have a workaround for you: Use bouncycastle as a JCE provider and see if that fixes your problem. Put the jar into your classpath, then at some point run this code: Security.addProvider(new BouncyCastleProvider());