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.

Thursday, June 13, 2013

Using ANTLR in your RCP

ANTLR is a parser generator widely used to create DSLs and all kinds of parsers for special purposes. In this tutorial I will show how to create a simple parser and how to implement it into an RCP.

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.

Prerequisites

We need some stuff from the ANTLR download page. Get Complete ANTLR 4.0 Java binaries jar and ANTLR 4.0 Java runtime binaries jar from there. The full package includes the build tool for grammars, the runtime binaries are needed to execute a parser in our RCP later on.

Step 1: Create a simple grammar

As this tutorial is not about ANTLR itself, but its integration into an RCP, we will use a very simple grammar to parse CSV files (actually just a single line of separated integers).

Currently there seems to be no eclipse support for ANTLRv4. To write grammars you could use ANTLRWorks 2 or write it directly in an editor of your choice.

Create a new Plug-in Project named com.example.antlr.parser. Afterwards create a grammar file CSV.g4 in the project root and add following content:
grammar CSV;

csv: NUMBER (DELIMITER NUMBER)*;

DELIMITER: ',';
NUMBER: DIGIT+;

fragment
DIGIT: [0-9];
Step 2: Compile grammar

To compile our grammar file we need the Complete ANTLR package we downloaded earlier and a simple script. As there is no native eclipse builder available, we will use an external build script.

Create a new folder build and copy antlr-4.0-complete.jar to it. Afterwards create a new file build.bat with following content:
"C:\Program Files\Java\jdk1.7.0_04\bin\java.exe" -cp antlr-4.0-complete.jar org.antlr.v4.Tool -visitor -package com.example.antlr.gen -o ..\src\com\example\antlr\gen\foo ..\CSV.g4

Extend this to your needs, port it to ANT or integrate it in a maven build (there seems to exist a maven target for ANTLRv4). It seems that the -o parameter needs some dummy folder name at the end. At least for me the very last path entry was skipped by the build tool.

You may launch this batch file from the External Tools located in the Run menu. The launcher is available in the source repository in the build folder.


Step 3: Add ANTLR runtime

The created files show lots of error markers because we have no runtime available yet. Create a new Plug-in from Existing JAR Archives and add antlr-runtime-4.0.jar to it. Name the project org.antlr.v4.runtime and add it as a dependency to com.example.antlr.parser.  All the error markers should be gone by now.

ANTLR comes with a BSD like license so you have to check if this fits to your application needs. According to this wiki entry it seems that it fits to EPL.

Step 4: Implement the parser

To run the parser we need 2 more classes. Lets start with com.example.antlr.CSVVisitor
package com.example.antlr;

import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

import org.antlr.v4.runtime.tree.RuleNode;
import org.antlr.v4.runtime.tree.TerminalNode;

import com.example.antlr.gen.CSVBaseVisitor;
import com.example.antlr.gen.CSVLexer;

public class CSVVisitor extends CSVBaseVisitor<List<Integer>> {

 @Override
 public List<Integer> visitChildren(RuleNode ctx) {
  List<Integer> numbers = new LinkedList<Integer>();
  for (int index = 0; index < ctx.getChildCount(); index++)
   numbers.addAll(visit(ctx.getChild(index)));

  return numbers;
 }

 @Override
 public List<Integer> visitTerminal(TerminalNode node) {

  if (node.getSymbol().getType() == CSVLexer.NUMBER) {
   int number = Integer.parseInt(node.getText());
   return Arrays.asList(number);
  }

  return Collections.emptyList();
 }
}
Now we can finally call the parser from com.example.antlr.CSVProcessor
package com.example.antlr;

import java.util.List;

import org.antlr.v4.runtime.ANTLRInputStream;
import org.antlr.v4.runtime.CommonTokenStream;

import com.example.antlr.gen.CSVLexer;
import com.example.antlr.gen.CSVParser;

public class CSVProcessor {

 public static List<Integer> parseCSV(final String data) {
  CSVLexer lexer = new CSVLexer(new ANTLRInputStream(data));
  CSVParser parser = new CSVParser(new CommonTokenStream(lexer));

  return parser.csv().accept(new CSVVisitor());
    }
 
 public static void main(String[] args) {
  List<Integer> numbers = parseCSV("2,45,66,123,24,6,7,7,8");
  System.out.println(numbers);
 }
}
If you need support on ANTLRv4 check out the webpage or - even better - support the project and buy the book.