Thursday, July 5, 2007

How Java Cryptography Extension works - Encryption and Decryption???


Java Cryptographic Extension is a very huge topic and I am not going to write a complete book here which makes my life miserable and readers also get bored reading chapters after chapters. In this post I am going to just discuss how Encryption and Decryption works using JCE API's and then give one working example. I will post other JCE features in coming posts.

Symmetric encryption

I know most of you are aware of how symmetric encryption works and what are the benifits/downsides of this but for whom this is a new topic it's my responsibility to give little bit of idea. This encryption method has a key which is shared by both parties (Encryper and Decryptor). It is much much faster compare to assymmetric encryption but exchanging key between both the parties is a complex task. This is used where bulk of data needs to be encrypted and decrypted. Even where ever assymmetric encryption is involved it is used for actual data encryption because assymmetric also is used to exchange symmetric key between parties. ( Please refer to my post How SSL works) .

I don't want to take more of your precious time and get back to real business here

Main cryptography classes used in this article comes from javax.crypto.* package.

Most of the classes in the JCE use factory methods instead of new operator for creating class.
Cipher class is the engine of the car and following are 4 wheels on which you can enjoy the ride on the car.

Wheel 1 : getInstance()

Make a call to the class's getInstance() method, with the name of the algorithm and some additional parameters like so:

Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");

The first parameter is the name of the algorithm, in this case, "DESede". The second is the mode the cipher should use, "ECB", which stands for Electronic Code Book. The third parameter is the padding, specified with "PKCS5Padding". In case second and third parameters are not mentioned they will be taken as per the JCE provider specification.

Wheel 2 : init()

Once an instance of Cipher is obtained, it must be initialized with the init() method. This declares the operating mode, which should be either ENCRYPT_MODE or DECRYPT_MODE, WRAP_MODE, UNWRAP_MODE and also passes the cipher a key (java.security.Key, described later). Assuming we had a key declared, initialized, and stored in the variable myKey, we could initialize a cipher for encryption with the following line of code:

cipher.init(Cipher.ENCRYPT_MODE, myKey);


Wheel 3 : update()

In order to actually encrypt or decrypt anything, we need to pass it to the cipher in the form of a byte array. If the data is in the form of anything other than a byte array, it needs to be converted. If we have a string called encryptme and we want to encrypt it with the cipher we've initialized above, we can do so with the following two lines of code:

byte[] plaintext = encryptme.getBytes("UTF8");
byte[] ciphertext = cipher.update(plaintext);

Ciphers typically buffer their output. If the input is large enough that it produces some ciphertext, it will be returned as a byte array. If the buffer has not been filled, then null will be returned. Note that in order to get bytes from a string, we should specify the encoding method. In most cases, it will be UTF8.

Wheel 4 : doFinal()

Now we can actually get the encrypted data from the cipher. doFinal() will produce a byte array, which is the encrypted data.

byte[] ciphertext = cipher.doFinal();

A number of the methods we've talked about can be overloaded with different arguments, like start and end indices for the byte arrays passed in.


As we need to have a key which we will be using to encrypt/decrypt the stuff, let's discuss a bit about java.security.key interface (NOTE this is an interface).

We will be creating instance of this interface by it's implementer classes like javax.crypto.KeyGenerator or java.security.KeyFactory

Key interface has three methods

1) getInstance()
Below example will generate DES key.
KeyGenerator keyGenerator = KeyGenerator.getInstance("DESede");

2) init()
Below code will generate 3DES key which is always 168 bits.
keyGenerator.init(168);

3) generateKey()

Finally we get the key using this method.
Key myKey = keyGenerator.generateKey();

Now since we have all the necessary things to build a house lets construct it. Just think before you start constructing it. Which brick will fit at what spot to make it a perfect house.

1) We need a key which we will be using for encryption and decryption.
2) We need to instantiate Cypher class using factory method to do the actual job.



package com.kapil.util;

import java.security.Key;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;

public class JESEncryptDecrypt
{
public static void main (String[] args)
throws Exception
{
if (args.length != 1) {
System.err.println("Please enter text to encrypt");
System.exit(1);
}
String text = args[0];

System.out.println("Generating a DESede (TripleDES) key...");

// Create a TripleDES key

KeyGenerator keyGenerator = KeyGenerator.getInstance("DESede");
keyGenerator.init(168); // need to initialize with the keysize
Key key = keyGenerator.generateKey();

System.out.println("Done generating the key.");

// Create a cipher using that key to initialize it

Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, key);

byte[] plaintext = text.getBytes("UTF8");

// Print out the bytes of the plaintext

System.out.println("\nPlaintext: ");

for (int i=0;i < plaintext.length;i++)
{
System.out.print(plaintext[i]+" ");
}
// Perform the actual encryption

byte[] ciphertext = cipher.doFinal(plaintext);

// Print out the ciphertext

System.out.println("\n\nCiphertext: ");
for (int i=0;i < ciphertext.length;i++) {
System.out.print(ciphertext[i]+" ");
}

// Re-initialize the cipher to decrypt mode

cipher.init(Cipher.DECRYPT_MODE, key);

// Perform the decryption

byte[] decryptedText = cipher.doFinal(ciphertext);

String output = new String(decryptedText,"UTF8");

System.out.println("\n\nDecrypted text: "+output);
}
}

No comments: