Posts Tagged Java

Encrypt and decrypt with Java

Encryption is a very important subject in computer science which developers need to deal with quite often. I already wrote a few years ago an article containing some code to encrypt data with PHP and decrypt it with Java.

I will give you this time the code to encrypt and decrypt data with the same language: Java. Once again, I used a secret key and an initialization vector for the encryption and decryption.

And here it is:

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.math.BigInteger;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

/**
 * This class provides methods to encrypt and decrypt data.
 * @author Stephane Moreau
 */
public class Crypto {
    private static String md5(final String input) throws NoSuchAlgorithmException {
        final MessageDigest md = MessageDigest.getInstance("MD5");
        final byte[] messageDigest = md.digest(input.getBytes());
        final BigInteger number = new BigInteger(1, messageDigest);
        return String.format("%032x", number);
    }

    private Cipher initCipher(final int mode, final String initialVectorString, final String secretKey)
            throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException {
        final SecretKeySpec skeySpec = new SecretKeySpec(md5(secretKey).getBytes(), "AES");
        final IvParameterSpec initialVector = new IvParameterSpec(initialVectorString.getBytes());
        final Cipher cipher = Cipher.getInstance("AES/CFB8/NoPadding");
        cipher.init(mode, skeySpec, initialVector);
        return cipher;
    }

    public String encrypt(final String dataToEncrypt, final String initialVector, final String secretKey) {
        String encryptedData = null;
        try {
            // Initialize the cipher
            final Cipher cipher = initCipher(Cipher.ENCRYPT_MODE, initialVector, secretKey);
            // Encrypt the data
            final byte[] encryptedByteArray = cipher.doFinal(dataToEncrypt.getBytes());
            // Encode using Base64
            encryptedData = (new BASE64Encoder()).encode(encryptedByteArray);
        } catch (Exception e) {
            System.err.println("Problem encrypting the data");
            e.printStackTrace();
        }
        return encryptedData;
    }

    public String decrypt(final String encryptedData, final String initialVector, final String secretKey) {
        String decryptedData = null;
        try {
            // Initialize the cipher
            final Cipher cipher = initCipher(Cipher.DECRYPT_MODE, initialVector, secretKey);
            // Decode using Base64
            final byte[] encryptedByteArray = (new BASE64Decoder()).decodeBuffer(encryptedData);
            // Decrypt the data
            final byte[] decryptedByteArray = cipher.doFinal(encryptedByteArray);
            decryptedData = new String(decryptedByteArray, "UTF8");
        } catch (Exception e) {
            System.err.println("Problem decrypting the data");
            e.printStackTrace();
        }
        return decryptedData;
    }

    public static void main(final String[] args) {
        final String iv = "0123456789123456"; // This has to be 16 characters
        final String secretKey = "Replace this by your secret key";
        final Crypto crypto = new Crypto();

        final String encryptedData = crypto.encrypt("This is a test message.", iv, secretKey);
        System.out.println(encryptedData);

        final String decryptedData = crypto.decrypt(encryptedData, iv, secretKey);
        System.out.println(decryptedData);
    }
}

, , ,

12 Comments

MD5 generates 31 bytes instead of 32

I wrote the following method to generate MD5 hashes:

private static String md5(String input) throws NoSuchAlgorithmException {
    MessageDigest md = MessageDigest.getInstance("MD5");
    byte[] messageDigest = md.digest(input.getBytes());
    BigInteger number = new BigInteger(1, messageDigest);
    return number.toString(16);
}

This method takes a String and outputs a 32 character hash.

However, depending on the value of the parameter, this method outputs a 31 character hash instead of 32.
Why is that?

It appears that it is because the leading zero is missing. But the question remains! Why?
This is simply because the toString method doesn’t know that we are expecting a leading zero. BigInteger stores just a number; it doesn’t know how many leading zeroes we need.

For example, how many leading zero would you expect with the following code?

new BigInteger("33").toString()

In order to be sure MD5 generates 32 bytes, we could replace the number.toString(16) by:

String.format("%032x", number)

So, the method will look like the following:

private static String md5(String input) throws NoSuchAlgorithmException {
    MessageDigest md = MessageDigest.getInstance("MD5");
    byte[] messageDigest = md.digest(input.getBytes());
    BigInteger number = new BigInteger(1, messageDigest);
    return String.format("%032x", number);
}

, , , ,

No Comments

Changes in Twitter4J 2.2.5

Over a year ago, I wrote an article on how to update Twitter status using Twitter4J:
Update your Twitter status with Java
Note that I was using the version 2.1.7 of Twitter4J at that time.

Following a few comments from users who were getting errors, I decided to get my code working on the latest version of Twitter4J, the version 2.2.5. πŸ™‚

This is the two differences I found:

  1. The package twitter4j.http has been renamed twitter4j.auth;
  2. The constructor of the object twitter4j.auth.OAuthAuthorization has changed and now only take an object of type twitter4j.conf.Configuration.

Considering this, please find below the updated code to get the access token:

import java.io.BufferedReader;
import java.io.InputStreamReader;

import twitter4j.Twitter;
import twitter4j.TwitterException;
import twitter4j.TwitterFactory;
import twitter4j.auth.AccessToken;
import twitter4j.auth.RequestToken;

public class TwitterAccessToken {
	private static final String CONSUMER_KEY = "[your consumer key]";
	private static final String CONSUMER_SECRET = "[you consumer secret]";

	public static void main(String[] args) throws Exception {
 		Twitter twitter = new TwitterFactory().getInstance();
		twitter.setOAuthConsumer(CONSUMER_KEY, CONSUMER_SECRET);
		RequestToken requestToken = twitter.getOAuthRequestToken();
		AccessToken accessToken = null;
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		while (null == accessToken) {
			System.out.println("Open the following URL and grant access to your account:");
			System.out.println(requestToken.getAuthorizationURL());
			System.out.print("Enter the PIN (if available) or just hit enter.[PIN]:");
			String pin = br.readLine();
 			try {
				if (pin.length() > 0) {
					accessToken = twitter.getOAuthAccessToken(requestToken, pin);
				} else {
					accessToken = twitter.getOAuthAccessToken();
				}
			} catch (TwitterException e) {
				if (401 == e.getStatusCode()) {
					System.err.println("Unable to get the access token.");
				} else {
					e.printStackTrace();
				}
			}
		}

		System.out.println("Access Token: " + accessToken.getToken());
		System.out.println("Access Token Secret: " + accessToken.getTokenSecret());
	}
}

And here is the amended code which allows to update your Twitter status:

import twitter4j.Twitter;
import twitter4j.TwitterException;
import twitter4j.TwitterFactory;
import twitter4j.auth.OAuthAuthorization;
import twitter4j.conf.ConfigurationBuilder;

public class TwitterTest {
	private static final String ACCESS_TOKEN = "[your access token]";
	private static final String ACCESS_TOKEN_SECRET = "[your access token secret]";
	private static final String CONSUMER_KEY = "[your consumer key]";
	private static final String CONSUMER_SECRET = "[you consumer secret]";

    public static void main(String[] args) {
    	ConfigurationBuilder builder = new ConfigurationBuilder();
    	builder.setOAuthAccessToken(ACCESS_TOKEN);
    	builder.setOAuthAccessTokenSecret(ACCESS_TOKEN_SECRET);
    	builder.setOAuthConsumerKey(CONSUMER_KEY);
    	builder.setOAuthConsumerSecret(CONSUMER_SECRET);
        OAuthAuthorization auth = new OAuthAuthorization(builder.build());
        Twitter twitter = new TwitterFactory().getInstance(auth);
		try {
			twitter.updateStatus("Hello World!");
		} catch (TwitterException e) {
			System.err.println("Error occurred while updating the status!");
			return;
		}
        System.out.println("Successfully updated the status.");
    }
}

See you maybe next year for an update on using the version 2.3 of Twitter4j. πŸ˜‰

, , ,

43 Comments

Too many open files on Tomcat

The other day, one of my websites was not available anymore. Looking at the log files, I found the following exception:

