Warning: Parameter 1 to Language::getMagic() expected to be a reference, value given in /home/wikija5/public_html/w/includes/StubObject.php on line 58
Secret Key Cryptography Tutorial - WikiJava
Tuesday, 21st October 2014
Follow WikiJava on twitter now. @Wikijava

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.

There's an update to this article, with some refactorings and the important improvement for handling user typed passwords. This is the new article: Secret key cryptography.

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)

Using Predefined Key

Nice experiment. This might be helpful to some - to further the experiment, I found I could use a given key (therefore it's reusable) with the following code to get the key instead of your generateKey() method.

//your key info, get them from wherever they're stored String key = "7777777777777777";//must be 16 long String iv = "8888888888888888";//must be 16 long

           SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(), "DES");
           IvParameterSpec ivSpec = new IvParameterSpec(iv.getBytes());

Then, doing it this way, you have to add the iv to the cipher init call

eg. cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);

The rest is the same. I also used AES for the SecretKeySpec and AES/CBC/PKCS5Padding for the algorithm.


--Using Predefined Key 15:20, 7 April 2011 (PDT)


Interesting about the reusable keys.

Hi,

This is a wiki, and what you just mentioned is very interesting, why don't you post your code and make a full article with it? I would be real interested in seeing it.

Thanks,


---DonGiulio 11:56, 8 April 2011 (UTC)


AES

code... code with nice secret key stuff

--AES 19:58, 14 April 2011 (PDT)


Made new article out of your comment

Hi,

Thanks for posting your code, I took it away to give it more space on a new article, here: Secret key cryptography.

I also took the occasion to review and reorganize the code copy pasted from this article so that it's more readable.

Please pass me your name, so I can refer you as author too. Thanks,


---DonGiulio 09:19, 15 April 2011 (UTC) 11:56, 8 April 2011 (UTC)

Thanks for new article!

Hi Don! Thanks for creating a new article for this and moving my code snippets to a new spot. Looks great, I just checked it against my demo JSP and everything matches up. In fact I think I'll make a login and add my JSP code up here as well next.

I actually tried to comment there first but it wouldn't let me saying it's not accepting comments.

Something people might want to know is that there is a very handy Java library called Jasypt ( http://www.jasypt.org/ ) that helps you do these sorts of things, symmetrical encryption and decryption, as well as hashing and hash checking like for passwords. It makes things a little easier, however you should still know how things work. Jasypt has good default behavior but can't prevent someone from making security mistakes. I've used it and it was fairly easy to adjust to, especially with the much reduced code required to use it! Once you have the above example code running and you understand it, something like Jasypt is a good next step.

By the way, my name is Michael Katich. I did not post the "AES" comment in the related Tutorial page but I was the one with the "Using Predefined Key" post.

--Thanks for new article! 12:25, 17 May 2011 (PDT)


Thank you for Sharing with Us ..

< AwSM! />

--Thank you for Sharing with Us .. 04:26, 21 June 2011 (PDT)


Thank you

Very helpful article

--Thank you 05:09, 1 August 2011 (PDT)


JohnBush

Hello! Very good job(this site)! Thank you man.

--JohnBush 13:29, 3 August 2011 (PDT) Very nice site!

Very nice site!

--Very nice site! 06:45, 3 September 2011 (PDT)


Comments on wikijava are disabled now, cause excessive spam.