Signing Java Objects for Secure Transfer

In distributed J2EE applications or in any application where you need to transfer Java objects to another system then there is always a security risk where the object can be intercepted which can result in data theft/loss. Especially in Serialization, (where the object is a physical file in the native file system) when the serialized Java objects are sent through the network, whoever knows the type of the object can always read it.

In this article, we will build two simple applications, one which generates the object, the keys (public & private) and signs the object with the private key. Other application which verifies the signed object in other end over the network or another application in the same machine. Both these apps can run independently in different machines. For signing the object we will be using Public-Key cryptography. This is one of the most widely used standards to sign data along with DSA & SHA1PRNG (cryptographically strong pseudo-random number generator (PRNG)). Public-Key cryptography is a asymmetric key algorithm, where the key used to encrypt a message is not the same as the key used to decrypt it.

This is the class diagram of the applications which we will be building. This article will be divided into two parts, the first part we will sign the object (serialized) and in the second part, we will verify it.

Sign the Java Object

First of all we need a class which will generate a public and private key. We will create a class named SecurityUtil which will generate those based on DSA (we can use RSA or any other algorithm as long as its available) and we will generate a cryptographically strong pseudo-random number generator (PRNG) which can be clubbed along with DSA (SHA1PRNG). The strength of the key will be 1024.

protected KeyPair generateKey () throws Exception {
    KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("DSA");
    SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
    keyPairGen.initialize(1024,secureRandom);
    KeyPair keyPair = keyPairGen.generateKeyPair();
    return keyPair;
}

Next we will create a class named EmployeeValueObject which is nothing but a POJO with a HashMap getter/setter. This will be the object which we will be transferring over the network/application. Since we serialize the object before transferring, this class should implement Serializable.

public class EmployeeValueObject implements Serializable {
    HashMap employeeSalary = new HashMap();
    public void setSalary (HashMap employeeSalary){
        this.employeeSalary = employeeSalary;
    }

    public HashMap getSalary () {
        return employeeSalary;
    }
}

Now we have all the supporting classes which we need and let’s start building the main application. Let’s call this class EmployeeDetails and this will create an object for the POJO which we created in our previous step and populate with some data. In addition to that, we will sign the POJO object and then serialize to a file. In this example we will be also serializing the public key to transfer to the other end. Note: In production implementations, both these objects shouldn’t be sent at the same time. The application at the other end should already have the public key)

Let’s create the POJO and populate with some data in the HashMap.

EmployeeValueObject employeeVO = new EmployeeValueObject();
employeeVO.setSalary(populateData());

private static HashMap populateData (){
    HashMap employeeSalary = new HashMap ();
    employeeSalary.put("3", "Johns, Galvin D. --> $18,000");
    employeeSalary.put("4", "Weber, Murphy I. --> $5,000");

    return employeeSalary;
}

Now let’s generate the public and private keys from SecutityUtil and sign the POJO which we created in the above step.

KeyPair keyPair = new SecurityUtil().generateKey();
PrivateKey privateKey = keyPair.getPrivate();
PublicKey publicKey = keyPair.getPublic();

Signature digitalSignature = Signature.getInstance(privateKey.getAlgorithm());
SignedObject digitalSignedObj =
    new SignedObject(employeeVO, privateKey, digitalSignature);

Now digitalSignedObj is a digitally signed data with the private key which we generated. Now let’s serialize this object for the secure transfer.

ileOutputStream serializedFileOutput = new FileOutputStream("employee.ser");
ObjectOutputStream serializedObjOutput = new ObjectOutputStream(serializedFileOutput);
serializedObjOutput.writeObject(digitalSignedObj);
serializedObjOutput.close();
serializedFileOutput.close();

We will also serialize the public key so that for this example we can send both of them to another machine to verify. Note: In production implementations, both these objects shouldn’t be sent at the same time. The application at the other end should already have the public key)

serializedFileOutput = new FileOutputStream("publickey.ser");
serializedObjOutput = new ObjectOutputStream(serializedFileOutput);
serializedObjOutput.writeObject(publicKey);
serializedObjOutput.close();
serializedFileOutput.close();

This will complete the creation of application one. When you run this application, it will create two new files in the same directory. employee.ser – which is the signed and serialized POJO (Salary details) & publickey.ser – public key to verify the POJO. Now using the appropriate protocol send these files to the other application (remote or local) and let’s start building the verification part.

Verification & De-Serializing the Java Object

As a start we have the files employee.ser & publickey.ser. Let’s start building up the class to verify and de-serialize these files. Let’s name this class DecryptEmployee. The following code should de-serialize the objects.

FileInputStream serializedPublicKeyIn = new FileInputStream("publicKey.ser");
ObjectInputStream serializedPublicKey = new ObjectInputStream(serializedPublicKeyIn);
PublicKey publicKey = (PublicKey) serializedPublicKey.readObject();

FileInputStream serializedEmployeeIn = new FileInputStream("employee.ser");
ObjectInputStream serializedEmployee = new ObjectInputStream(serializedEmployeeIn);
SignedObject digitalSignedObj = (SignedObject) serializedEmployee.readObject();

Since the public key was not signed, publicKey variable will be readable. But the employee POJO was signed, so we are reading the object as a SignedObject. Let’s move forward and verify this.

Signature digitalSignature = Signature.getInstance(publicKey.getAlgorithm());
boolean decryptFlag = digitalSignedObj.verify(publicKey, digitalSignature);

The decryptFlag contains the status of the verification. If the public key is incorrect or if the object was tampered, then this will return false and we won’t be able to verify the object. If its true then everything looks good and we can successfully verify the POJO and print the values from HashMap.

if(decryptFlag) {
    EmployeeValueObject employeeVO = (EmployeeValueObject) digitalSignedObj.getObject();
    HashMap employeeSalary = (HashMap) employeeVO.getSalary();
    Collection collHashMap = employeeSalary.values();
    Iterator collectionIterator = collHashMap.iterator();
    while (collectionIterator.hasNext()) {
        System.out.println(collectionIterator.next());
    }
} else {
    System.out.println ("Decryption Failed. Please check the Keys.");
}

If you run this application, we will get an output similar to below.

This can be used in any sensitive application to make sure that the objects which are transferred over the network are safe.

UPDATE: SignedObject signs the object, but it doesn’t encrypt it. So if you need encryption, you can use the Cipher class in Java.

Simple Proxy Server in Java

In this post, I am going to show how a simple Proxy server can be designed in Java which will provide the core functionalities of a proxy. From Wikipedia, “a proxy server is a server (a computer system or an application program) that acts as an intermediary for requests from clients seeking resources from other servers.“The proxy server generally has some resources, or has access to some resources and when it receives request from a client, it access the appropriate resource and sends back the response.

So it serves two purposes, giving access to a resource which the client do not have access and it hides the real client who needs the resource. The second part is used for the anonymous browsing in Internet using anonymous proxy servers. Although this may not be as “anonymous” as it sounds because the proxy server which you connect to can maintain logs about the clients who are connecting to the server, and also the bigger risk being the data theft. Since the “anonymous” proxy server has access to all the request you send, there is risk of that data being exposed unless there is some kind of encryption in place between the client and the proxy server.

If you are in a network, and the machine which you are using don’t have access to Internet but another machine in the same subnet has access to Internet, then you can run this proxy application in the machine which has Internet access and in your local machine, you can configure your web browser to use the IP and Port number of the machine where the proxy is running in the LAN/Network settings. Once done, you should be able to access the Internet. This is one of the practical use for proxy servers.

The proxy server which we will be designing will be a simple HTTP proxy which gets web requests based on HTTP protocol and sends back response in the same protocol. We will start by declaring some constants.

int proxyServerPortNumber = 7879;
int webServerPortNumber = 80;
String webServerIpAddress = "192.168.1.1";
final int PROXY_SERVER_TIME_OUT = 5000;
final int SOCKET_TIME_OUT = 2000;

proxyServerPortNumber defines the port where the proxy server will be listening. You can use any port number which is not used by other process / standard port.

webServerIpAddress and webServerPortNumber defines the IP/port where the server can access the resources. Since we are designing this to access websites over http, the port is defined as 80 and the IP should be a machine which has Internet access (can be localhost too)

PROXY_SERVER_TIME_OUT and SOCKET_TIME_OUT are standard parameters defined for Server and network socket timeout. You can adjust this based on your needs.

Now we need to start the Java class to bind to the port number defined and to run in a infinite loop or as a daemon thread, so that it keeps on listening for requests. In this example, we will be using the infinite loop.

try {
    serverSocket = new ServerSocket(proxyServerPortNumber);
} catch(Exception exc) {
        System.exit(0);
}

Now the process will be listening in the port 7879 for requests from clients. Now, let’s open an infinte loop and make a connection to the resource, in our case the web server.

socketProxy = new Socket(InetAddress.getByName(webServerIpAddress),webServerPortNumber);
socketProxy.setSoTimeout(PROXY_SERVER_TIME_OUT);
socket = serverSocket.accept();
socket.setSoTimeout(SOCKET_TIME_OUT);
inputStream = socket.getInputStream();

The request from the client will be received by Input Stream, so once we are connected, we will be sending this Input Stream which is nothing but a normal HTTP REQ object to the server which has the resource or as in our case the machine connected to Internet. The server will respond with the response which will be a HTTP RES over the Java Output Stream. We will be forwarding this output stream to the client which will be rendered in the application which the client requested in. That is if the request was sent through command line, the entire HTML will be printed, if its a browser the page will be rendered.

try {
    while( (intCounter = in.read()) != -1) {
        if(intCounter == -1) break;
        if(!bREQ)
            bREQ = true;
        pOutputStream.write(intCounter);
        if(byteCheckFl > 0) {
            break;
        }
        if(intCounter == 13 && intPrevCounter == 10)
            byteCheckFl++;
        intPrevCounter = intCounter;
    }
} catch(Exception e) {
    if(!bREQ) {
        continue;
    }
}

pOutputStream.flush();
pIutputStream = socketProxy.getInputStream();
outputStream = socket.getOutputStream();
try {
    while( (intCounter = pIutputStream.read()) != -1) {
        outputStream.write(intCounter);
    }
} catch(Exception e) {
}
outputStream.flush();

Make sure to close all the opened sockets and connections once the response is sent. Since this whole code is running in an infinite loop, the server will keep on waiting for the requests and sending the responses back. This is a crude implementation of the concept and there is room for a lot more improvements (like supporting SSL), but this should serve as a foundation to make the proxy a robust one.

We can easily make this Java class as a Win32 service, so that it will always run in background and starts along with the OS. That will need some work with JNI. I will explain that in a later post.