Dec 7, 2011 1:22:39 AM org.apache.jk.common.ChannelSocket acceptConnections
WARNING: Exception executing accept
java.net.SocketException: Too many open files
	at java.net.PlainSocketImpl.socketAccept(Native Method)
	at java.net.PlainSocketImpl.accept(PlainSocketImpl.java:384)
	at java.net.ServerSocket.implAccept(ServerSocket.java:450)
	at java.net.ServerSocket.accept(ServerSocket.java:421)
	at org.apache.jk.common.ChannelSocket.accept(ChannelSocket.java:307)
	at org.apache.jk.common.ChannelSocket.acceptConnections(ChannelSocket.java:661)
	at org.apache.jk.common.ChannelSocket$SocketAcceptor.runIt(ChannelSocket.java:872)
	at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:690)
	at java.lang.Thread.run(Thread.java:595)

This was the first time I was getting this exception. What is even stranger is that I didn’t change anything on this application for quite a while!
Anyway, I first did what I usually do with Tomcat: restart it! This fixed the issue but only for a few hours before it crashed again.

After some investigation, it seems that Tomcat was reaching the limit of open file descriptors allowed in this machine (1024 in my case).
To get the maximum number of open file descriptors, simply type the following command:

ulimit -n

It is possible to increase this value by editing the file /etc/security/limits.conf and adding the new limit for the user running Tomcat. However, this is not recommended as 1024 should be sufficient.

The second thing I did was to check the list of open files used by the Tomcat process:

lsof -p 

What I found by running this command was a bit odd. It seems that Tomcat was having a multitude of opened connections to one of the web services used by the application. So it looks like the connections between my website and the web service were never closed!  😐
Because I didn’t change the code on my side, I asked the third party who owns the web service to check their code. I don’t know what was the root cause of the problem but they fixed it on their side and it is now working fine.

In conclusion, if you get the same exception, try to find where the problem is coming from before increasing the maximum number of open file descriptors. πŸ˜‰

, , , , , ,

No Comments

Make image backgrounds transparent with tolerance

In one of the projects I am working on at the moment, I needed to convert the background colour of an image to be transparent so the image looks better on a non-white background.

Looking on the Web, I found the following article from Dustin Marx:
Making White Image Backgrounds Transparent with Java 2D/Groovy
If the link is broken, please download his code from the following link: ImageTransparency.java

The method which makes the background colour transparent is called makeColorTransparent. This method works pretty well, except in some cases as shown in the example below:

Original image Converted image
using Dustin’s method

This is actually quite normal. Indeed, his code is converting a specific colour (#FFFFFF in our case) to be transparent. But what if the background is not homogeneous?

This is the reason why I had to modify his method to add a new parameter called tolerance:

private Image makeColorTransparent(final BufferedImage im, final Color color, int tolerance) {
    int temp = 0;
    if (tolerance < 0 || tolerance > 100) {
        System.err.println("The tolerance is a percentage, so the value has to be between 0 and 100.");
        temp = 0;
    } else {
        temp = tolerance * (0xFF000000 | 0xFF000000) / 100;
    }
    final int toleranceRGB = Math.abs(temp);
		
    final ImageFilter filter = new RGBImageFilter() {
        // The color we are looking for (white)... Alpha bits are set to opaque
        public int markerRGBFrom = (color.getRGB() | 0xFF000000) - toleranceRGB;
        public int markerRGBTo = (color.getRGB() | 0xFF000000) + toleranceRGB;

        public final int filterRGB(final int x, final int y, final int rgb) {
            if ((rgb | 0xFF000000) >= markerRGBFrom && (rgb | 0xFF000000) <= markerRGBTo) {
                // Mark the alpha bits as zero - transparent
                return 0x00FFFFFF & rgb;
            } else {
                // Nothing to do
                return rgb;
            }
        }
    };

    final ImageProducer ip = new FilteredImageSource(im.getSource(), filter);
    return Toolkit.getDefaultToolkit().createImage(ip);
}

Such as Photoshop, the tolerance is a percentage value between 0 and 100. The higher the tolerance is, the bigger the range of colours will be.

Let’s take our previous example and apply a 50% tolerance:

That looks much better, isn’t it? πŸ™‚

, , ,

3 Comments