Wednesday, June 26, 2013

Writing your own JCA extensions - a simple digest

When dealing with cryptographic algorithms in Java you should use the Java Cryptography Architecture (JCA). It is part of Java SE and provides support for several different algorithms like DES or AES. Even more algorithms are supported by BouncyCastle.

But what if you need to implement your own digest or cipher? JCE allows to add your own cryptographic provider to the framework, which is what we will do in this tutorial.

Source code for this tutorial is available on googlecode as a single zip archive, as a Team Project Set or you can checkout the SVN projects directly.

Step 1: Create a digest implementation

We will implement a simple digest that will XOR all bytes of a message and therefore return a 1 byte checksum.

Start by creating a new Java Project named com.example.jce.provider. To implement a digest we need to extend MessageDigestSpi. Implement com.example.jce.provider.XORDigest as follows:
package com.example.jce.provider;

import java.security.MessageDigestSpi;

public class XORDigest extends MessageDigestSpi {

 private byte mChecksum = 0;

 public XORDigest() {
 }

 @Override
 protected void engineUpdate(byte input) {
  mChecksum ^= input;
 }

 @Override
 protected void engineUpdate(byte[] input, int offset, int len) {
  for (int index = offset; index < offset + len; index++)
   engineUpdate(input[index]);
 }

 @Override
 protected byte[] engineDigest() {
  return new byte[] { mChecksum };
 }

 @Override
 protected void engineReset() {
  mChecksum = 0;
 }
}
Step 2: Create a JCE provider

To register our digest in the JRE we need to use a provider. This provider is used by the JCE as an entry point to locate our Digest class. Create a new class com.example.jce.provider.CryptoProvider:
package com.example.jce.provider;

import java.security.Provider;

public class CryptoProvider extends Provider {

 private static final long serialVersionUID = -67123468605911408L;

 public CryptoProvider() {
  super("SimpleCrypto", 1.0, "XOR digest v1.0");

  put("MessageDigest.XOR", XORDigest.class.getName());
 }
}
Finally we need to register this provider in our runtime. There are several ways to do this, here we will use the dynamic approach as we do not want to alter our JRE install folder. Registration is handled by the Security class:
Security.addProvider(new CryptoProvider());

Step 3: Using our provider

Lets see our provider in action:
 public static void main(String[] args) {

  Security.addProvider(new CryptoProvider());

  try {
   MessageDigest digest = MessageDigest.getInstance("XOR");
   byte[] checksum = digest.digest(new byte[] { 0x01, 0x23, 0x45 });
   System.out.println("Checksum: 0x" + Integer.toHexString(checksum[0]));

  } catch (NoSuchAlgorithmException e) {
   e.printStackTrace();
  }
 }
First we are registering our provider as explained in step 2. Afterwards we create a new digest and feed some data to it. The checksum you get should be 0x67.

1 comment: