Tuesday, April 26, 2011

Java Cryptography Sample Code

Java Cryptography

Create cipher text on the Client side


We will use a property file to store some parameter values. The following is a sample property file:
#############  client.properties ##############

# type of keystore file
client.keystore.type = PKCS12

# location of keystore file on filesystem or in CLASSPATH
client.keystore.file = C:/foo.p12

# password for keystore
client.keystore.password = changeme

# alias for client's key
client.keystore.key.alias = foo

# password for private key
client.private.key.password = changeme

##########################################

  1. Use java keyStore to get the private key

    1. import java.security.KeyStore;
      import java.security.PrivateKey;
      import javax.crypto.Cipher;
      import javax.security.cert.X509Certificate;  
      
    2. Create a KeyStore object based on the KeyStore type (PKCS12 in this case):
      KeyStore clientKeyStore = KeyStore.getInstance( props.getProperty( CLIENT_KEYSTORE_TYPE ) );
    3. Load the keystore file:
      clientKeyStore.load( inputFile, props.getProperty( CLIENT_KEYSTORE_PASS_PROP ).toCharArray() );
      Here the input file is the file path and the name of the keystore file.
    4. Get the password for the keystore from the user property file:
      KeyStore.PasswordProtection keyPassword = new KeyStore.PasswordProtection( props.getProperty( CLIENT_PRIVATE_KEY_PASS_PROP ).toCharArray() );
    5. Get the PrivateKeyEntry using the keystore key alias and the key password:
      KeyStore.PrivateKeyEntry pkEntry = ( KeyStore.PrivateKeyEntry ) clientKeyStore.getEntry( props.getProperty( CLIENT_KEYSTORE_KEY_ALIAS_PROP ), keyPassword );
    6. Check to see if key is expired
      if( !X509Certificate.getInstance( pkEntry.getCertificate().getEncoded() ).getNotAfter().after( new Date() ) )
      {
      throw new Exception("The identity certificate has expired" );
      }
    7. Get the PrivateKey:
      return pkEntry.getPrivateKey(); 
      
      The above method returns an instance of PrivateKey.
  2. Use the PrivateKey to create a java Cipher:
    1. import javax.crypto.Cipher;
    2. Create a Cipher obect with some algorithm name as input:
      final Cipher cipher = Cipher.getInstance( "RSA/ECB/PKCS1Padding" );
    3. Initialize the cipher using the privateKey object:
      cipher.init( Cipher.ENCRYPT_MODE, getPrivateKey( clientId ) );
    4. Return the cipher:
      return cipher;
  3. Use the Cipher to generate the cipher text:
    1. import javax.crypto.Cipher;
      import sun.misc.BASE64Encoder;
    2. Use Cipher:
      final byte[] cipherBytes = cipher.doFinal( ( "some plain text" ).getBytes() );
    3. Use encoder:
      String cipherText = new BASE64Encoder().encode( cipherBytes );

Note that usually the public key is used to encrypt a message. But here it is different. The private key is used to generate the encrypted message. This is more like to sign a message using the private key.

Decipher on the Server Side

You can also have a property file for parameters used in the decipher.
  1. Use the client ID to get the Certificate of the client.
    Note that when the client sends the cipherText, he can append the plain text clientId to the cipherText using some fixed format so the server can parse the result string and get the plain text clientId from it.
       import javax.security.cert.Certificate;
       import javax.security.cert.X509Certificate;
       Certificate clientCert = getCertificate( clientId );
    
    Here the method getCertificate() is just a method you implement. For example, you can save the certificates in LDAP and retrieve them from there.
  2. Use the Certificate to get the Public key and the Cipher
            Cipher cipher = Cipher.getInstance( "RSA" );
            cipher.init( Cipher.DECRYPT_MODE, clientCert.getPublicKey() );
    
  3. Use the Cipher to decode the cipherText.
    byte[] results = cipher.doFinal( new BASE64Decoder().decodeBuffer( cipherText ) ) );
Note that the key can be loaded as a file. The following is a sample.
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.ObjectInputStream;

...

private void test(){
  ...
  InputStream is = new FileInputStream(new File("C:/temp/xyz.ser"));  
  ObjectInputStream objectinputstream = new ObjectInputStream(is);
  Key key = (Key) objectinputstream.readObject();

  if (objectinputstream != null)
    objectinputstream.close();
  cipher.init(Cipher.DECRYPT_MODE, key);
  ...
}

The file xyz.ser is the key. As an example, on linux the command "file xyz.ser" gives the following output: xyz.ser: Java serialization data, version 5

The following is a sample class that encrypts and then decrypts some text.

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.Date;

import javax.crypto.Cipher;
import javax.security.cert.X509Certificate;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

public class Cryptography {
 private String CLIENT_KEYSTORE_TYPE = "PKCS12";
 private String inputFile = "path/to/your/keyfile.p12";
 private String CLIENT_KEYSTORE_PASSWORD = "yourpassword";
 private String CLIENT_PRIVATE_KEY_PASSWORD = "yourpassword";
 private String CLIENT_KEYSTORE_KEY_ALIAS = "yourAlias";

 private KeyStore.PrivateKeyEntry getKeyEntry() throws Exception {
  KeyStore clientKeyStore = KeyStore.getInstance(CLIENT_KEYSTORE_TYPE);
  InputStream is = new FileInputStream(new File(inputFile));
  clientKeyStore.load(is, CLIENT_KEYSTORE_PASSWORD.toCharArray());
  KeyStore.PasswordProtection keyPassword = new KeyStore.PasswordProtection(
    CLIENT_PRIVATE_KEY_PASSWORD.toCharArray());
  KeyStore.PrivateKeyEntry pkEntry = (KeyStore.PrivateKeyEntry) clientKeyStore
    .getEntry(CLIENT_KEYSTORE_KEY_ALIAS, keyPassword);
  if (!X509Certificate.getInstance(pkEntry.getCertificate().getEncoded())
    .getNotAfter().after(new Date())) {
   throw new Exception("The identity certificate has expired");
  }
  return pkEntry;
 }

 private PrivateKey getPrivateKey() throws Exception {
  return getKeyEntry().getPrivateKey();
 }

 private PublicKey getPublicKey() throws Exception {
  return getKeyEntry().getCertificate().getPublicKey();
 }

 public String encrypt(String text) throws Exception {
  final Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
  cipher.init(Cipher.ENCRYPT_MODE, getPrivateKey());
  final byte[] cipherBytes = cipher.doFinal(text.getBytes());
  String cipherText = new BASE64Encoder().encode(cipherBytes);
  return cipherText;
 }

 public String decrypt(String cipherText) throws Exception {
  Cipher cipher = Cipher.getInstance("RSA");
  cipher.init(Cipher.DECRYPT_MODE, getPublicKey());
  byte[] results = cipher.doFinal(new BASE64Decoder()
    .decodeBuffer(cipherText));
  return new String(results);
 }

 public void test() throws Exception {
  String text = "hello world";
  String encryptedText = encrypt("test " + text);
  System.out.println("EncryptedText is: " + encryptedText);
  String decryptedText = decrypt(encryptedText);
  System.out.println("Result is: " + decryptedText);
 }

 public static void main(String[] args) {
  Cryptography p = new Cryptography();
  try {
   p.test();
  } catch (Exception e) {
   e.printStackTrace();
  }
 }
}

No comments:

Post a Comment