Tuesday, 17th August 2010
The new frontier for learning Java

Secret Key Cryptography Tutorial

From WikiJava

Jump to: navigation, search
The author suggests:

buy this book

this tutorial guides you through the Java Cryptographic Extension. It's a simple example of how you can encrypt and decrypt a string message using a private key.


Contents

the article

Overview

we can separate the process into few steps:

  1. Generate the encryption key
  2. Encrypt the message using the generated key
  3. Decrypt the message starting from the encrypted message and the generated key

Note that in this example we use a private key algorithm this means that the same key for encrypting is used both for encryption and decryption.

Generate the encryption key

The following code generates a java.security.Key that is a valid DES algorithm encryption key.

private Key key;
 
private void generateKey() throws NoSuchAlgorithmException {
	KeyGenerator generator;
	generator = KeyGenerator.getInstance("DES");
	generator.init(new SecureRandom());
	key = generator.generateKey();
}

the method getInstance(String algorithm) of the javax.crypto.KeyGenerator class, returns javax.crypto.KeyGenerator objects for the algorithm.

The generator object must then be initialized with a java.security.SecureRandom that grants secure random numbers, as we need the random number to be cryptographically strong.

Finally we can generate the secret encryption key, this is done using the method generateKey() that returns the java.security.Key that we need.

Encrypt the message

Now we get into the interesting part of the game, the encryption of a message.

There are three steps involved in this:

  1. building the Cipher object that will be responsible of doing the encryption.
  2. converting the message to a format suitable for the Cipher
  3. converting the encrypted message to a format that will be easy

to read on screen (this step is not really needed, but we do it :) )

See the comments in the code for details:

private String encrypt(String message) throws IllegalBlockSizeException,
	    BadPaddingException, NoSuchAlgorithmException,
	    NoSuchPaddingException, InvalidKeyException,
	    UnsupportedEncodingException {
	// Get a cipher object.
	Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
	cipher.init(Cipher.ENCRYPT_MODE, key);
 
	// Gets the raw bytes to encrypt, UTF8 is needed for
	// having a standard character set
	byte[] stringBytes = message.getBytes("UTF8");
 
	// encrypt using the cypher
	byte[] raw = cipher.doFinal(stringBytes);
 
	// converts to base64 for easier display.
	BASE64Encoder encoder = new BASE64Encoder();
	String base64 = encoder.encode(raw);
 
	return base64;
}


Decrypt the message

The steps for decrypting the message are basically doing the reverse steps in the reverse order as the encryption:

  1. Obtain a Cipher, same as for the encryption, just now it's in DECRYPT_MODE
  2. decode the BASE64 coded message, we need to pass in to the decrypter exactly the same string that we got out from the encrypter.
  3. Decrypt the message using the Cipher
  4. Convert the decrypted byte array to the String so it can be printed easily

Note: the only data in common between the encryption and the decryption methods is the key.

private String decrypt(String encrypted) throws InvalidKeyException,
	    NoSuchAlgorithmException, NoSuchPaddingException,
	    IllegalBlockSizeException, BadPaddingException, IOException {
 
	// Get a cipher object.
	Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
	cipher.init(Cipher.DECRYPT_MODE, key);
 
	//decode the BASE64 coded message
	BASE64Decoder decoder = new BASE64Decoder();
	byte[] raw = decoder.decodeBuffer(encrypted);
 
	//decode the message
	byte[] stringBytes = cipher.doFinal(raw);
 
	//converts the decoded message to a String
	String clear = new String(stringBytes, "UTF8");
	return clear;
}


Image:250px-Subversion.png
You can download the complete code of this article from the Subversion repository at this link

Using the username:readonly and password: readonly

See the using the SVN repository instructions page for more help about this.

the whole class

package org.wikijava.crypto;
 
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
 
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
 
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
 
/**
 *  
 * @author Giulio
 */
public class CryptoMessage {
 
    private Key key;
 
    /**
     * Generates the encryption key. using "des" algorithm
     * 
     * @throws NoSuchAlgorithmException
     */
    private void generateKey() throws NoSuchAlgorithmException {
	KeyGenerator generator;
	generator = KeyGenerator.getInstance("DES");
	generator.init(new SecureRandom());
	key = generator.generateKey();
    }
 
