Showing posts with label JCE. Show all posts
Showing posts with label JCE. Show all posts

Sunday, 16 November 2014

Generating MD5 hash in Java

Background

Heard of MD5 hashing algorithm ?  MD5 stands for Message Digest algorithm 5 which is a cryptographic algorithm invented by Ronald Rivest in 1991 for calculating hash values. So MD5 is a widely used hashing algorithm in many companies and firms. (MD5 Wiki)

How did I get here you ask ? 

I was trying to understand how passwords are stored in database. For example you create a website where users can login you will need to store user credentials - username and password for instance. Now how would you store the password ? Plain text ? Don't guess... answer is NO! It is a major security flaw. Anyone can get the passwords once they get into the file system you are using to store the passwords. Then store in encrypted ? Better idea then storing as raw text but again not recommended. Once someone knows the encryption method you have used all your sensitive data is gone. Infact developers developing the product should not know what passwords users have. And answer to all of it is hash the password string and store it which is exactly why we are looking at MD5 algorithm in this post. Well... natural question to follow is how is password verified when user logs in again? Again the hash of user entered password is generated and compared against the save hash value.

Infact you can use MD5 checksum to verify integrity of your files after transferring it over the network. In linux you can use md5sum command to calculate the checksum value. 

  • Hash is 128 bit or 16 byte or 32 hex characters.



If checksum is same after transferring your file over the network then your files is transferred correctly. If it's not the same that mean your file is corrupted.

To the Code

 Java code to generate MD5 hash is as follows - 

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;


public class MD5HashDemo {
    
    public static void main(String args[]) throws IOException 
    {
        
        String password = "password";
        try {
            System.out.println("MD5 hash generated : " + getMD5Hash(password));
        } catch (NoSuchAlgorithmException e) {
            System.out.println("Could not generate MD5 hash for password");
            e.printStackTrace();
        }
        
    }
    
    public static String getMD5Hash(String password) throws NoSuchAlgorithmException, UnsupportedEncodingException
    {
        
        byte[] passwordBytes = password.getBytes("UTF-8");
        MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] md5Bytes = md.digest(passwordBytes);
        
        StringBuffer hexStringBuffer = new StringBuffer();
        for (int i=0;i<md5Bytes.length;i++) {
            String hexString=Integer.toHexString(md5Bytes[i] & 0xff);
                if(hexString.length()==1) 
                {
                hexStringBuffer.append('0');
                }
            hexStringBuffer.append(hexString);
        }
        
        return hexStringBuffer.toString();
    }

}


Output : 
MD5 hash generated : 5f4dcc3b5aa765d61d8327deb882cf99

Above is just plain raw method to generate MD5 hash but we need not code from scratch. We have libraries that help us do that. You can use commons-codec library which apache provides. Then you can get the hash by simply executing -

org.apache.commons.codec.digest.DigestUtils.md5Hex(password);

Even Spring framework provides such a method.

Note :  See how I have used "UTF-8" encoding in getBytes() method? It is a good idea to do so unless you are using a specific encoding throughout your application. If not provided system encoding is picked up by default which may vary from system to system.


Lets now come to million dollar question....

Is it possible to decrypt md5 hashes?

Answer is No! If we could then why bother for hashing we could go for good encryption only. So we cannot get the original string from the hash unless you use Rainbow tables do some kind of brute forcing technique to guess.  But even using that it is almost impossible to get the original string back.

Also if you use Salt to generate the hash then even above techniques won't work. Using salt gives different hashes every time for same String input. But note using salt will not work in case of passwords for obvious reasons (you will not be able to compare it then)



Related Links

Sunday, 21 September 2014

How to install Java Cryptography Extension (JCE) unlimited strength jurisdiction policy files

Problem

JCE has been integrated into the Java 2 SDK since the 1.4 release.

Below diagram shows a general overview of Java cryptographic architecture. What we are discussing in this post is related to JCE implementation provided by Sun/Oracle.




As per the Oracle documentation - 

Due to import control restrictions by the governments of a few countries, the jurisdiction policy files shipped with the JDK 5.0 from Sun Microsystems specify that "strong" but limited cryptography may be used.

 That mean JDK has a deliberate key size restriction by default. So you cannot perform an encryption with key more than 128 bits (16 bytes). If you do you will get an error something like -

Caused by: java.security.InvalidKeyException: Illegal key size or default parameters

If you get this Exception there is nothing wrong that you are doing. It's just the restriction on the encryption key that comes built into the JDK.

The reason for this is that some countries have restrictions on the permitted key strength used in encryption algorithms.

Again as per the documentation - 

An "unlimited strength" version of these files indicating no restrictions on cryptographic strengths is available for those living in eligible countries (which is most countries). But only the "strong" version can be imported into those countries whose governments mandate restrictions. The JCE framework will enforce the restrictions specified in the installed jurisdiction policy files.


Update -  Updates Since Java 8 and Java 9

There have been multiple updates since Java 8 and 9. Before you dive down into more details review this section based on the Java version you are using. I have shown how to resolve this issue with various Java versions in the video below. 




Java 9 and higher :


The Unlimited Strength Jurisdiction Policy Files are included with Java 9 and used by default (see Security Updates in the Java 9 Migration Guide).

If you get this error with Java 9, it might mean the policy configuration has been changed to a more restrictive policy (limited), see the instructions from the migration guide:

It states -

JCE Jurisdiction Policy File Default is Unlimited

If your application previously required the Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files, then you no longer need to download or install them. They are included in the JDK and are activated by default.

If your country or usage requires a more restrictive policy, the limited Java cryptographic policy files are still available.

If you have requirements that are not met by either of the policy files provided by default, then you can customize these policy files to meet your needs.

See the crypto.policy Security property in the  <java-home>/conf/security/java.security file, or Cryptographic Strength Configuration in the Java Platform, Standard Edition Security Developer's Guide.

Java 8 Update 161 and higher

Starting with Java 8 Update 161, Java 8 defaults to the Unlimited Strength Jurisdiction Policy. If you receive this error, it could indicate the configuration has been changed to limited. See instructions in the next section on Java 8 Update 151, or the previous section on Java 9, for changing this back to unlimited.

Java 8 Update 151 and higher

Starting with Java 8 Update 151, the Unlimited Strength Jurisdiction Policy is included with Java 8 but not used by default. To enable it, you need to edit the java.security file in <java_home>/jre/lib/security (for JDK) or <java_home>/lib/security (for JRE). Uncomment (or include) the line

crypto.policy=unlimited
Make sure you edit the file using an editor run as administrator.

The policy change only takes effect after restarting the JVM (this is especially important for long-running server processes like Tomcat).

For backward compatibility, installing the policy files as documented in the next section will still work as well.


Before Java 8 Update 151 - Removing the maximum key size restriction

You can remove the maximum key restriction by replacing the existing JCE jars with unlimited strength policy jars.

 Download the zip file extract the jars and replace them in your JDK/JRE.

For this Copy local_policy.jar and US_export_policy.jar extracted from above zip file to the $JAVA_HOME/jre/lib/security 

Note: These jars will already be present there so you will have to overwrite them.

Then simply restart your java application and the Exception should be gone.

NOTE: If you are using Ubuntu and the webupd8 PPA, you can simply run -

  • apt-get install oracle-java8-unlimited-jce-policy

 An alternate way to maximum encryption key size problem

This way is really a workaround. In fact, this approach is the workaround to all problems and it's not straightforward. Yeah you must have guessed it by now - Reflection

You can override the restriction with Reflection as follows - 

try {
    Field field = Class.forName("javax.crypto.JceSecurity").getDeclaredField("isRestricted");
    field.setAccessible(true);
    field.set(null, java.lang.Boolean.FALSE);
   } catch (Exception ex) {
      ex.printStackTrace();
   }

Note 1: I do not recommend the Reflection approach as it's hacky. If you are using it keep it for testing only. Don't put it in production code :)

Note 2: As the change of replacing policy files is in JDK itself you will have to do it in all your servers. Also, you will have to ask all your clients to do so.

Finding the maximum possible key length

To find maximum key length allowed by an encryption algorithm you can use Cipher.getMaxAllowedKeyLength() method.  For example, for AES algorithm you can do - 

int maxKeyLength = Cipher.getMaxAllowedKeyLength("AES");


Related Links

t> UA-39527780-1 back to top