Thursday, February 16, 2012

Spring Beans and Dependency Injection - Part 1

In earlier posts, we saw how to manage session state - using cookies and hash tables, and even using jsp and Struts beans.

Trying to manage state ourselves can be difficult, even dangerous. Imagine managing a "Cart" object for each online customer. If you had a bug in your code, you could easily charge the wrong customer the wrong items, and ship them elsewhere! It would be a huge mess even before you realized you had a bug!

Let the professionals handle state.

Like Spring.

Spring Beans & Dependency Injection framework allows you to declare your stateful classes as spring beans. Spring will then take responsibility for creating, managing and destroying these class instances. It will make the right class instance available in the right place.

Let us see this with an example.

Suppose you have an online Shop, with a cart and checkout.

It is critical that the cart that gets filled in during shopping, is the same cart that gets charged at checkout.

Suppose we have a Shop.java class for shopping and a Checkout.java class for checking out. And we have a Cart.java class for the cart.

Both Shop.java and Checkout.java have to access the exact same instance of Cart.java.

If not, clearly, the customer will get charged all wrong. Therefore, we decide not to do this ourselves and let Spring do it for us.

So we declare Shop.java, Checkout.java and Cart.java all as Spring Beans.

We then tell Spring to "inject" the same instance of Cart.java into both Shop.java and Checkout.java.

This is called "Dependency Injection".

Doing all this is called "Bean Configuration" and "Bean Wiring" (telling Spring which Beans to inject). It can be done in an XML file, or as annotations.

In this example, we will use the XML file because it is the more established method.

Spring

Spring is probably one of the most talked about frameworks in Java. But you will probably never get a very clear answer what exactly it does!

This is because Spring is more or less an "umbrella" project which does several things - more and more each day.

It provides a Dependency Injection and Session Beans management framework, an MVC framework, Hibernate and JMS integration, Security infrastructure, Cloud support, etc, etc

Many of these components have nothing to do with each other.

We will try and use each of these Spring frameworks, starting with the Dependency Injection.

IoC - Inversion of Control

There are two ways to make bricks.

One, I hire Joe, tell him to get clay, mix the hardening agents, put it in the mold, bake it in the oven, inspect the brick quality, stack the bricks, ..... I am in control of the operation, Joe does as I ask.

Or, I could give Joe a specification of my bricks - and let Joe figure it out. How he does it is of no concern to me - so long as I get the bricks I want, stacked the way I want. Joe asks me for clarifications/suggestions as necessary. He is in control. I chip in when he asks.

Software is built like that too.

You can write software that pulls in external libraries and gets work done. Your code is the active component.

Or, you can write your software as a component that "plugs" into a bigger infrastructure. That infrastructure is the primary controller and calls your component/code as necessary.

This is called Inversion of Control, or IoC.

In Java, most of the time you will find yourself writing components that fit into a framework.

We already saw this in our previous posts - we wrote our servlets to the Java EE specification, and the Tomcat Servlet container called our servlets as necessary.

We also saw this in JSP - we wrote JSP templates and the JSP container transformed them into java classes and eventually HTML as necessary.

We wrote Struts controller and views, and Struts called them as necessary.

We will see more of this IoC pattern repeating as we use more frameworks.

Tuesday, February 14, 2012

Certificates

You see this word 'certificates' everywhere, but never know what it is.

Today is your lucky day!

In the last post, we generated a public/private key pair. Now, say, we want to use it.

We can give our public key to Joe, who encrypts his secret document with it and gives it to us.

But what if Mr.Evil gave Joe his own public key, saying it was our public key.

If Joe took Evil's word, he would be handing his secret document to Evil.

Instead, suppose, Joe could ask Evil for an "ID" - like a driver's license. Assuming it is impossible to forge driver's license, this would make it impossible for Evil to trick Joe.

This "driver's license" is called a Certificate.

After we generate a private and public key-pair, we can take our public key to a Certificate Authority (CA) like VeriSign. They give us a certificate, which is just a text file with .cert (or .crt) extension.

It looks like this in a text editor:
 Owner: CN=Mahesh Lavannis, OU=software design, O=cconfucius.org, L=Rockville, ST=MD, C=US  
Issuer: CN=Mahesh Lavannis, OU=software design, O=cconfucius.org, L=Rockville, ST=MD, C=US
Serial number: 4f3a8d65
Valid from: Tue Feb 14 11:35:49 EST 2012 until: Mon May 14 12:35:49 EDT 2012
Certificate fingerprints:
MD5: EF:12:64:80:EC:95:95:60:EE:84:83:F5:69:E0:16:A0
SHA1: 23:48:F9:E6:B3:3D:91:CB:F4:29:00:0A:DB:6E:2C:CF:04:80:1F:EE
Signature algorithm name: SHA1withRSA
Version: 3



The certificate contains a hash of the public key, a hash of the certificate itself, our name and contact information, a unique serial number, and several other things which can confirm that this certificate belongs to this public key.

(Note that this is a self-signed certificate, so the owner and issuer are the same. Typically, the issuer would be a Certificate Authority like VeriSign.)

Now, when Joe gets a public key and the corresponding certificate, he can give them to the Certificate Authority, and they will confirm if they match correctly.

Next question - what if Mr. Evil asked us for our public key and certificate, then give them both to Joe saying he was us.

Joe will believe him!

But, so what? If Joe encrypts his secret document and gives it to Evil, Evil still can't decrypt it because he does not have the private key!

Only way for Evil to really trick Joe is to have all three - the public key, the private key and the certificate.

That is why it is critical to keep the private key safely locked in the keystore, and the keystore itself saved under tight security on a machine that Evil cannot get to.

So, let us see all the steps involved in getting a certificate.

First, generate a private-public key-pair, like this:
 keytool -genkey -alias mydomain -keyalg RSA -keystore keystore.jks -keysize 2048  


Second, to request a certificate from a Certificate Authority, you need to give them a certificate signing request (CSR).

You can use keytool to generate the CSR, like this:
 keytool -certreq -alias mydomain -keystore keystore.jks -file mydomain.csr  


Third, after you get the certificate from the CA, you need to put it in the keystore, like this:
 keytool -import -trustcacerts -alias mydomain -file mydomain.crt -keystore keystore.jks  


Finally, you will point your web server (like Tomcat) to use this keystore and alias to get the public/private keys and certificate, in case a client connects to it with https.

(How you do that depends on the web server)

Sunday, February 12, 2012

Keystores

Keystores are used to store public/private keys and certificates, in a password protected manner.

Keystores are typically *.jks files, but there is no restriction on the filename or extension.

keytool is a Java utility used to create/manage keystores, keys and certificates.

To use keytool, make sure your JDK /bin directory is in your system PATH.

Now at a command prompt, type:

 C:\Users\mlavannis>keytool -genkey -alias org.confucius -keyalg RSA -keystore confucius.jks -keysize 2048  


This creates a new keystore ("confucius.jks") with a new set of RSA key-pair (aliased "org.confucius")

You will be asked a series of questions before the keystore and keys get created.

Use "changeit" as password for both the keystore and the key-pair.

Let us see how to access the key-pair from our Java code.

In your /src/org/confucius folder, create a class KeystoreAccess.java, like this:

 package org.confucius;  

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.security.Key;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.UnrecoverableKeyException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;

public class KeystoreAccess {
private static final String keystorePassword = "changeit";
private static final String keyPassword = "changeit";
private static final String keystoreFile = "C:\\users\\mlavannis\\confucius.jks";
private static final String keyAlias = "org.confucius";

public static void main(String[] args){
try {
KeyStore keystore = KeyStore.getInstance("JKS");
keystore.load(new FileInputStream(keystoreFile), keystorePassword.toCharArray());

Key key = keystore.getKey(keyAlias, keyPassword.toCharArray());
System.out.println("Key = " + key);

if (key instanceof PrivateKey) {
Certificate cert = keystore.getCertificate(keyAlias);
PublicKey publicKey = cert.getPublicKey();
System.out.println("Public Key = " + publicKey);
}
}
catch (KeyStoreException e) {
e.printStackTrace();
} catch (UnrecoverableKeyException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (CertificateException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}

}



We load the keystore and the keys (using its alias), then access the private and public keys.

R-click on the file in Eclipse navigator and select Run As --> Java Application.

You will see the private and public keys printed in the console.

Encryption with RSA

RSA is a asymmetric encryption algorithm. It has a public key used to encrypt and a private key used to decrypt.

Let us do the same example we did in the previous post, this time with RSA.

In your /src/org/confucius folder, create a class RSAEncryption.java, like this:

 package org.confucius;  

import java.security.InvalidKeyException;
import java.security.Key;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;

public class RSAEncryption {

public static void main(String[] args) {
String secretMessageString = "For your eyes only...";

try {
KeyPairGenerator kpg;
kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(2048);
KeyPair kp = kpg.genKeyPair();
Key publicKey = kp.getPublic();
Key privateKey = kp.getPrivate();

// Encrypt
Cipher encryptCipher = Cipher.getInstance("RSA");
encryptCipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] secretMessage = secretMessageString.getBytes();
byte[] encryptedMessage = encryptCipher.doFinal(secretMessage);
System.out.println("Encrypted Message = " + new String(encryptedMessage));

// Decrypt
Cipher decryptCipher = Cipher.getInstance("RSA");
decryptCipher.init(Cipher.DECRYPT_MODE, (Key) privateKey);
byte[] decryptedMessage = decryptCipher.doFinal(encryptedMessage);
System.out.println("Decrypted message = " + new String(decryptedMessage));

} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
}
}

}



If you run this program (R-click in navigator view, select Run As --> Java application) you will see the encrypted and decrypted string printed to the console.

Encryption with AES

Java Cryptography Architecture (JCA) provides support for encryption/decryption for most of the popular algorithms (AES, TripleDES, RSA, PBE, ..)

Here we will see how to do a symmetric encryption (same key for encrypt/decrypt) using AES.

The basic idea in JCA is to create a "cipher" using the secret key. Then use the cipher to encrypt/decrypt.

In your /src/org/confucius, create a class AESEncryption.java, like this:

 package org.confucius;  

import java.security.InvalidKeyException;
import java.security.Key;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.spec.KeySpec;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;

public class AESEncryption {

public static void main(String[] args) {
String keyString = "TOP-SECRET-KEY-SHARE-ONLY-WITH-INTENDED-RECEPIENT";
String secretMessageString = "For your eyes only...";

try {
// Create a AES Key
MessageDigest digester = MessageDigest.getInstance("SHA-256");
digester.update(keyString.getBytes());
byte[] key = digester.digest();
KeySpec keySpec = new SecretKeySpec(key, "AES" );

// Encrypt
Cipher encryptCipher = Cipher.getInstance("AES");
encryptCipher.init(Cipher.ENCRYPT_MODE, (Key) keySpec);
byte[] secretMessage = secretMessageString.getBytes();
byte[] encryptedMessage = encryptCipher.doFinal(secretMessage);
System.out.println("Encrypted Message = " + new String(encryptedMessage));

// Decrypt
Cipher decryptCipher = Cipher.getInstance("AES");
decryptCipher.init(Cipher.DECRYPT_MODE, (Key) keySpec);
byte[] decryptedMessage = decryptCipher.doFinal(encryptedMessage);
System.out.println("Decrypted message = " + new String(decryptedMessage));

} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
}
}

}



In this example code, we do both the encryption and decryption.

We create a KeySpec using the key string, then a cipher which uses the KeySpec, then use the cipher to encrypt/decrypt.

R-click on this file in your Eclipse navigator view, and select Run As->Java Application.

In the console, you will see both the encrypted and decrypted strings.