I am running the following Java program on a Macbook Air with OSX 10.9.4, 1.7GHz i7, 8GB memory. I have Java Cryptography Extension (JCE) installed.
import javax.crypto.Mac; public class Main { public static void main(String[] args) throws Exception { Mac.getInstance("HmacSHA1"); } }
Running this simple program will lead to a runtime of more than 5 seconds!
$ javac -version javac 1.7.0_45 $ javac Main.java $ java -version java version "1.7.0_45" Java(TM) SE Runtime Environment (build 1.7.0_45-b18) Java HotSpot(TM) 64-Bit Server VM (build 24.45-b08, mixed mode) $ time java Main real 0m5.326s user 0m0.390s sys 0m0.033s
I did a bunch of searches, but did not find many workarounds or explanations.
Mac.getInstance () for an HmacSHA1 requiring age to execute
This seems like my problem, but all the sources that I read show that /dev/random and /dev/urandom same on OSX.
How to solve the performance problem using Java SecureRandom?
Again, the discussion of the source of randomness is SecureRandom, but it does not seem to apply to OSX.
Has anyone heard of this issue before? Or do you know how I can debug what happens? It really upsets taking a 5 second penalty for your unit tests when they were instant so far.
Edit: Here is the time inside the program and the list of security providers:
import java.security.Provider; import java.security.Security; import javax.crypto.Mac; public class Main { public static void main(String[] args) throws Exception { for (Provider p: Security.getProviders()) { System.out.println(p.getName() + " " + p.getVersion() + " " + p.getInfo()); } long start = System.currentTimeMillis(); Mac.getInstance("HmacSHA1"); System.out.println(System.currentTimeMillis() - start + "ms"); } } $ java Main SUN 1.7 SUN (DSA key/parameter generation; DSA signing; SHA-1, MD5 digests; SecureRandom; X.509 certificates; JKS keystore; PKIX CertPathValidator; PKIX CertPathBuilder; LDAP, Collection CertStores, JavaPolicy Policy; JavaLoginConfig Configuration) SunRsaSign 1.7 Sun RSA signature provider SunEC 1.7 Sun Elliptic Curve provider (EC, ECDSA, ECDH) SunJSSE 1.7 Sun JSSE provider(PKCS12, SunX509 key/trust factories, SSLv3, TLSv1) SunJCE 1.7 SunJCE Provider (implements RSA, DES, Triple DES, AES, Blowfish, ARCFOUR, RC2, PBE, Diffie-Hellman, HMAC) SunJGSS 1.7 Sun (Kerberos v5, SPNEGO) SunSASL 1.7 Sun SASL provider(implements client mechanisms for: DIGEST-MD5, GSSAPI, EXTERNAL, PLAIN, CRAM-MD5, NTLM; server mechanisms for: DIGEST-MD5, GSSAPI, CRAM-MD5, NTLM) XMLDSig 1.0 XMLDSig (DOM XMLSignatureFactory; DOM KeyInfoFactory) SunPCSC 1.7 Sun PC/SC provider Apple 1.1 Apple Provider 5224ms
Edit 2:
We figured out how to run HPROF in code.
$ java -agentlib:hprof=cpu=times Main $ cat java.hprof.txt ... TRACE 308670: java.net.InetAddress$1.lookupAllHostAddr(InetAddress.java:Unknown line) java.net.InetAddress.getAddressesFromNameService(InetAddress.java:Unknown line) java.net.InetAddress.getLocalHost(InetAddress.java:Unknown line) javax.crypto.JarVerifier.getSystemEntropy(JarVerifier.java:Unknown line) ... CPU TIME (ms) BEGIN (total = 6680) Sat Aug 16 05:59:39 2014 rank self accum count trace method 1 74.87% 74.87% 1 308670 java.net.InetAddress$1.lookupAllHostAddr ...
So it seems that for some reason, JarVerifier is trying to get entropy from the system, and this causes the program to spend 5 seconds in InetAddress $ 1.lookupAllHostAddr ...
Edit 3:
Upgrading Java to version "1.7.0_67" does not fix the problem.