Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In windows Java SecureRandom.generateSeed failed: Unexpected CryptoAPI failure

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

like image 438
jeffery.yuan Avatar asked Mar 27 '12 07:03

jeffery.yuan


1 Answers

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

like image 117
Jonathan S. Fisher Avatar answered Oct 20 '22 01:10

Jonathan S. Fisher