    private String encrypt(String message) throws IllegalBlockSizeException,
	    BadPaddingException, NoSuchAlgorithmException,
	    NoSuchPaddingException, InvalidKeyException,
	    UnsupportedEncodingException {
	// Get a cipher object.
	Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
	cipher.init(Cipher.ENCRYPT_MODE, key);
 
	// Gets the raw bytes to encrypt, UTF8 is needed for
	// having a standard character set
	byte[] stringBytes = message.getBytes("UTF8");
 
	// encrypt using the cypher
	byte[] raw = cipher.doFinal(stringBytes);
 
	// converts to base64 for easier display.
	BASE64Encoder encoder = new BASE64Encoder();
	String base64 = encoder.encode(raw);
 
	return base64;
    }
 
      private String decrypt(String encrypted) throws InvalidKeyException,
	    NoSuchAlgorithmException, NoSuchPaddingException,
	    IllegalBlockSizeException, BadPaddingException, IOException {
 
		// Get a cipher object.
		Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
		cipher.init(Cipher.DECRYPT_MODE, key);
 
		//decode the BASE64 coded message
		BASE64Decoder decoder = new BASE64Decoder();
		byte[] raw = decoder.decodeBuffer(encrypted);
 
		//decode the message
		byte[] stringBytes = cipher.doFinal(raw);
 
		//converts the decoded message to a String
		String clear = new String(stringBytes, "UTF8");
		return clear;
    }
 
    public CryptoMessage(String message) {
	try {
	    System.out.println("clear message: " + message);
 
	    generateKey();
 
	    String encrypted = encrypt(message);
	    System.out.println("encrypted message: " + encrypted);
 
	    String decrypted = decrypt(encrypted);
	    System.out.println("decrypted message: " + decrypted);
 
	} catch (NoSuchAlgorithmException e) {
	    e.printStackTrace();
	} catch (NoSuchPaddingException e) {
	    e.printStackTrace();
	} catch (InvalidKeyException e) {
	    e.printStackTrace();
	} catch (UnsupportedEncodingException e) {
	    e.printStackTrace();
	} catch (IllegalBlockSizeException e) {
	    e.printStackTrace();
	} catch (BadPaddingException e) {
	    e.printStackTrace();
	} catch (IOException e) {
	    e.printStackTrace();
	}
    }
 
    /**
     * 
     * @param args
     */
    public static void main(String[] args) {
	if (args.length == 1) {
	    new CryptoMessage(args[0]);
	} else {
	    System.out.println("usage: ");
	    System.out.println("CryptoMessage [message]");
	}
 
    }
 
}

Comments from the users

To be notified via mail on the updates of this discussion you can login and click on watch at the top of the page

key management?

You might want to mention that any data you encrypt with this and then store will be lost forever after the program terminates. It generates a new, random key each run of the program. You could use a PBE algorithm or introduce the KeyStore...

--209.191.15.3 19:16, 2 January 2009 (UTC)


right,

Yeah.. thanks I forgot to mention it. The key is generated new at each execution. This program is just an experiment but has no real practical use. To be of any use we would need to store the generated key somehow. For example in a file.

--DonGiulio 20:12, 2 January 2009 (UTC)


algorithms

Can we apply any algorithms ( I tried with TwoFish2) on the same program. My trial with TwoFish2 failed saying 'Twofish2 KeyGenerator not available' Hanumesh

--61.16.169.37 12:18, 13 January 2009 (UTC)


re:

Hi Hanumesh, What did you write exactly?


--DonGiulio 14:57, 14 January 2009 (UTC)


Storing generated key

Can I just ask if you could show an example of storing/retrieving the generated key.

Also what happens is the encryption is executed creating a key, then a second instance is executed, will that over-ride the 1st instances key thus making anything encrypted by the 1st instance 'lost'?

--199.196.51.119 17:45, 23 January 2009 (UTC)


Sending the key

Hi, Thanks for posting wonderful explanation, as I am relatively new to this concept, I need some more information.

I need to send the key generated to the other user for him to decrypt the message. I would encrypt the key with his public key so that only he can decrypt it.

My problem is I am not able to understand how can Key's object be passed to him, i.e. please describe any way in which I can send him key object or something from which he can generate the same key in which the message is encrypted.

--114.143.51.7 04:45, 16 February 2009 (UTC)


Find out the key?

So it is a private key for both methods, right? Is this possible to find out the key if you know the message, encrypted message and the encrypt algorithm?

--123.24.155.116 17:50, 16 February 2009 (UTC)


Bob Zitelli said ...

DonGuilio, Thank you for posting this example. It is very helpful.

--Bob Zitelli 03:40, 18 May 2009 (PDT)


Robo

Hmmm, I've copied this class verbatim, but I just get an exception when I try to decrypt: "Input length must be multiple of 8 when decrypting with padded cipher"


--Robo 05:39, 17 August 2010 (PDT)


Title (required):

Website:

Comment: