views:

238

answers:

1

Look at the following line of java:

Mac.getInstance("HmacSHA1");

If I put this in a simple test program, it runs without problems on my server. However, if I use this line in a container, I get

java.security.NoSuchAlgorithmException: Algorithm HmacSHA1 not available
  at javax.crypto.Mac.getInstance(DashoA13*..)

The same JDK installation is used in both cases.

After googling around a bit, I managed to get it to work by doing two things:

  1. Copying sunjce_provider.jar from $JAVA_HOME/jre/lib/ext to the lib directory of the container.
  2. Adding the following line to my code:

    java.security.Security.addProvider(new com.sun.crypto.provider.SunJCE());

Specifically, this happens to me in an Apache James mailet, but I'm pretty sure this is has to do with JVM options. Here is the startup script that it uses.

Although I got it to work in the end, the solution feels too hacked to be the right one. I would appreciate an explanation of what is going on, as well as a more "proper" solution.

Related question: http://stackoverflow.com/questions/1009996/using-java-crypto-leads-to-nosuchalgorithmexception. However, in this case I'm pretty sure the HmacSHA1 algorithm should be supported out of the box. As evidence, this works without problems in a test program.

+1  A: 

The startup script sets the java.ext.dirs to its own set of directories (specific to the application) but omitting the "normal" extension directory ($JAVA_HOME/jre/lib/ext/) which is where sunjce_provider.jar resides. This explains your first point (copying the Jar file to the lib directory makes it visible again). This is easily reproduced.

As for the second point, I think this is due the policy file that the startup script sets with the -Djava.security.policy option. Whether some providers are available or not depends on policy files. The default policy file makes the SunJCE provider available, but since the startup scripts mandates a non-default, custom policy file, then anything goes. I suggest you take a look at that policy file.

For instance, on my system (Ubuntu Linux, with Sun JVM 1.6.0_20 as packaged by Ubuntu), the default policy file is in /etc/java-6-sun/security/java.security and contains (among others) the following lines:

security.provider.1=sun.security.provider.Sun
security.provider.2=sun.security.rsa.SunRsaSign
security.provider.3=com.sun.net.ssl.internal.ssl.Provider
security.provider.4=com.sun.crypto.provider.SunJCE
security.provider.5=sun.security.jgss.SunProvider
security.provider.6=com.sun.security.sasl.Provider
security.provider.7=org.jcp.xml.dsig.internal.dom.XMLDSigRI
security.provider.8=sun.security.smartcardio.SunPCSC

which define what providers should be available by default. From your symptoms, I think that the custom policy file made SunJCE unavailable unless explicitly registered (which is understandable since the startup script also removed the access to the Jar file containing SunJCE...).

Thomas Pornin
Wish I could upvote you more than once. Oh wait, I can...
itsadok