In windows Java SecureRandom.generateSeed failed:

2019-06-20 05:30发布

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.

1条回答
放荡不羁爱自由
2楼-- · 2019-06-20 06:15

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());

查看更多
登录 后发表回答