Skip to content
accelerando

Monthly Archives: July 2011

Java and invalid SSL certificates (java-trustprovideragent)

25-Jul-11

It’s truly easy to generate a SSL certificate for example to use with tomcat (see here). This certificate is invalid as it is self-signed by you and it often doesn’t match the hostname. This is no problem when your access the project with a browser, with more or less jumps through hoops you accept the development certificate and you’re done.

If you access the site through java itself you’ll have problem with all tools that basically use an URLConnection. You’ll end up with an exception like this:

Exception in thread "main" javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: 
PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: 
unable to find valid certification path to requested target

This is will hit you for example using HtmlUnit or my oembed client.

It isn’t enough to import the certificate in question using keytool (at least, it didn’t work for me).

I search and i found this post titled “SSL Trust Provider for Java”. Interesting stuff.

This works by providing a “java.security.Provider” through the Security API accepting all certificates. Nice tip, thanks!

I didn’t want to change my sources though so i wrote a very little java agent to instrument my development setup. I also added a “javax.net.ssl.HostnameVerifier” that accepts all host names, in case the certificates cn doesn’t match the development machines hostname. If i want my vm to trust all and everything, i just add “-javaagent:full/path/to/java-trustprovideragent-0.0.1-SNAPSHOT.jar”.

The code is on github java-trustprovideragent, please feel free to use it.

Thanks to the original authors on devcentral.f5.com.

MySql compatible AES encryption / decryption in Java

18-Jul-11

MySQL has an aes_encrypt/aes_decrypt pair of functions (Encryption and Compression Functions) that enable encryption and decryption of data using the official AES algorithm.

The functions are easy to use (select AES_ENCRYPT(‘text’,'password’)) and the result is easy to store (insert into secrets values HEX(AES_ENCRYPT(‘text’,'password’))) as hex values.

I used this technique for a while but i wanted to have a more database agnostic version of this encryption and tried to build the same methods with java.

Although it was relatively easy to find the exact cipher mode (which is AES/ECB/PKCS5Padding), i had a real hard time figuring out how the key is calculated from the given password (the key must be 16bytes long, per default MySql uses AES-128). It turns out that the MySQL algorithm just or’s the bytes of a given passphrase against the previous bytes if the password is longer than 16 chars and just leaves them 0 when the password is shorter than 16 chars. So you can generate a secret key spec in Java for an aes_encrypt/decrypt compatible cipher like so:

import java.io.UnsupportedEncodingException;
 
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
 
import org.apache.commons.codec.binary.Hex;
 
public class Demo {
	public static SecretKeySpec generateMySQLAESKey(final String key, final String encoding) {
		try {
			final byte[] finalKey = new byte[16];
			int i = 0;
			for(byte b : key.getBytes(encoding))
				finalKey[i++%16] ^= b;			
			return new SecretKeySpec(finalKey, "AES");
		} catch(UnsupportedEncodingException e) {
			throw new RuntimeException(e);
		}
	}
 
	public static void main(String... args) throws Exception {
		// Decrypt
		final Cipher decryptCipher = Cipher.getInstance("AES");	        				
		decryptCipher.init(Cipher.DECRYPT_MODE, generateMySQLAESKey("your super secret passphrase", "UTF-8"));
		System.out.println(new String(decryptCipher.doFinal(Hex.decodeHex("56A34D7AB6225616799F6559AA388F07C2C9E53983111BDD5F49F36461AAD789".toCharArray()))));
 
		// Encrypt
		final Cipher encryptCipher = Cipher.getInstance("AES");	        				
		encryptCipher.init(Cipher.ENCRYPT_MODE, generateMySQLAESKey("your super secret passphrase", "UTF-8"));		
		System.out.println(String.format("Select aes_decrypt(unhex('%s'), 'your super secret passphrase');", new String(Hex.encodeHex(encryptCipher.doFinal("Hallo nach Aachen".getBytes("UTF-8")))))); 
	}
}

You need Commons Codec to run these.

This isn’t probably the most secure solution from a cryptographic point of view but it just replicates the built-in MySql function for other databases or just for interoperability. I hope to save someone else time with this as i spent about days about those view lines.

Close
E-mail It