Monday, August 22, 2016

RESTful Web Services in Java

Read about REST here...
In the example program REST is implemented using Jersey Framework.
Download Jersey framework from here...
I used Dynamic Web Project in Eclipse for coding. Extract jersey zip file and copy all the .jar files from api, ext, lib folders to WebContent/WEB-INF/lib folder.

Employee.java
 
package in.theinsanetechie.rest;

import java.io.Serializable;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name = "employee")
public class Employee implements Serializable {

 private static final long serialVersionUID = 1L;
 private int empcode;
 private String name;
 private String designation;
 private float basicpay;
 
 public Employee() {  
 }
 
 public Employee(int empcode, String name, String designation, float basicpay) {
  super();
  this.empcode = empcode;
  this.name = name;
  this.designation = designation;
  this.basicpay = basicpay;
 }

 public int getEmpcode() {
  return empcode;
 }
 
 @XmlElement
 public void setEmpcode(int empcode) {
  this.empcode = empcode;
 }
 
 public String getName() {
  return name;
 }
 
 @XmlElement
 public void setName(String name) {
  this.name = name;
 }
 
 public String getDesignation() {
  return designation;
 }
 
 @XmlElement
 public void setDesignation(String designation) {
  this.designation = designation;
 }
 
 public float getBasicpay() {
  return basicpay;
 }
 
 @XmlElement
 public void setBasicpay(float basicpay) {
  this.basicpay = basicpay;
 }

 @Override
 public boolean equals(Object obj) {
  if (this == obj)
   return true;
  if (obj == null)
   return false;
  if (getClass() != obj.getClass())
   return false;
  Employee other = (Employee) obj;
  if (Float.floatToIntBits(basicpay) != Float
    .floatToIntBits(other.basicpay))
   return false;
  if (designation == null) {
   if (other.designation != null)
    return false;
  } else if (!designation.equals(other.designation))
   return false;
  if (empcode != other.empcode)
   return false;
  if (name == null) {
   if (other.name != null)
    return false;
  } else if (!name.equals(other.name))
   return false;
  return true;
 }

}


EmployeeAccessObject.java
 
package in.theinsanetechie.rest;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.List;

public class EmployeeAccessObject {

 private String fileName = "Employee.dat";
 
 @SuppressWarnings("unchecked")
 public List getFullList() {
  List list = null;
  File file = new File(fileName);
  try {
   if (file.exists()) {
    FileInputStream fileInputStream = new FileInputStream(file);
    ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
    list = (List) objectInputStream.readObject();
    objectInputStream.close();
   } else{
    Employee employee = new Employee(1001, "The Insane Techie", "Dev", 99999.99f);
    list = new ArrayList();
    list.add(employee);
    saveList(list);
   }
   
  } catch (FileNotFoundException e) {
   e.printStackTrace();
  } catch (IOException e) {
   e.printStackTrace();
  } catch (ClassNotFoundException e) {
   e.printStackTrace();
  }
  
  return list;
 }
 
 public Employee get(int empcode) {
  List list = getFullList();
  
  for (Employee temp : list) {
   if (temp.getEmpcode() == empcode) {
    return temp;
   }
  }
  
  return null;
 }
 
 public boolean addToList(Employee emp){
  List list = getFullList();
  boolean exists = false;
  for(Employee temp: list){
   if(temp.getEmpcode() == emp.getEmpcode()){
    exists = true;
    break;
   }
  }  
  if(!exists){
   list.add(emp);
   saveList(list);
   return true;
  }
  return false;
 }
 
 public boolean updateList(Employee emp){
  List list = getFullList();
  for(Employee temp: list){
   if(temp.getEmpcode() == emp.getEmpcode()){
    int index = list.indexOf(temp);   
    list.set(index, emp);
    saveList(list);
    return true;
   }
  }  
  return false;
 }

 public boolean deleteFromList(int empcode){
  List list = getFullList();

  for(Employee temp: list){
   if(temp.getEmpcode() == empcode){
    int index = list.indexOf(temp);   
    list.remove(index);
    saveList(list);
    return true;   
   }
  }  
  return false;
 }
 
 private void saveList(List list) {
  
  File file = new File(fileName);
  try {
   FileOutputStream fileOutputStream = new FileOutputStream(file);
   ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
   objectOutputStream.writeObject(list);
   objectOutputStream.close();
  } catch (FileNotFoundException e) {
   e.printStackTrace();
  } catch (IOException e) {
   e.printStackTrace();
  }
  
 }
}


EmployeeService.java
 
package in.theinsanetechie.rest;

import java.io.IOException;
import java.util.List;

import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.OPTIONS;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;

@Path("/EmployeeService")
public class EmployeeService {

 EmployeeAccessObject accessObject = new EmployeeAccessObject();
 private static final String SUCCESS = "success";
 private static final String FAILURE = "failure";


 @GET
 @Path("/employees")
 @Produces(MediaType.APPLICATION_XML)
 public List getFullList(){
  return accessObject.getFullList();
 }

 @GET
 @Path("/employees/{empcode}")
 @Produces(MediaType.APPLICATION_XML)
 public Employee get(@PathParam("empcode") int empcode){
  return accessObject.get(empcode);
 }

 @PUT
 @Path("/employees")
 @Produces(MediaType.APPLICATION_XML)
 @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
 public String add(@FormParam("empcode") int empcode,
   @FormParam("name") String name,
   @FormParam("designation") String designation,
   @FormParam("basicpay") float basicpay,
   @Context HttpServletResponse servletResponse) throws IOException{
  Employee emp = new Employee(empcode, name, designation, basicpay);
  boolean result = accessObject.addToList(emp);
  if(result == true){
   return SUCCESS;
  }
  return FAILURE;
 }

 @POST
 @Path("/employees")
 @Produces(MediaType.APPLICATION_XML)
 @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
 public String update(@FormParam("empcode") int empcode,
   @FormParam("name") String name,
   @FormParam("designation") String designation,
   @FormParam("basicpay") float basicpay,
   @Context HttpServletResponse servletResponse) throws IOException{
  Employee emp = new Employee(empcode, name, designation, basicpay);
  boolean result = accessObject.updateList(emp);
  if(result == true){
   return SUCCESS;
  }
  return FAILURE;
 }

 @DELETE
 @Path("/employees/{empcode}")
 @Produces(MediaType.APPLICATION_XML)
 public String deleteUser(@PathParam("empcode") int empcode){
  boolean result = accessObject.deleteFromList(empcode);
  if(result == true){
   return SUCCESS;
  }
  return FAILURE;
 }

 @OPTIONS
 @Path("/employees")
 @Produces(MediaType.APPLICATION_XML)
 public String getSupportedOperations(){
  return "GET, PUT, POST, DELETE";
 }
}


WebServiceTester.java
 
package in.theinsanetechie.rest;

import java.util.List;

import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.Form;
import javax.ws.rs.core.GenericType;
import javax.ws.rs.core.MediaType;

public class WebServiceTester  {

 private Client client;
 private String REST_SERVICE_URL = "http://localhost:8080/EmployeeManagement/rest/EmployeeService/employees";
 private static final String SUCCESS="success";
 private static final String PASS = "pass";
 private static final String FAIL = "fail";

 private void init(){
  this.client = ClientBuilder.newClient();
 }

 public static void main(String[] args){
  
  WebServiceTester tester = new WebServiceTester();  
  tester.init();
  tester.testGetFullList();
  tester.testGet();
  tester.testUpdate();
  tester.testAdd();
  tester.testDelete();
 }
 
 private void testGetFullList(){
  GenericType> list = new GenericType>() {};
  List employees = client
    .target(REST_SERVICE_URL)
    .request(MediaType.APPLICATION_XML)
    .get(list);
  String result = PASS;
  if(employees.isEmpty()){
   result = FAIL;
  }
  System.out.println("Test case name: testGetFullList, Result: " + result );
 }

 private void testGet(){
  Employee sampleEmp = new Employee();
  sampleEmp.setEmpcode(1001);

  Employee emp = client
    .target(REST_SERVICE_URL)
    .path("/{empcode}")
    .resolveTemplate("empcode", 1001)
    .request(MediaType.APPLICATION_XML)
    .get(Employee.class);
  String result = FAIL;
  if(sampleEmp != null && sampleEmp.getEmpcode() == emp.getEmpcode()){
   result = PASS;
  }
  System.out.println("Test case name: testGet, Result: " + result );
 }

 private void testUpdate(){
  Form form = new Form();
  form.param("empcode", "1001");
  form.param("name", "Dhanoop Bhaskar");
  form.param("designation", "Computer Scientist");
  form.param("basicpay", "100000.00f");

  String callResult = client
    .target(REST_SERVICE_URL)
    .request(MediaType.APPLICATION_XML)
    .post(Entity.entity(form,
      MediaType.APPLICATION_FORM_URLENCODED_TYPE),
      String.class);
  String result = PASS;
  if(!SUCCESS.equals(callResult)){
   result = FAIL;
  }

  System.out.println("Test case name: testUpdate, Result: " + result );
 }
 
 private void testAdd(){
  Form form = new Form();
  form.param("empcode", "1002");
  form.param("name", "The Insane Techie");
  form.param("designation", "Computer Scientist");
  form.param("basicpay", "100000.00f");

  String callResult = client
    .target(REST_SERVICE_URL)
    .request(MediaType.APPLICATION_XML)
    .put(Entity.entity(form,
      MediaType.APPLICATION_FORM_URLENCODED_TYPE),
      String.class);

  String result = PASS;
  if(!SUCCESS.equals(callResult)){
   result = FAIL;
  }

  System.out.println("Test case name: testAdd, Result: " + result );
 }
 
 private void testDelete(){
  String callResult = client
    .target(REST_SERVICE_URL)
    .path("/{empcode}")
    .resolveTemplate("empcode", 1002)
    .request(MediaType.APPLICATION_XML)
    .delete(String.class);

  String result = PASS;
  if(!SUCCESS.equals(callResult)){
   result = FAIL;
  }

  System.out.println("Test case name: testDelete, Result: " + result );
 }
}


web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://java.sun.com/xml/ns/javaee"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
    http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
    id="WebApp_ID" version="3.0">
    <display-name>Employee Management</display-name>
    <servlet>
        <servlet-name>Jersey RESTful Application</servlet-name>
        <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
            <init-param>
                <param-name>jersey.config.server.provider.packages</param-name>
                <param-value>in.theinsanetechie.rest</param-value>
            </init-param>
        </servlet>
    <servlet-mapping>
    <servlet-name>Jersey RESTful Application</servlet-name>
        <url-pattern>/rest/*</url-pattern>
    </servlet-mapping>
</web-app>

Tuesday, June 14, 2016

The Insane Techie - Android App



Launched an android app for the blog on 07th June 2016.

Get it from google play store...

Tips for using the app
  • Use in landscape mode while viewing the code snippets.
  • For convenience, I have added major categories as separate feeds in the app (as an update on 08th June 2016).
  • Use Help section for updates about the app.
Thanks :)

Wednesday, March 9, 2016

Installing and Configuring phpMyAdmin in Ubuntu/Linux Mint


Install phpmyadmin
sudo apt-get install phpmyadmin

Configure phpmyadmin
sudo dpkg-reconfigure -plow phpmyadmin

Then select Apache 2 for the webserver you wish to configure.

Try hitting the URL http://localhost/phpmyadmin/

If this does not work, then you have to include the phpMyAdmin-shipped Apache configuration into Apache:

sudo ln -s /etc/phpmyadmin/apache.conf /etc/apache2/conf.d/phpmyadmin.conf
sudo /etc/init.d/apache2 reload

Since Ubuntu 13.10 (Saucy Salamander), Apache no longer loads configuration files from the /etc/apache2/conf.d directory.
Instead, they are placed in the /etc/apache2/conf-available directory which is managed with the a2enconf command.
Therefore, if you need to manually include the phpMyAdmin-shipped Apache configuration file, you must run the following:

sudo ln -s /etc/phpmyadmin/apache.conf /etc/apache2/conf-available/phpmyadmin.conf
sudo a2enconf phpmyadmin
sudo /etc/init.d/apache2 reload

Sunday, February 14, 2016

DNS Lookup - Implementation in C


Read about DNS here...

DNS Lookup - Implementation in C
 
/**dnsclient.c**/
#include"stdio.h"  
#include"stdlib.h"  
#include"sys/types.h"  
#include"sys/socket.h"  
#include"string.h"  
#include"netinet/in.h"  
#include"netdb.h"
#include"arpa/inet.h"
  
#define BUF_SIZE 512
#define SERVER "8.8.8.8"
#define PORT 53
#define WIDTH 16
  
int createSocket();
void createRequest(char * url);
void hexdump (char *desc, void *addr, int len);
void lookUp();

struct query {
	uint16_t length;
	char * url;
	unsigned char request[BUF_SIZE];
	uint16_t reqType;
};

struct query dnsQuery = {
				.length = 12,
				.url = "",
				.reqType = 0x01,
				.request = { 0xDB, 0x42, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
			};

int main(int argc, char** argv) {
	char * url;

	if (argc != 2) {
		fprintf(stderr,"usage: %s hostnameToResolve\n", argv[0]);
		exit(1);
	}

	url = argv[1];
		
	createRequest(url);
	lookUp();
}



int createSocket() {
	int sockfd;

	sockfd = socket(AF_INET, SOCK_DGRAM, 0);
	if (sockfd < 0) {  
		printf("Error creating socket!\n");  
		exit(1);  
	}  
	//printf("Socket created...\n");

	return sockfd;
}

void createRequest(char * url) {
	char * word;
	int i;	
	printf("Asking DNS server %s about %s\n", SERVER, url);
	dnsQuery.url = strdup(url);
	dnsQuery.reqType = 0x01;

	word = strtok(url, ".");
	while (word) {
		printf("parsing hostname: \"%s\" is %d characters\n", word, strlen(word));
		dnsQuery.request[dnsQuery.length++] = strlen(word);
		for (i = 0; i < strlen(word); i++) {
			dnsQuery.request[dnsQuery.length++] = word[i];
		}
		word = strtok(NULL, ".");
	}

	dnsQuery.request[dnsQuery.length++] = 0x00; // End of the host name
	dnsQuery.request[dnsQuery.length++] = 0x00; // 0x0001 - Query is a Type A query (host address)
	dnsQuery.request[dnsQuery.length++] = dnsQuery.reqType;
	dnsQuery.request[dnsQuery.length++] = 0x00; // 0x0001 - Query is class IN (Internet address)
	dnsQuery.request[dnsQuery.length++] = 0x01;
}


// http://stackoverflow.com/questions/7775991/how-to-get-hexdump-of-a-structure-data
void hexdump (char *desc, void *addr, int len) {
    int i;
    unsigned char buff[17];
    unsigned char *pc = addr;

    // Output description if given.
    if (desc != NULL)
        printf ("%s:\n", desc);

    // Process every byte in the data.
    for (i = 0; i < len; i++) {
        // Multiple of 16 means new line (with line offset).

        if ((i % 16) == 0) {
            // Just don't print ASCII for the zeroth line.
            if (i != 0)
                printf ("  %s\n", buff);

            // Output the offset.
            printf ("  %04x ", i);
        }

        // Now the hex code for the specific character.
        printf (" %02x", pc[i]);

        // And store a printable ASCII character for later.
        if ((pc[i] < 0x20) || (pc[i] > 0x7e))
            buff[i % 16] = '.';
        else
            buff[i % 16] = pc[i];
        buff[(i % 16) + 1] = '\0';
    }

    // Pad out last line if not exactly 16 characters.
    while ((i % 16) != 0) {
        printf ("   ");
        i++;
    }

    // And print the final ASCII bit.
    printf ("  %s\n", buff);
}


void lookUp() {
	struct sockaddr_in addr;
	int socket;
	int ret, rcode, size, i;
	int ip = 0, dom = 0;
	int length;
	unsigned char buffer[BUF_SIZE];
	unsigned char tempBuf[3];
	uint16_t QDCOUNT; //No. of items in Question Section
	uint16_t ANCOUNT; //No. of items in Answer Section
	uint16_t NSCOUNT; //No. of items in Authority Section
	uint16_t ARCOUNT; //No. of items in Additional Section
	uint16_t QCLASS; //Specifies the class of the query
	uint16_t ATYPE; //Specifies the meaning of the data in the RDATA field
	uint16_t ACLASS; //Specifies the class of the data in the RDATA field
	uint32_t TTL; //The number of seconds the results can be cached
	uint16_t RDLENGTH; //The length of the RDATA field
	uint16_t MSGID;

	socket = createSocket();

	memset(&addr, 0, sizeof(addr));  
	addr.sin_family = AF_INET;  
	addr.sin_addr.s_addr = inet_addr(SERVER);
	addr.sin_port = htons(PORT);
	size = sizeof(addr);

	hexdump("sending packet", &dnsQuery.request, dnsQuery.length);
	ret = sendto(socket, dnsQuery.request, dnsQuery.length, 0, (struct sockaddr*)&addr, size);
	if (ret < 0) {
		printf("Error Sending Request");
		exit(1);		
	}
	//printf("Sent\n");

	memset(&buffer, 0, BUF_SIZE);
	ret = recvfrom(socket, buffer, BUF_SIZE, 0, (struct sockaddr*)&addr, &size);
	if (ret < 0) {
		printf("Error Receiving Response");
		exit(1);
	}	
		
	hexdump("received packet", &buffer, ret);

	close(socket);

	rcode = (buffer[3] & 0x0F);

	//tempBuf[0] = buffer[4];
	//tempBuf[1] = buffer[5];
	//tempBuf[2] = '\0';
	
	//printf("%0x %0x %0x %0x\n", buffer[4], buffer[5], tempBuf[0], tempBuf[1]);

	//QDCOUNT = (uint16_t) strtol(tempBuf, NULL, 16);
	QDCOUNT = (uint16_t)  buffer[4] * 0x100 + buffer[5];
	printf("entries in question section: %u\n", QDCOUNT);
	ANCOUNT = (uint16_t)  buffer[6] * 0x100 + buffer[7];
	printf("records in answer section: %u\n", ANCOUNT);
	NSCOUNT = (uint16_t)  buffer[8] * 0x100 + buffer[9];
	printf("name server resource record count: %u\n", NSCOUNT);
	ARCOUNT = (uint16_t)  buffer[10] * 0x100 + buffer[11];
	printf("additional records count: %u\n", ARCOUNT);

	printf("query type: %u\n", dnsQuery.reqType);
	QCLASS = (uint16_t) dnsQuery.request[dnsQuery.length - 2] * 0x100 + dnsQuery.request[dnsQuery.length - 1];
	printf("query class: %u\n", QCLASS);
	length = dnsQuery.length + 1;	 // to skip 0xc00c
	ATYPE = (uint16_t) buffer[length + 1] * 0x100 + buffer[length + 2];
	printf("answer type: %u\n", ATYPE);
	ACLASS = (uint16_t) buffer[length + 3] * 0x100 + buffer[length + 4];
	printf("answer class: %u\n", ACLASS);
	TTL = (uint32_t) buffer[length + 5] * 0x1000000 + buffer[length + 6] * 0x10000 + buffer[length + 7] * 0x100 + buffer[length + 8];
	printf("seconds to cache: %u\n", TTL);
	RDLENGTH = (uint16_t) buffer[length + 9] * 0x100 + buffer[length + 10];
	printf("bytes in answer: %u\n", RDLENGTH);
	MSGID = (uint16_t) buffer[0] * 0x100 + buffer[1];
	printf("answer msg id: %u\n", MSGID);	
	
	

	if (rcode == 2) {
		printf("nameserver %s returned SERVFAIL:\n", SERVER);
		printf("  the name server was unable to process this query due to a\n  problem with the name server.\n");
		exit(1);
	} else if (rcode == 3) {
		printf("nameserver %s returned NXDOMAIN for %s:\n", SERVER, dnsQuery.url);
		printf("  the domain name referenced in the query does not exist\n");
		exit(1);
	}

  	/* search for and print IPv4 addresses */
	if (dnsQuery.reqType == 0x01) {
		printf("DNS server's answer is: (type#=%u):", ATYPE);
		//printf("IPv4 address(es) for %s:\n", dnsQuery.url);
		for (i = 0 ; i < ret ; i++) {
			if (buffer[i] == 0xC0 && buffer[i+3] == 0x01) {
				ip++; i += 12; /* ! += buf[i+1]; */
				printf(" %u.%u.%u.%u\n", buffer[i], buffer[i+1], buffer[i+2], buffer[i+3]);
			}
		}

		if (!ip) {
			printf("  No IPv4 address found in the DNS response!\n");
			exit(1);
		}
  	}
}


Output

dhanoopbhaskar@dhanoop-laptop:~/workspace/Copy/_works$ gcc dnsclient.c 
dhanoopbhaskar@dhanoop-laptop:~/workspace/Copy/_works$ ./a.out www.theinsanetechie.in
Asking DNS server 8.8.8.8 about www.theinsanetechie.in
parsing hostname: "www" is 3 characters
parsing hostname: "theinsanetechie" is 15 characters
parsing hostname: "in" is 2 characters
sending packet:
  0000  db 42 01 00 00 01 00 00 00 00 00 00 03 77 77 77  .B...........www
  0010  0f 74 68 65 69 6e 73 61 6e 65 74 65 63 68 69 65  .theinsanetechie
  0020  02 69 6e 00 00 01 00 01                          .in.....
received packet:
  0000  db 42 81 80 00 01 00 03 00 00 00 00 03 77 77 77  .B...........www
  0010  0f 74 68 65 69 6e 73 61 6e 65 74 65 63 68 69 65  .theinsanetechie
  0020  02 69 6e 00 00 01 00 01 c0 0c 00 05 00 01 00 00  .in.............
  0030  32 c7 00 10 03 67 68 73 06 67 6f 6f 67 6c 65 03  2....ghs.google.
  0040  63 6f 6d 00 c0 34 00 05 00 01 00 00 54 5f 00 08  com..4......T_..
  0050  03 67 68 73 01 6c c0 38 c0 50 00 01 00 01 00 00  .ghs.l.8.P......
  0060  01 2b 00 04 4a 7d 44 79                          .+..J}Dy
entries in question section: 1
records in answer section: 3
name server resource record count: 0
additional records count: 0
query type: 1
query class: 1
answer type: 5
answer class: 1
seconds to cache: 12999
bytes in answer: 16
answer msg id: 56130
DNS server's answer is: (type#=5): 74.125.68.121

dhanoopbhaskar@dhanoop-laptop:~/workspace/Copy/_works$ 

Thursday, January 7, 2016

Renewed IEEE membership :)

 

Wednesday, March 11, 2015

Java program to find the distance between two GPS locations.

Location.java
 
package com.cables.gps;

public class Location {
 private int latDegree;
 private int latMinutes;
 private int latSeconds;
 private char latDirection;
 private int longDegree;
 private int longMinutes;
 private int longSeconds;
 private char longDirection;
 
 private float latitude;
 private float longitude;
 
 private void init() throws Exception {
  latitude = latDegree + (latMinutes / 60.0f) + (latSeconds / 3600.0f);
  if (latDirection == 'N') {
   latitude *= 1f;
  } else if (latDirection == 'S'){
   latitude *= -1f;
  } else {
   throw new Exception("Invalid Latitude Direction: " + latDirection);
  }
  longitude = longDegree + (longMinutes / 60.0f) + (longSeconds / 3600.0f);
  if (longDirection == 'E') {
   longitude *= 1f;
  } else if (longDirection == 'W') {
   longitude *= -1f;
  } else {
   throw new Exception("Invalid Longitude Direction: " + longDirection);
  }
 }
 
 public String toString() {
  String returnString = "";
  try {
   init();
  } catch (Exception e) {   
   e.printStackTrace();
   return null;
  }
  returnString += "(" + latitude + ", " + longitude + ")";
  return returnString;
 }
 
 public void setLatitude(int deg, int min, int sec, char dir) {
  latDegree = deg;
  latMinutes = min;
  latSeconds = sec;
  latDirection = dir;
 }
 
 public void setLongitude(int deg, int min, int sec, char dir) {
  longDegree = deg;
  longMinutes = min;
  longSeconds = sec;
  longDirection = dir;
 }

 public int getLatDegree() {
  return latDegree;
 }

 public void setLatDegree(int latDegree) {
  this.latDegree = latDegree;
 }

 public int getLatMinutes() {
  return latMinutes;
 }

 public void setLatMinutes(int latMinutes) {
  this.latMinutes = latMinutes;
 }

 public int getLatSeconds() {
  return latSeconds;
 }

 public void setLatSeconds(int latSeconds) {
  this.latSeconds = latSeconds;
 }

 public char getLatDirection() {
  return latDirection;
 }

 public void setLatDirection(char latDirection) throws Exception {
  if (latDirection != 'N' && latDirection != 'S') {
   throw new Exception("Invalid Latitude Direction: " + latDirection);   
  }
  this.latDirection = latDirection;
 }

 public int getLongDegree() {
  return longDegree;
 }

 public void setLongDegree(int longDegree) {
  this.longDegree = longDegree;
 }

 public int getLongMinutes() {
  return longMinutes;
 }

 public void setLongMinutes(int longMinutes) {
  this.longMinutes = longMinutes;
 }

 public int getLongSeconds() {
  return longSeconds;
 }

 public void setLongSeconds(int longSeconds) {
  this.longSeconds = longSeconds;
 }

 public char getLongDirection() {
  return longDirection;
 }

 public void setLongDirection(char longDirection) throws Exception {
  if (longDirection != 'E' && longDirection != 'W') {
   throw new Exception("Invalid Longitude Direction: " + longDirection);   
  }
  this.longDirection = longDirection;
 }

 public float getLatitude() throws Exception {
  init();
  return latitude;
 }

 public void setLatitude(float latitude) {
  this.latitude = latitude;
 }

 public float getLongitude() throws Exception {  
  init();
  return longitude;
 }

 public void setLongitude(float longitude) {
  this.longitude = longitude;
 }  
 
 public void setLatString(String latStr) throws Exception {
  latStr = latStr.trim();
  String[] values = latStr.split(" ");
  latDegree = Integer.parseInt(values[0].trim());
  latMinutes = Integer.parseInt(values[1].trim());
  latSeconds = Integer.parseInt(values[2].trim());
  latDirection = values[3].trim().charAt(0);
  if (latDirection != 'N' && latDirection != 'S') {   
   throw new Exception("Invalid Latitude Direction: " + latDirection);   
  }
 }
 
 public void setLongString(String longStr) throws Exception {  
  longStr = longStr.trim();
  String[] values = longStr.split(" ");
  longDegree = Integer.parseInt(values[0].trim());
  longMinutes = Integer.parseInt(values[1].trim());
  longSeconds = Integer.parseInt(values[2].trim());
  longDirection = values[3].trim().charAt(0);
  if (longDirection != 'E' && longDirection != 'W') {
   throw new Exception("Invalid Longitude Direction: " + longDirection);   
  }
 }
}
LocationOps.java
 
package com.cables.gps;

public class LocationOps {

 private Location location1 = null;
 private Location location2 = null;
 private int radius = 6371;
 
 
 public LocationOps(Location location1, Location location2) {
  this.location1 = location1;
  this.location2 = location2;
 }
 
 public double calculateDistance() throws Exception {
  double distance = 0.0;
  double lat1 = degreesToRadians(location1.getLatitude());
  double lat2 = degreesToRadians(location2.getLatitude());
  double dLat = degreesToRadians(
    location2.getLatitude() - location1.getLatitude());
  double dLong = degreesToRadians(
    location2.getLongitude() - location1.getLongitude());
  double a = Math.sin(dLat/2.0) * Math.sin(dLat/2.0)
     + Math.cos(lat1) * Math.cos(lat2) *
     Math.sin(dLong/2.0) * Math.sin(dLong/2.0);
  double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
  distance = radius * c;
  return distance;
 }
 
 public double degreesToRadians(double degrees) {
  double radians = 0.0;
  radians = degrees * Math.PI / 180.0;
  return radians;
 }
 
 public static void main(String[] args) throws Exception {
  Location loc1 = new Location();
  loc1.setLatDegree(50);
  loc1.setLatMinutes(03);
  loc1.setLatSeconds(59);
  loc1.setLatDirection('N');
  loc1.setLongDegree(005);
  loc1.setLongMinutes(42);
  loc1.setLongSeconds(53);
  loc1.setLongDirection('W');
  Location loc2 = new Location();
  loc2.setLatDegree(58);
  loc2.setLatMinutes(38);
  loc2.setLatSeconds(38);
  loc2.setLatDirection('N');
  loc2.setLongDegree(003);
  loc2.setLongMinutes(04);
  loc2.setLongSeconds(12);
  loc2.setLongDirection('W');
  System.out.println(new LocationOps(loc1, loc2).calculateDistance());
  loc1.setLatString("50 03 59 N");
  loc1.setLongString("005 42 53 W");
  loc2.setLatString("58 38 38 N");
  loc2.setLongString("003 04 12 W");
  System.out.println(new LocationOps(loc1, loc2).calculateDistance());
 }

}

Tuesday, December 30, 2014

Sum of Prime Numbers Between 1000000 and 1000100 Using Sieve of Eratosthenes

NB: http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes

 
#include "stdio.h"
#include "string.h"
#include "stdlib.h"
#include "assert.h"

typedef  unsigned long long biggerint;

void findPrimeNumbers(biggerint start, biggerint end) {
 char * primeList = malloc(sizeof(unsigned char) * (end + 1));
 int i;
 biggerint sum = 0;

 assert(primeList != NULL);

 /* set prime status */
 for (i = 0; i <= end + 1 ; i++) {
  *(primeList + i) = 1;
 }

 primeList[0] = 0;
 primeList[1] = 0;

 /* mark all the non-prime numbers */
 biggerint currentFactor = 2;
 biggerint lastSquare = 0;
 biggerint currentSquare = 0;
 while (currentFactor * currentFactor <= end) {
  /* mark all the multiples of the current factor */
  biggerint mark = currentFactor + currentFactor;
  while (mark <= end) {
   *(primeList + mark) = 0;
   mark += currentFactor;
  }  

  /* set currentFactor to next prime number */
  currentFactor++;
  while (*(primeList+currentFactor) == 0) currentFactor++;
  assert(currentFactor <= end);
 }

 
 for(i = start; i <= end ; i++) {
  if(*(primeList + i)) sum += i;
 }

 free(primeList);

 printf("%llu\n", sum);
}

int main(int argc, char *argv[]) {
 biggerint start = 1000000;
 biggerint end = 1000100;
 findPrimeNumbers(start, end);
 return 0;
}

Wednesday, July 30, 2014

AES Implementation In Java with ECB | CBC | OFB | CFB Modes Of Operation

Note that these are ONLY basic level programs for easy understanding of the Advanced Encryption Standard (AES) algorithm

Key Generation - AESkeygen.java
 
import java.io.File;
import java.io.FileWriter;

public class AESkeygen {
 
 private final File file = new File("AESkey.txt");
 private final int KEY_LENGTH = 32;
 private final static char[] hexArray = "0123456789ABCDEF".toCharArray();
 
 public AESkeygen() {
  try {   
   FileWriter fileWriter = new FileWriter(file);
   fileWriter.write("");
   for (int i = 0 ; i < KEY_LENGTH ; i++) {
    double random = Math.random();
    int index = (int) (random * 16);
    fileWriter.append(hexArray[index]);
    fileWriter.flush();
   }
   fileWriter.close();
   System.out.println("Key generated and saved in " + file.getName());
  } catch(Exception exp) {
   exp.printStackTrace();
  }
 }
 
 public static void main(String[] args) {
  new AESkeygen();
 }

}


Word.java
 

public class Word {
 
 private byte[] word = null;
 
 public Word() {
  word = new byte[4];
 }
 
 public Word(byte k0, byte k1, byte k2, byte k3) {
  this();
  word[0] = k0;
  word[1] = k1;
  word[2] = k2;
  word[3] = k3;
 }
 
 public byte[] getWord() {
  return word;
 }
 
 public void setWord(byte[] word) {
  this.word = word;
 }
 
 public static byte[] wordToBytes(Word word) {
  return word.getWord();
 }
 
 public static byte[] wordsToBytes(Word[] words) {
  byte[] out = new byte[4 * words.length];
  for (int i = 0 ; i < words.length ; i++) {
   byte[] temp = words[i].getWord();
   out[4*i] = temp[0];
   out[4*i+1] = temp[1];
   out[4*i+2] = temp[2];
   out[4*i+3] = temp[3];   
  }
  return out;
 }
 
 public void rotWord() {
  byte[] temp = this.getWord();
  byte[] newWord = new byte[4];
  newWord[0] = temp[1];
  newWord[1] = temp[2];
  newWord[2] = temp[3];
  newWord[3] = temp[0]; 
  this.setWord(newWord);
 }
 
 public void subWord() {
  byte[] in = this.getWord();
  byte[] out = new byte[4];  
  for (int i = 0 ; i < 4 ; i++) {
   byte a = in[i];
   int row = (a >> 4) & 0x000F;
   int col = a & 0x000F;   
   out[i] = (byte) AESencrypt.sBox[row * 16 + col];
  }
  for (int i = 0 ; i < 4 ; i++) {
   this.word[i] = out[i];
  }  
 } 
 
 public static Word XORWords(Word word1, Word word2) {
  Word outWord = new Word();
  byte[] in1 = word1.getWord();
  byte[] in2 = word2.getWord();
  byte[] out = new byte[4];
  for (int i = 0 ; i < 4 ; i++) {
   out[i] = (byte)((in1[i] ^ in2[i]) & 0xff);
  }
  outWord.setWord(out);  
  return outWord;
 }
 
 public String toString() {
  return AESencrypt.bytesToHex(this.getWord());
 }
}


Encryption - AESencrypt.java
 
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.util.Arrays;

public class AESencrypt {
 
 private static final int BITS = 16;
 private static final int ROUNDS = 10;
 private static final int NO_OF_WORDS_IN_KEY = 44;
 private static final int KEY_LENGTH = 16;
 private static final int BLOCK_LENGTH = 16;
 final protected static char[] hexArray = "0123456789ABCDEF".toCharArray();
 int[] RC = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36};
 Word[] Rcon = new Word[ROUNDS]; 
 private byte[] word = null;
 private String mode = null;
 
 static final int[] sBox = {
  0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
  0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
  0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
  0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
  0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
  0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
  0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
  0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
  0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
  0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
  0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
  0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
  0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
  0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
  0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
  0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
 };
  
 static final int[] invSBox = {
  0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
  0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
  0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
  0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, 
  0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, 
  0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, 
  0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, 
  0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 
  0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, 
  0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, 
  0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 
  0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, 
  0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, 
  0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, 
  0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, 
  0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d
 };
  
 
 public AESencrypt(String mode) {
  this.mode = mode;
  for (int i = 0 ; i < ROUNDS ; i++) {
   Rcon[i] = new Word();
   byte[] temp = new byte[4];
   temp[0] = (byte) (RC[i] & 0xff);
   temp[1] = 0;
   temp[2] = 0;
   temp[3] = 0;
   Rcon[i].setWord(temp);   
  }
  word = new byte[NO_OF_WORDS_IN_KEY];
 }
 
 /* Ref: http://www.samiam.org/galois.html */
 /* Galois Addition*/
 byte gadd(byte a, byte b) {
  return (byte) ((a ^ b) & 0xff);
 }
 /* Galois Subtraction*/
 byte gsub(byte a, byte b) {
  return (byte) ((a ^ b) & 0xff);
 }
 /* Galois Multiplication*/
 byte gmul(byte a, byte b) {
  byte p = 0;
  int counter;
  byte high_bit_set;
  byte byte0x80 = hexStringToByteArray("80")[0];
  for (counter = 0 ; counter < 8 ; counter++) {
   if((b & 0x01) == 1) {
    //System.out.println("lower bit of b is set");
    p = (byte)((p ^ a) & 0xff);
   }   
   high_bit_set = (byte) (a & 0x80);
   //printByte("high_bit_set", high_bit_set);
   a <<= 1;
   if (high_bit_set == byte0x80) {
    //System.out.println("higher bit of a is set");
    a = (byte)((a ^ 0x1b) & 0xff);
   }
   b = (byte)((b >> 1) & 0x7f);
   
   //printByte("a", a);
   //printByte("b", b);
   //printByte("p", p);
  }
  return p;
 }
 
 byte gmul(byte a, int b) {
  byte t = (byte)(b & 0xff);
  return gmul(a, t);
 }
 
 /* Key Expansion */
 private byte[] expandKey(byte[] key) throws Exception {
  //System.out.println(key.length);
  //System.out.println(bytesToHex(key));
  if(key.length != KEY_LENGTH) {
   throw new Exception("Key should be of length, 128 bits");
  }
  Word[] w = new Word[NO_OF_WORDS_IN_KEY]; 
  Word temp;
  for (int i = 0; i < 4; i++) {
   w[i] = new Word(key[4*i], key[4*i+1], key[4*i+2], key[4*i+3]); 
   //System.out.println("w" + i + " = " + w[i]);
  }
  
  for (int i = 4; i < 44; i++) {
   temp = w[i-1];
   Word temp1 = new Word();
   temp1.setWord(temp.getWord());
   //System.out.println("w" + (i-1) + " = " + temp);
   if (i % 4 == 0) {
    temp1.rotWord();
    //System.out.println("Rot=" + temp1);
    temp1.subWord();
    //System.out.println("Sub=" + temp1);
    temp1 = Word.XORWords(temp1, Rcon[(i/4) - 1]);
    //System.out.println("Rcon" + temp1);
   }
   w[i] = Word.XORWords(w[i-4], temp1);
   //System.out.println("w" + i + " = " + w[i]);   
  }
  return Word.wordsToBytes(w);
 }
 
 /* Substitute Bytes */
 private byte[] subBytes(byte[] in) {
  byte[] out = new byte[BITS];
  for (int i = 0 ; i < BITS ; i++) {
   byte a = in[i];
   int row = (a >> 4) & 0x000F;
   int col = a & 0x000F;   
   out[i] = (byte) sBox[row * BITS + col];
  }
  return out;
 }
 
 /* Inverse Substitute Bytes */
 private byte[] inverseSubBytes(byte[] in) {
  byte[] out = new byte[BITS];
  for (int i = 0 ; i < BITS ; i++) {
   byte a = in[i];
   int row = (a >> 4) & 0x000F;
   int col = a & 0x000F;   
   out[i] = (byte) invSBox[row * BITS + col];
  }
  return out;
 }
 
 /* Shift Rows */
 private byte[] shiftRows(byte[] in) {
  byte[] out = new byte[BITS];
  byte[] temp = new byte[BITS];
  for (int i = 0 ; i < BITS/4 ; i++) {
   for (int j = 0 ; j < BITS/4 ; j++) {
    temp[4*j+i] = in[4*i+j];
   }
  }
  //System.out.println("temp: " + bytesToHex(temp));
  for (int i = 0 ; i < BITS/4 ; i++) {
   byte[] a = Arrays.copyOfRange(temp, (4 * i), (4 * i + 4));
   byte[] b = leftShift(a, i);
   in[4*i] = b[0];
   in[4*i+1] = b[1];
   in[4*i+2] = b[2];
   in[4*i+3] = b[3];
  }   
  for (int i = 0 ; i < BITS/4 ; i++) {
   for (int j = 0 ; j < BITS/4 ; j++) {
    out[4*j+i] = in[4*i+j];
   }
  }
  return out;
 }
 
 private byte[] leftShift(byte[] in, int times) {
  byte[] out = new byte[4];
  out = Arrays.copyOfRange(in, 0, 4);
  for (int i = 0 ; i < times ; i++) {
   out[0] = in[1];
   out[1] = in[2];
   out[2] = in[3];
   out[3] = in[0];
   in = Arrays.copyOfRange(out, 0, 4);
  }
  return out;
 }
 
 /* Inverse Shift Rows */
 private byte[] inverseShiftRows(byte[] in) {
  byte[] out = new byte[BITS];
  byte[] temp = new byte[BITS];
  for (int i = 0 ; i < BITS/4 ; i++) {
   for (int j = 0 ; j < BITS/4 ; j++) {
    temp[4*j+i] = in[4*i+j];
   }
  }
  for (int i = 0 ; i < BITS/4 ; i++) {
   byte[] a = Arrays.copyOfRange(temp, (4 * i), (4 * i + 4));
   byte[] b = rightShift(a, i);
   in[4 * i] = b[0];
   in[4 * i + 1] = b[1];
   in[4 * i + 2] = b[2];
   in[4 * i + 3] = b[3];
  }
  for (int i = 0 ; i < BITS/4 ; i++) {
   for (int j = 0 ; j < BITS/4 ; j++) {
    out[4*j+i] = in[4*i+j];
   }
  }
  return out;
 }
 
 private byte[] rightShift(byte[] in, int times) {
  byte[] out = new byte[4];
  out = Arrays.copyOfRange(in, 0, 4);
  for (int i = 0 ; i < times ; i++) {
   out[0] = in[3];
   out[1] = in[0];
   out[2] = in[1];
   out[3] = in[2];
   in = Arrays.copyOfRange(out, 0, 4);
  }
  return out;
 }
 
 /* Mix Columns */
 private byte[] mixColumns(byte[] in) {
  byte[] out = new byte[BITS];
  byte[] temp = new byte[BITS];  
  for (int i = 0 ; i < BITS/4 ; i++) {
   for (int j = 0 ; j < BITS/4 ; j++) {
    temp[4*j+i] = in[4*i+j];
   }
  }
  in = temp;
  for (int j = 0 ; j < BITS/4 ; j++) {
   out[4*0+j] = (byte) ((gmul(in[4*0+j], 2)  ^ gmul(in[4*1+j], 3)  ^ in[4*2+j]    ^ in[4*3+j])    & 0xff);
   out[4*1+j] = (byte) ((in[4*0+j]    ^ gmul(in[4*1+j], 2)  ^ gmul(in[4*2+j], 3)  ^ in[4*3+j])    & 0xff);
   out[4*2+j] = (byte) ((in[4*0+j]    ^ in[4*1+j]    ^ gmul(in[4*2+j], 2)  ^ gmul(in[4*3+j], 3))  & 0xff);
   out[4*3+j] = (byte) ((gmul(in[4*0+j], 3)  ^ in[4*1+j]    ^ in[4*2+j]    ^ gmul(in[4*3+j], 2))  & 0xff);
  }
  for (int i = 0 ; i < BITS/4 ; i++) {
   for (int j = 0 ; j < BITS/4 ; j++) {
    temp[4*j+i] = out[4*i+j];
   }
  }
  out = temp;
  return out;
 }
 
 /* Inverse Mix Columns */
 private byte[] inverseMixColumns(byte[] in) {
  byte[] out = new byte[BITS];
  byte[] temp = new byte[BITS];  
  for (int i = 0 ; i < BITS/4 ; i++) {
   for (int j = 0 ; j < BITS/4 ; j++) {
    temp[4*j+i] = in[4*i+j];
   }
  }
  in = temp;
  for (int j = 0 ; j < BITS/4 ; j++) {
   out[4*0+j] = (byte) ((gmul(in[4*0+j], 14)  ^ gmul(in[4*1+j], 11)  ^ gmul(in[4*2+j], 13)  ^ gmul(in[4*3+j], 9))  & 0xff);
   out[4*1+j] = (byte) ((gmul(in[4*0+j], 9)  ^ gmul(in[4*1+j], 14)  ^ gmul(in[4*2+j], 11)  ^ gmul(in[4*3+j], 13))  & 0xff);
   out[4*2+j] = (byte) ((gmul(in[4*0+j], 13)  ^ gmul(in[4*1+j], 9) ^ gmul(in[4*2+j], 14)  ^ gmul(in[4*3+j], 11))  & 0xff);
   out[4*3+j] = (byte) ((gmul(in[4*0+j], 11)  ^ gmul(in[4*1+j], 13) ^ gmul(in[4*2+j], 9) ^ gmul(in[4*3+j], 14))  & 0xff);
  }
  for (int i = 0 ; i < BITS/4 ; i++) {
   for (int j = 0 ; j < BITS/4 ; j++) {
    temp[4*j+i] = out[4*i+j];
   }
  }
  out = temp;
  return out;
 }
 
 private byte[] hexStringToByteArray(String string) {
  int length = string.length();
  int n = (int)Math.ceil((length + 1) / 2);
  byte[] result = new byte[n];  
  for (int i = length - 1; i >= 0 ; i -= 2) { 
   if (i == 0) {
    result[i / 2] = (byte) ((Character.digit('0', 16) << 4)
      + Character.digit(string.charAt(i), 16));
   } else {
    result[i / 2] = (byte) ((Character.digit(string.charAt(i - 1), 16) << 4)
     + Character.digit(string.charAt(i), 16));
   }
  }
  return result;
 }
 
 /* http://stackoverflow.com/questions/9655181/convert-from-byte-array-to-hex-string-in-java */
 public static String bytesToHex(byte[] bytes) {
     char[] hexChars = new char[bytes.length * 2];
     for ( int j = 0; j < bytes.length; j++ ) {
         int v = bytes[j] & 0xFF;
         hexChars[j * 2] = hexArray[v >>> 4];
         hexChars[j * 2 + 1] = hexArray[v & 0x0F];
     }
     return new String(hexChars);
 }
 
 private void printBytes(byte[] input) {    
  for (int i = 0 ; i < input.length; i++) {
   System.out.print(byteToBits(input[i]) + " ");
  }
  System.out.println();
 }
 
 private void printByte(String msg, byte input) {
  byte[] temp = new byte[1];
  temp[0] = input;
  System.out.println(msg + ": " + bytesToHex(temp));  
 }
 
 private String byteToBits(byte b) {
  StringBuffer buffer = new StringBuffer();
  for (int i = 0 ; i < 8 ; i++)
   buffer.append((int)(b >> (8-(i+1)) & 0x0001));
  return buffer.toString();
 }
 
 private byte[] getRoundKey(int round) {
  byte[] out = new byte[KEY_LENGTH];
  out = Arrays.copyOfRange(word, 16*round, 16*round+16);  
  return out;
 }
 
 public static byte[] XORBytes(byte[] in1, byte[] in2) {  
  byte[] out = new byte[in1.length];
  for (int i = 0 ; i < in1.length ; i++) {
   out[i] = (byte)((in1[i] ^ in2[i]) & 0xff);
  }   
  return out;
 }
 
 public byte[] encryptText(byte[] plainText, byte[] key) throws Exception {
  byte[] cipher = new byte[BLOCK_LENGTH];  
  this.word = expandKey(key);
  byte[] roundKey = getRoundKey(0);
  /* Round 0 */
  cipher = XORBytes(plainText, roundKey);
  //System.out.println("Round 0\n" + bytesToHex(cipher));
  /* Rounds 1 to 9*/
  for (int i = 1 ; i < 10 ; i++) {
   //System.out.println("Round " + i);
   cipher = subBytes(cipher);
   //System.out.println("SubBytes: " + bytesToHex(cipher));
   cipher = shiftRows(cipher);
   //System.out.println("ShiftRows: " + bytesToHex(cipher));
   cipher = mixColumns(cipher);
   //System.out.println("MixColumns: " + bytesToHex(cipher));
   roundKey = getRoundKey(i);
   //System.out.println("RoundKey: " + bytesToHex(roundKey));
   cipher = XORBytes(cipher, roundKey);   
   //System.out.println("CIPHER: " + bytesToHex(cipher));
  }
  /* Round 10*/
  //System.out.println("Round 10");
  cipher = subBytes(cipher);
  //System.out.println("SubBytes: " + bytesToHex(cipher));
  cipher = shiftRows(cipher);
  //System.out.println("ShiftRows: " + bytesToHex(cipher));
  roundKey = getRoundKey(10);
  //System.out.println("RoundKey: " + bytesToHex(roundKey));
  cipher = XORBytes(cipher, roundKey);
  //System.out.println("CIPHER: " + bytesToHex(cipher));
  return cipher;
 }
 
 public byte[] decryptText(byte[] cipher, byte[] key) throws Exception {
  byte[] plainText = new byte[BLOCK_LENGTH];  
  this.word = expandKey(key);
  byte[] roundKey = getRoundKey(10);
  /* Round 0 */
  plainText = XORBytes(cipher, roundKey);
  /* Rounds 1 to 9*/
  for (int i = 9 ; i > 0 ; i--) {
   plainText = inverseShiftRows(plainText);
   plainText = inverseSubBytes(plainText);
   roundKey = getRoundKey(i);
   plainText = XORBytes(plainText, roundKey);
   plainText = inverseMixColumns(plainText);
  }
  /* Round 10*/
  plainText = inverseShiftRows(plainText);
  plainText = inverseSubBytes(plainText);
  roundKey = getRoundKey(0);
  plainText = XORBytes(plainText, roundKey);
  return plainText;
 }
 
 public static void main(String[] args) throws Exception {
  try {
   if (args.length != 1) {
    System.out.println("Usage: java < classname > < mode >"
      + "\n\t< mode > := (ECB|CBC|OFB|CFB)");
    return;
   }
   /* ECB, CBC, OFB, or CFB */   
   String mode = args[0];
   //String mode = "CFB";
   mode = mode.toUpperCase();
   AESencrypt aes = new AESencrypt(mode); 
   File keyFile = new File("AESkey.txt");
   File textFile = new File("AESplaintext.txt");
   File cipherFile = new File("AESciphertext.txt");   
   FileReader keyFileReader = new FileReader(keyFile);
   BufferedReader bufferedReader = new BufferedReader(keyFileReader);
   FileInputStream textFileInputStream = new FileInputStream(textFile);
   FileOutputStream cipherFileOutputStream = new FileOutputStream(cipherFile);
   byte[] key = new byte[(int) keyFile.length()];
   String keyString = bufferedReader.readLine();
   key = aes.hexStringToByteArray(keyString);
   byte[] message = new byte[(int) textFile.length()];
   textFileInputStream.read(message);        
   byte[] cipher = aes.encrypt(message, key);
   cipherFileOutputStream.write(cipher);
   cipherFileOutputStream.flush();
   cipherFileOutputStream.close();
   bufferedReader.close();
   textFileInputStream.close();
   System.out.println("Encryption done! Please check AESciphertext.txt for output!");
  } catch(Exception exp) {
   exp.printStackTrace();
  }
 }

 private byte[] encrypt(byte[] message, byte[] key) throws Exception {
  if (message.length < 16) {
   System.out.println("Message should be atleast 64 bits");
   System.exit(1);
  }
  if (key.length != 16) {
   System.out.println("Key should be 64 bits");
   System.exit(1);
  }
  int length = message.length;
  int n = (length + 15)/16 * 16;
  byte[] cipher = new byte[n];
  if (length == 16) {
   if (mode.equals("ECB")) {
    return encryptText(message, key);
   } else if (mode.equals("CBC")) {
    byte[] iv = getInitializationVector();
    message = XORBytes(message, iv);
    return encryptText(message, key);
   } else if (mode.equals("OFB")) {
    byte[] nounce = getNounce();
    byte[] temp = encryptText(nounce, key);
    byte[] result = XORBytes(temp, message);
    return result;
   } else if (mode.equals("CFB")) {
    
   } else {
    System.out.println("Unsupported mode of operation!");
    return null;
   }   
  }
  int i = 0;
  int k = 0;
  byte[] feedback = new byte[16];  
  if (mode.equals("CBC")) {
   feedback = getInitializationVector();
  } else if (mode.equals("OFB")) {
   feedback = getNounce();   
  } else if (mode.equals("CFB")) {
   feedback = getInitializationVectorCFB();
  }
  
  while (i < length) {
   byte[] block = new byte[16];
   byte[] result = new byte[16];
   int j = 0;
   for (; j < 16 && i < length; j++, i++) {
    block[j] = message[i];
   }
   while (j < 16) {
    /* pad with white spaces */
    block[j++] = 0x20;
   }
      
   //System.out.println("BLOCK: ");
   //printBytes(block);  
   if (mode.equals("ECB")) {
    result = encryptText(block, key);
   } else if (mode.equals("CBC")) {    
    block = XORBytes(block, feedback);
    result = encryptText(block, key);
    feedback = Arrays.copyOfRange(result, 0, 16);       
   } else if (mode.equals("OFB")) {
    result = encryptText(feedback, key);
    feedback = Arrays.copyOfRange(result, 0, 16);
    result = XORBytes(result, block);
   } else if (mode.equals("CFB")) {    
    result = encryptText(feedback, key);
    byte[] resultPart = Arrays.copyOfRange(result, 0, 8);
    byte[] blockPart = Arrays.copyOfRange(block, 0, 8);
    byte[] temp1 = XORBytes(resultPart, blockPart);
    feedback = mergeBytes(Arrays.copyOfRange(result, 8, 16), temp1);     
    resultPart = Arrays.copyOfRange(result, 8, 16);
    blockPart = Arrays.copyOfRange(block, 8, 16);
    result = encryptText(feedback, key);
    byte[] temp2 = XORBytes(resultPart, blockPart);
    feedback = mergeBytes(Arrays.copyOfRange(result, 8, 16), temp2);
    result = mergeBytes(temp1, temp2);       
   } else {
    System.out.println("Unsupported mode of operation!");
    return null;
   }   
   //System.out.println("RESULT: ");
   //printBytes(result);
   for (j = 0 ; j < 16 && k < cipher.length; j++, k++) {
    cipher[k] = result[j];
   }
  }
  return cipher;  
 }
 
 private byte[] getInitializationVector() {
  return hexStringToByteArray("247D8AC4DDB1AA739DC593821D0BC432");   
 }
 
 private byte[] getInitializationVectorCFB() {
  return hexStringToByteArray("247D8AC4DDB1AA739DC593821D0BC432");   
 }
 
 private byte[] getNounce() {
//  char[] hexArray = "0123456789ABCDEF".toCharArray();
//  String nounceStr = "";
//  for (int i = 0 ; i < 16 ; i++) {
//   double random = Math.random();
//   int index = (int) (random * 16);
//   nounceStr += hexArray[index];   
//  }
//  return hexStringToByteArray(nounceStr);
  return hexStringToByteArray("247D8AC4DDB1AA739DC593821D0BC432");
 } 

 private byte[] mergeBytes(byte[] in1, byte[] in2) {
  byte[] out = new byte[in1.length + in2.length];
  int i = 0;
  for (int j = 0 ; j < in1.length ; j++) {
   out[i++] = in1[j];
  }
  for (int j = 0 ; j < in2.length ; j++) {
   out[i++] = in2[j];
  }
  return out;
 } 
}

Decryption - AESdecrypt.java
 
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.util.Arrays;

public class AESdecrypt {
 
 private static final int BITS = 16;
 private static final int ROUNDS = 10;
 private static final int NO_OF_WORDS_IN_KEY = 44;
 private static final int KEY_LENGTH = 16;
 private static final int BLOCK_LENGTH = 16;
 final protected static char[] hexArray = "0123456789ABCDEF".toCharArray();
 int[] RC = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36};
 Word[] Rcon = new Word[ROUNDS]; 
 private byte[] word = null;
 private String mode = null;
 
 static final int[] sBox = {
  0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
  0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
  0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
  0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
  0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
  0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
  0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
  0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
  0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
  0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
  0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
  0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
  0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
  0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
  0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
  0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
 };
  
 static final int[] invSBox = {
  0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
  0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
  0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
  0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, 
  0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, 
  0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, 
  0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, 
  0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 
  0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, 
  0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, 
  0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 
  0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, 
  0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, 
  0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, 
  0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, 
  0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d
 };
  
 
 public AESdecrypt(String mode) {
  this.mode = mode;
  for (int i = 0 ; i < ROUNDS ; i++) {
   Rcon[i] = new Word();
   byte[] temp = new byte[4];
   temp[0] = (byte) (RC[i] & 0xff);
   temp[1] = 0;
   temp[2] = 0;
   temp[3] = 0;
   Rcon[i].setWord(temp);   
  }
  word = new byte[NO_OF_WORDS_IN_KEY];
 }
 
 /* Ref: http://www.samiam.org/galois.html */
 /* Galois Addition*/
 byte gadd(byte a, byte b) {
  return (byte) ((a ^ b) & 0xff);
 }
 /* Galois Subtraction*/
 byte gsub(byte a, byte b) {
  return (byte) ((a ^ b) & 0xff);
 }
 /* Galois Multiplication*/
 byte gmul(byte a, byte b) {
  byte p = 0;
  int counter;
  byte high_bit_set;
  byte byte0x80 = hexStringToByteArray("80")[0];
  for (counter = 0 ; counter < 8 ; counter++) {
   if((b & 0x01) == 1) {
    //System.out.println("lower bit of b is set");
    p = (byte)((p ^ a) & 0xff);
   }   
   high_bit_set = (byte) (a & 0x80);
   //printByte("high_bit_set", high_bit_set);
   a <<= 1;
   if (high_bit_set == byte0x80) {
    //System.out.println("higher bit of a is set");
    a = (byte)((a ^ 0x1b) & 0xff);
   }
   b = (byte)((b >> 1) & 0x7f);
   
   //printByte("a", a);
   //printByte("b", b);
   //printByte("p", p);
  }
  return p;
 }
 
 byte gmul(byte a, int b) {
  byte t = (byte)(b & 0xff);
  return gmul(a, t);
 }
 
 /* Key Expansion */
 private byte[] expandKey(byte[] key) throws Exception {
  //System.out.println(key.length);
  //System.out.println(bytesToHex(key));
  if(key.length != KEY_LENGTH) {
   throw new Exception("Key should be of length, 128 bits");
  }
  Word[] w = new Word[NO_OF_WORDS_IN_KEY]; 
  Word temp;
  for (int i = 0; i < 4; i++) {
   w[i] = new Word(key[4*i], key[4*i+1], key[4*i+2], key[4*i+3]); 
   //System.out.println("w" + i + " = " + w[i]);
  }
  
  for (int i = 4; i < 44; i++) {
   temp = w[i-1];
   Word temp1 = new Word();
   temp1.setWord(temp.getWord());
   //System.out.println("w" + (i-1) + " = " + temp);
   if (i % 4 == 0) {
    temp1.rotWord();
    //System.out.println("Rot=" + temp1);
    temp1.subWord();
    //System.out.println("Sub=" + temp1);
    temp1 = Word.XORWords(temp1, Rcon[(i/4) - 1]);
    //System.out.println("Rcon" + temp1);
   }
   w[i] = Word.XORWords(w[i-4], temp1);
   //System.out.println("w" + i + " = " + w[i]);   
  }
  return Word.wordsToBytes(w);
 }
 
 /* Substitute Bytes */
 private byte[] subBytes(byte[] in) {
  byte[] out = new byte[BITS];
  for (int i = 0 ; i < BITS ; i++) {
   byte a = in[i];
   int row = (a >> 4) & 0x000F;
   int col = a & 0x000F;   
   out[i] = (byte) sBox[row * BITS + col];
  }
  return out;
 }
 
 /* Inverse Substitute Bytes */
 private byte[] inverseSubBytes(byte[] in) {
  byte[] out = new byte[BITS];
  for (int i = 0 ; i < BITS ; i++) {
   byte a = in[i];
   int row = (a >> 4) & 0x000F;
   int col = a & 0x000F;   
   out[i] = (byte) invSBox[row * BITS + col];
  }
  return out;
 }
 
 /* Shift Rows */
 private byte[] shiftRows(byte[] in) {
  byte[] out = new byte[BITS];
  byte[] temp = new byte[BITS];
  for (int i = 0 ; i < BITS/4 ; i++) {
   for (int j = 0 ; j < BITS/4 ; j++) {
    temp[4*j+i] = in[4*i+j];
   }
  }
  //System.out.println("temp: " + bytesToHex(temp));
  for (int i = 0 ; i < BITS/4 ; i++) {
   byte[] a = Arrays.copyOfRange(temp, (4 * i), (4 * i + 4));
   byte[] b = leftShift(a, i);
   in[4*i] = b[0];
   in[4*i+1] = b[1];
   in[4*i+2] = b[2];
   in[4*i+3] = b[3];
  }   
  for (int i = 0 ; i < BITS/4 ; i++) {
   for (int j = 0 ; j < BITS/4 ; j++) {
    out[4*j+i] = in[4*i+j];
   }
  }
  return out;
 }
 
 private byte[] leftShift(byte[] in, int times) {
  byte[] out = new byte[4];
  out = Arrays.copyOfRange(in, 0, 4);
  for (int i = 0 ; i < times ; i++) {
   out[0] = in[1];
   out[1] = in[2];
   out[2] = in[3];
   out[3] = in[0];
   in = Arrays.copyOfRange(out, 0, 4);
  }
  return out;
 }
 
 /* Inverse Shift Rows */
 private byte[] inverseShiftRows(byte[] in) {
  byte[] out = new byte[BITS];
  byte[] temp = new byte[BITS];
  for (int i = 0 ; i < BITS/4 ; i++) {
   for (int j = 0 ; j < BITS/4 ; j++) {
    temp[4*j+i] = in[4*i+j];
   }
  }
  for (int i = 0 ; i < BITS/4 ; i++) {
   byte[] a = Arrays.copyOfRange(temp, (4 * i), (4 * i + 4));
   byte[] b = rightShift(a, i);
   in[4 * i] = b[0];
   in[4 * i + 1] = b[1];
   in[4 * i + 2] = b[2];
   in[4 * i + 3] = b[3];
  }
  for (int i = 0 ; i < BITS/4 ; i++) {
   for (int j = 0 ; j < BITS/4 ; j++) {
    out[4*j+i] = in[4*i+j];
   }
  }
  return out;
 }
 
 private byte[] rightShift(byte[] in, int times) {
  byte[] out = new byte[4];
  out = Arrays.copyOfRange(in, 0, 4);
  for (int i = 0 ; i < times ; i++) {
   out[0] = in[3];
   out[1] = in[0];
   out[2] = in[1];
   out[3] = in[2];
   in = Arrays.copyOfRange(out, 0, 4);
  }
  return out;
 }
 
 /* Mix Columns */
 private byte[] mixColumns(byte[] in) {
  byte[] out = new byte[BITS];
  byte[] temp = new byte[BITS];  
  for (int i = 0 ; i < BITS/4 ; i++) {
   for (int j = 0 ; j < BITS/4 ; j++) {
    temp[4*j+i] = in[4*i+j];
   }
  }
  in = temp;
  for (int j = 0 ; j < BITS/4 ; j++) {
   out[4*0+j] = (byte) ((gmul(in[4*0+j], 2)  ^ gmul(in[4*1+j], 3)  ^ in[4*2+j]    ^ in[4*3+j])    & 0xff);
   out[4*1+j] = (byte) ((in[4*0+j]    ^ gmul(in[4*1+j], 2)  ^ gmul(in[4*2+j], 3)  ^ in[4*3+j])    & 0xff);
   out[4*2+j] = (byte) ((in[4*0+j]    ^ in[4*1+j]    ^ gmul(in[4*2+j], 2)  ^ gmul(in[4*3+j], 3))  & 0xff);
   out[4*3+j] = (byte) ((gmul(in[4*0+j], 3)  ^ in[4*1+j]    ^ in[4*2+j]    ^ gmul(in[4*3+j], 2))  & 0xff);
  }
  for (int i = 0 ; i < BITS/4 ; i++) {
   for (int j = 0 ; j < BITS/4 ; j++) {
    temp[4*j+i] = out[4*i+j];
   }
  }
  out = temp;
  return out;
 }
 
 /* Inverse Mix Columns */
 private byte[] inverseMixColumns(byte[] in) {
  byte[] out = new byte[BITS];
  byte[] temp = new byte[BITS];  
  for (int i = 0 ; i < BITS/4 ; i++) {
   for (int j = 0 ; j < BITS/4 ; j++) {
    temp[4*j+i] = in[4*i+j];
   }
  }
  in = temp;
  for (int j = 0 ; j < BITS/4 ; j++) {
   out[4*0+j] = (byte) ((gmul(in[4*0+j], 14)  ^ gmul(in[4*1+j], 11)  ^ gmul(in[4*2+j], 13)  ^ gmul(in[4*3+j], 9))  & 0xff);
   out[4*1+j] = (byte) ((gmul(in[4*0+j], 9)  ^ gmul(in[4*1+j], 14)  ^ gmul(in[4*2+j], 11)  ^ gmul(in[4*3+j], 13))  & 0xff);
   out[4*2+j] = (byte) ((gmul(in[4*0+j], 13)  ^ gmul(in[4*1+j], 9) ^ gmul(in[4*2+j], 14)  ^ gmul(in[4*3+j], 11))  & 0xff);
   out[4*3+j] = (byte) ((gmul(in[4*0+j], 11)  ^ gmul(in[4*1+j], 13) ^ gmul(in[4*2+j], 9) ^ gmul(in[4*3+j], 14))  & 0xff);
  }
  for (int i = 0 ; i < BITS/4 ; i++) {
   for (int j = 0 ; j < BITS/4 ; j++) {
    temp[4*j+i] = out[4*i+j];
   }
  }
  out = temp;
  return out;
 }
 
 private byte[] hexStringToByteArray(String string) {
  int length = string.length();
  int n = (int)Math.ceil((length + 1) / 2);
  byte[] result = new byte[n];  
  for (int i = length - 1; i >= 0 ; i -= 2) { 
   if (i == 0) {
    result[i / 2] = (byte) ((Character.digit('0', 16) << 4)
      + Character.digit(string.charAt(i), 16));
   } else {
    result[i / 2] = (byte) ((Character.digit(string.charAt(i - 1), 16) << 4)
     + Character.digit(string.charAt(i), 16));
   }
  }
  return result;
 }
 
 /* http://stackoverflow.com/questions/9655181/convert-from-byte-array-to-hex-string-in-java */
 public static String bytesToHex(byte[] bytes) {
     char[] hexChars = new char[bytes.length * 2];
     for ( int j = 0; j < bytes.length; j++ ) {
         int v = bytes[j] & 0xFF;
         hexChars[j * 2] = hexArray[v >>> 4];
         hexChars[j * 2 + 1] = hexArray[v & 0x0F];
     }
     return new String(hexChars);
 }
 
 private void printBytes(byte[] input) {    
  for (int i = 0 ; i < input.length; i++) {
   System.out.print(byteToBits(input[i]) + " ");
  }
  System.out.println();
 }
 
 private void printByte(String msg, byte input) {
  byte[] temp = new byte[1];
  temp[0] = input;
  System.out.println(msg + ": " + bytesToHex(temp));  
 }
 
 private String byteToBits(byte b) {
  StringBuffer buffer = new StringBuffer();
  for (int i = 0 ; i < 8 ; i++)
   buffer.append((int)(b >> (8-(i+1)) & 0x0001));
  return buffer.toString();
 }
 
 private byte[] getRoundKey(int round) {
  byte[] out = new byte[KEY_LENGTH];
  out = Arrays.copyOfRange(word, 16*round, 16*round+16);  
  return out;
 }
 
 public static byte[] XORBytes(byte[] in1, byte[] in2) {  
  byte[] out = new byte[in1.length];
  for (int i = 0 ; i < in1.length ; i++) {
   out[i] = (byte)((in1[i] ^ in2[i]) & 0xff);   
  }   
  return out;
 }
 
 public byte[] encryptText(byte[] plainText, byte[] key) throws Exception {
  byte[] cipher = new byte[BLOCK_LENGTH];  
  this.word = expandKey(key);
  byte[] roundKey = getRoundKey(0);
  /* Round 0 */
  cipher = XORBytes(plainText, roundKey);
  //System.out.println("Round 0\n" + bytesToHex(cipher));
  /* Rounds 1 to 9*/
  for (int i = 1 ; i < 10 ; i++) {
   //System.out.println("Round " + i);
   cipher = subBytes(cipher);
   //System.out.println("SubBytes: " + bytesToHex(cipher));
   cipher = shiftRows(cipher);
   //System.out.println("ShiftRows: " + bytesToHex(cipher));
   cipher = mixColumns(cipher);
   //System.out.println("MixColumns: " + bytesToHex(cipher));
   roundKey = getRoundKey(i);
   //System.out.println("RoundKey: " + bytesToHex(roundKey));
   cipher = XORBytes(cipher, roundKey);   
   //System.out.println("CIPHER: " + bytesToHex(cipher));
  }
  /* Round 10*/
  //System.out.println("Round 10");
  cipher = subBytes(cipher);
  //System.out.println("SubBytes: " + bytesToHex(cipher));
  cipher = shiftRows(cipher);
  //System.out.println("ShiftRows: " + bytesToHex(cipher));
  roundKey = getRoundKey(10);
  //System.out.println("RoundKey: " + bytesToHex(roundKey));
  cipher = XORBytes(cipher, roundKey);
  //System.out.println("CIPHER: " + bytesToHex(cipher));
  return cipher;
 }
 
 public byte[] decryptText(byte[] cipher, byte[] key) throws Exception {
  byte[] plainText = new byte[BLOCK_LENGTH];  
  this.word = expandKey(key);
  byte[] roundKey = getRoundKey(10);
  /* Round 0 */
  plainText = XORBytes(cipher, roundKey);
  /* Rounds 1 to 9*/
  for (int i = 9 ; i > 0 ; i--) {
   plainText = inverseShiftRows(plainText);
   plainText = inverseSubBytes(plainText);
   roundKey = getRoundKey(i);
   plainText = XORBytes(plainText, roundKey);
   plainText = inverseMixColumns(plainText);
  }
  /* Round 10*/
  plainText = inverseShiftRows(plainText);
  plainText = inverseSubBytes(plainText);
  roundKey = getRoundKey(0);
  plainText = XORBytes(plainText, roundKey);
  return plainText;
 }
 
 public static void main(String[] args) throws Exception {
  try {
   if (args.length != 1) {
    System.out.println("Usage: java < classname > < mode >"
      + "\n\t< mode > := (ECB|CBC|OFB|CFB)");
    return;
   }
   /* ECB, CBC, OFB, or CFB */
   String mode = args[0];
   //String mode = "CFB";
   mode = mode.toUpperCase();
   AESdecrypt aes = new AESdecrypt(mode); 
   File keyFile = new File("AESkey.txt");
   File textFile = new File("AESplaintext.txt");
   File cipherFile = new File("AESciphertext.txt");   
   FileReader keyFileReader = new FileReader(keyFile);
   BufferedReader bufferedReader = new BufferedReader(keyFileReader);
   FileInputStream cipherFileInputStream = new FileInputStream(cipherFile);
   FileOutputStream textFileOutputStream = new FileOutputStream(textFile);
   byte[] key = new byte[(int) keyFile.length()];
   String keyString = bufferedReader.readLine();
   key = aes.hexStringToByteArray(keyString);
   byte[] cipher = new byte[(int) cipherFile.length()];
   cipherFileInputStream.read(cipher);        
   byte[] message = aes.decrypt(cipher, key);   
   textFileOutputStream.write(message);
   textFileOutputStream.flush();
   textFileOutputStream.close();
   bufferedReader.close();
   cipherFileInputStream.close();
   System.out.println("Decryption done! Please check AESplaintext.txt for output!");
  } catch(Exception exp) {
   exp.printStackTrace();
  }
 }

 private byte[] decrypt(byte[] message, byte[] key) throws Exception {
  if (message.length < 16) {
   System.out.println("Message should be atleast 64 bits");
   System.exit(1);
  }
  if (key.length != 16) {
   System.out.println("Key should be 64 bits");
   System.exit(1);
  }
  int length = message.length;
  int n = (length + 15)/16 * 16;
  byte[] cipher = new byte[n];
  if (length == 16) {
   if (mode.equals("ECB")) {
    return decryptText(message, key);
   } else if (mode.equals("CBC")) {
    byte[] iv = getInitializationVector();
    message = XORBytes(message, iv);
    return decryptText(message, key);
   } else if (mode.equals("OFB")) {
    byte[] nounce = getNounce();
    byte[] temp = encryptText(nounce, key);
    byte[] result = XORBytes(temp, message);
    return result;
   } else if (mode.equals("CFB")) {
    
   } else {
    System.out.println("Unsupported mode of operation!");
    return null;
   }   
  }
  int i = 0;
  int k = 0;
  byte[] feedback = new byte[16];  
  if (mode.equals("CBC")) {
   feedback = getInitializationVector();
  } else if (mode.equals("OFB")) {
   feedback = getNounce();   
  } else if (mode.equals("CFB")) {
   feedback = getInitializationVectorCFB();
  }
  
  while (i < length) {
   byte[] block = new byte[16];
   byte[] result = new byte[16];
   int j = 0;
   for (; j < 16 && i < length; j++, i++) {
    block[j] = message[i];
   }
   while (j < 16) {
    /* pad with white spaces */
    block[j++] = 0x20;
   }
      
   //System.out.println("BLOCK: ");
   //printBytes(block);  
   if (mode.equals("ECB")) {
    result = decryptText(block, key);
   } else if (mode.equals("CBC")) {    
    result = decryptText(block, key);
    result = XORBytes(result, feedback);
    feedback = Arrays.copyOfRange(block, 0, 16);     
   } else if (mode.equals("OFB")) {
    result = encryptText(feedback, key);
    feedback = Arrays.copyOfRange(result, 0, 16);
    result = XORBytes(result, block);    
   } else if (mode.equals("CFB")) {    
    result = encryptText(feedback, key);
    byte[] resultPart = Arrays.copyOfRange(result, 0, 8);
    byte[] blockPart = Arrays.copyOfRange(block, 0, 8);
    byte[] temp1 = XORBytes(resultPart, blockPart);
    feedback = mergeBytes(Arrays.copyOfRange(result, 8, 16), blockPart);     
    resultPart = Arrays.copyOfRange(result, 8, 16);
    blockPart = Arrays.copyOfRange(block, 8, 16);
    result = encryptText(feedback, key);
    byte[] temp2 = XORBytes(resultPart, blockPart);
    feedback = mergeBytes(Arrays.copyOfRange(result, 8, 16), blockPart);
    result = mergeBytes(temp1, temp2);
   } else {
    System.out.println("Unsupported mode of operation!");
    return null;
   }   
   //System.out.println("RESULT: ");
   //printBytes(result);
   for (j = 0 ; j < 16 && k < cipher.length; j++, k++) {
    cipher[k] = result[j];
   }
  }
  return cipher;  
 }
 
 private byte[] getInitializationVector() {
  return hexStringToByteArray("247D8AC4DDB1AA739DC593821D0BC432");   
 }
 
 private byte[] getInitializationVectorCFB() {
  return hexStringToByteArray("247D8AC4DDB1AA739DC593821D0BC432");   
 }
 
 private byte[] getNounce() {
//  char[] hexArray = "0123456789ABCDEF".toCharArray();
//  String nounceStr = "";
//  for (int i = 0 ; i < 16 ; i++) {
//   double random = Math.random();
//   int index = (int) (random * 16);
//   nounceStr += hexArray[index];   
//  }
//  return hexStringToByteArray(nounceStr);
  return hexStringToByteArray("247D8AC4DDB1AA739DC593821D0BC432");
 } 

 private byte[] mergeBytes(byte[] in1, byte[] in2) {
  byte[] out = new byte[in1.length + in2.length];
  int i = 0;
  for (int j = 0 ; j < in1.length ; j++) {
   out[i++] = in1[j];
  }
  for (int j = 0 ; j < in2.length ; j++) {
   out[i++] = in2[j];
  }
  return out;
 } 
}

Output
dhanoopbhaskar@dhanoop-laptop:~/workspace/Copy/crypto/run_aes$ java AESkeygen 
Key generated and saved in AESkey.txt 
dhanoopbhaskar@dhanoop-laptop:~/workspace/Copy/crypto/run_aes$ java AESencrypt 
Usage: java < classname > < mode > 
 < mode > := (ECB|CBC|OFB|CFB) 
dhanoopbhaskar@dhanoop-laptop:~/workspace/Copy/crypto/run_aes$ java AESencrypt ecb 
Encryption done! Please check AESciphertext.txt for output! 
dhanoopbhaskar@dhanoop-laptop:~/workspace/Copy/crypto/run_aes$ java AESdecrypt ecb 
Decryption done! Please check AESplaintext.txt for output! 
dhanoopbhaskar@dhanoop-laptop:~/workspace/Copy/crypto/run_aes$ java AESencrypt cbc 
Encryption done! Please check AESciphertext.txt for output! 
dhanoopbhaskar@dhanoop-laptop:~/workspace/Copy/crypto/run_aes$ java AESdecrypt cbc 
Decryption done! Please check AESplaintext.txt for output! 
dhanoopbhaskar@dhanoop-laptop:~/workspace/Copy/crypto/run_aes$ java AESencrypt ofb 
Encryption done! Please check AESciphertext.txt for output! 
dhanoopbhaskar@dhanoop-laptop:~/workspace/Copy/crypto/run_aes$ java AESdecrypt ofb 
Decryption done! Please check AESplaintext.txt for output! 
dhanoopbhaskar@dhanoop-laptop:~/workspace/Copy/crypto/run_aes$ java AESencrypt cfb 
Encryption done! Please check AESciphertext.txt for output! 
dhanoopbhaskar@dhanoop-laptop:~/workspace/Copy/crypto/run_aes$ java AESdecrypt cfb 
Decryption done! Please check AESplaintext.txt for output! 
dhanoopbhaskar@dhanoop-laptop:~/workspace/Copy/crypto/run_aes$

About Input/Output Files
AESkeygen.java - (output) AESkey.txt
AESencrypt.java - (input) AESkey.txt & AESplaintext.txt (output) AESciphertext.txt
AESdecrypt.java - (input) AESkey.txt & AESciphertext.txt (output) AESplaintext.txt

DES Implementation In Java with ECB | CBC | OFB | CFB Modes Of Operation

Note that these are ONLY basic level programs for easy understanding of the Data Encryption Standard (DES) algorithm

Key Generation - DESkeygen.java
 
import java.io.File;
import java.io.FileWriter;

public class DESkeygen {
 
 private final File file = new File("DESkey.txt");
 private final int KEY_LENGTH = 16;
 private final static char[] hexArray = "0123456789ABCDEF".toCharArray();
 
 public DESkeygen() {
  try {   
   FileWriter fileWriter = new FileWriter(file);
   fileWriter.write("");
   for (int i = 0 ; i < KEY_LENGTH ; i++) {
    double random = Math.random();
    int index = (int) (random * 16);
    fileWriter.append(hexArray[index]);
    fileWriter.flush();
   }
   fileWriter.close();
   System.out.println("Key generated and saved in " + file.getName());
  } catch(Exception exp) {
   exp.printStackTrace();
  }
 }
 
 public static void main(String[] args) {
  new DESkeygen();
 }

}

Encryption - DESencrypt.java
 
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.util.Arrays;


public class DESencrypt {
 
 private String mode = null;
 final protected static char[] hexArray = "0123456789ABCDEF".toCharArray();
 
 /* Initial Permutation */
 static final int[] IP = {
  58, 50, 42, 34, 26, 18, 10, 2,
  60, 52, 44, 36, 28, 20, 12, 4,
  62, 54, 46, 38, 30, 22, 14, 6,
  64, 56, 48, 40, 32, 24, 16, 8,
  57, 49, 41, 33, 25, 17,  9, 1,
  59, 51, 43, 35, 27, 19, 11, 3,
  61, 53, 45, 37, 29, 21, 13, 5,
  63, 55, 47, 39, 31, 23, 15, 7
 };
 /* Inverse Initial Permutation */
 static final int[] IIP = {
  40, 8, 48, 16, 56, 24, 64, 32,
  39, 7, 47, 15, 55, 23, 63, 31,
  38, 6, 46, 14, 54, 22, 62, 30,
  37, 5, 45, 13, 53, 21, 61, 29,
  36, 4, 44, 12, 52, 20, 60, 28,
  35, 3, 43, 11, 51, 19, 59, 27,
  34, 2, 42, 10, 50, 18, 58, 26,
  33, 1, 41,  9, 49, 17, 57, 25
 };
 /* Expansion Permutation */
 static final int[] E = {
  32,  1,  2,  3,  4,  5,
  4,  5,  6,  7,  8,  9,
  8,  9, 10, 11, 12, 13,
  12, 13, 14, 15, 16, 17,
  16, 17, 18, 19, 20, 21,
  20, 21, 22, 23, 24, 25,
  24, 25, 26, 27, 28, 29,
  28, 29, 30, 31, 32,  1
 };
 /* Permutation Function */
 static final int[] P = {
  16,  7, 20, 21,
  29, 12, 28, 17,
  1, 15, 23, 26,
  5, 18, 31, 10,
  2,  8, 24, 14,
  32, 27,  3,  9,
  19, 13, 30,  6,
  22, 11,  4, 25
 };
 /* S-Boxes*/
 static final int[] S1 = {
  14,  4, 13,  1,  2, 15, 11,  8,  3, 10,  6, 12,  5,  9,  0,  7,
   0, 15,  7,  4, 14,  2, 13,  1, 10,  6, 12, 11,  9,  5,  3,  8,
   4,  1, 14,  8, 13,  6,  2, 11, 15, 12,  9,  7,  3, 10,  5,  0,
  15, 12,  8,  2,  4,  9,  1,  7,  5, 11,  3, 14, 10,  0,  6, 13
 };
 static final int[] S2 = {
  15,  1,  8, 14,  6, 11,  3,  4,  9,  7,  2, 13, 12,  0,  5, 10,
   3, 13,  4,  7, 15,  2,  8, 14, 12,  0,  1, 10,  6,  9, 11,  5,
   0, 14,  7, 11, 10,  4, 13,  1,  5,  8, 12,  6,  9,  3,  2, 15,
  13,  8, 10,  1,  3, 15,  4,  2, 11,  6,  7, 12,  0,  5, 14,  9
 };
 static final int[] S3 = {
  10,  0,  9, 14,  6,  3, 15,  5,  1, 13, 12,  7, 11,  4,  2,  8,
  13,  7,  0,  9,  3,  4,  6, 10,  2,  8,  5, 14, 12, 11, 15,  1,
  13,  6,  4,  9,  8, 15,  3,  0, 11,  1,  2, 12,  5, 10, 14,  7,
   1, 10, 13,  0,  6,  9,  8,  7,  4, 15, 14,  3, 11,  5,  2, 12
 };
 static final int[] S4 = {
   7, 13, 14,  3,  0,  6,  9, 10,  1,  2,  8,  5, 11, 12,  4, 15,
  13,  8, 11,  5,  6, 15,  0,  3,  4,  7,  2, 12,  1, 10, 14,  9,
  10,  6,  9,  0, 12, 11,  7, 13, 15,  1,  3, 14,  5,  2,  8,  4,
   3, 15,  0,  6, 10,  1, 13,  8,  9,  4,  5, 11, 12,  7,  2, 14
 };
 static final int[] S5 = {
   2, 12,  4,  1,  7, 10, 11,  6,  8,  5,  3, 15, 13,  0, 14,  9,
  14, 11,  2, 12,  4,  7, 13,  1,  5,  0, 15, 10,  3,  9,  8,  6,
   4,  2,  1, 11, 10, 13,  7,  8, 15,  9, 12,  5,  6,  3,  0, 14,
  11,  8, 12,  7,  1, 14,  2, 13,  6, 15,  0,  9, 10,  4,  5,  3
 };
 static final int[] S6 = {
  12,  1, 10, 15,  9,  2,  6,  8,  0, 13,  3,  4, 14,  7,  5, 11,
  10, 15,  4,  2,  7, 12,  9,  5,  6,  1, 13, 14,  0, 11,  3,  8,
   9, 14, 15,  5,  2,  8, 12,  3,  7,  0,  4, 10,  1, 13, 11,  6,
   4,  3,  2, 12,  9,  5, 15, 10, 11, 14,  1,  7,  6,  0,  8, 13
 };
 static final int[] S7 = {
   4, 11,  2, 14, 15,  0,  8, 13,  3, 12,  9,  7,  5, 10,  6,  1,
  13,  0, 11,  7,  4,  9,  1, 10, 14,  3,  5, 12,  2, 15,  8,  6,
   1,  4, 11, 13, 12,  3,  7, 14, 10, 15,  6,  8,  0,  5,  9,  2,
   6, 11, 13,  8,  1,  4, 10,  7,  9,  5,  0, 15, 14,  2,  3, 12
 };
 static final int[] S8 = {
  13,  2,  8,  4,  6, 15, 11,  1, 10,  9,  3, 14,  5,  0, 12,  7,
   1, 15, 13,  8, 10,  3,  7,  4, 12,  5,  6, 11,  0, 14,  9,  2,
   7, 11,  4,  1,  9, 12, 14,  2,  0,  6, 10, 13, 15,  3,  5,  8,
   2,  1, 14,  7,  4, 10,  8, 13, 15, 12,  9,  0,  3,  5,  6, 11
 };
 /* Permuted Choice One */
 static final int[] PC1 = {
  57, 49, 41, 33, 25, 17,  9,
   1, 58, 50, 42, 34, 26, 18,
  10,  2, 59, 51, 43, 35, 27,
  19, 11,  3, 60, 52, 44, 36,
  63, 55, 47, 39, 31, 23, 15,
   7, 62, 54, 46, 38, 30, 22,
  14,  6, 61, 53, 45, 37, 29,
  21, 13,  5, 28, 20, 12,  4
 };
 /* Permuted Choice Two */
 static final int[] PC2 = {
  14, 17, 11, 24,  1,  5,
   3, 28, 15,  6, 21, 10,
  23, 19, 12,  4, 26,  8,
  16,  7, 27, 20, 13,  2,
  41, 52, 31, 37, 47, 55,
  30, 40, 51, 45, 33, 48,
  44, 49, 39, 56, 34, 53,
  46, 42, 50, 36, 29, 32
 };
 /* Schedule of Left Shifts */
 static final int[] SHIFTS = {
  1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1
 };
 
 public DESencrypt() {
  this.mode = "ECB";
 }
 
 public DESencrypt(String mode) {
  this.mode = mode;
 }
 
 private byte[] performXOR(byte[] one, byte[] two) {
  byte[] result = new byte[one.length];
  for (int i = 0 ; i < one.length ; i++) {
   result[i] = (byte) (one[i] ^ two[i]);
  }
  return result;
 }
 
 private byte[] permute(byte[] input, int[] mapping) {
  int byteCount = 1 + (mapping.length - 1) / 8;
  byte[] output = new byte[byteCount];
  int pos;
  
  for (int i = 0 ; i < mapping.length ; i++) {
   pos = mapping[i] - 1;
   int value = getBitFromArray(input, pos);
   setBitInArray(output, i, value);
  }  
  return output;
 } 

 private int getBitFromArray(byte[] array, int pos) {
  int value;
  int bytePos = pos / 8;
  int bitPos = pos % 8;  
  value = (array[bytePos] >> (8 - (bitPos + 1))) & 0x0001;  
  /* eg: right shift selected byte 5 times to get 3rd bit 
   * (bitPos = 2) at rightmost position and 
   * then AND with 0x0001*/
  return value;
 }
 
 private void setBitInArray(byte[] input, int pos, int value) {
  int bytePos = pos / 8;
  int bitPos = pos % 8;  
  byte old = input[bytePos];
  old = (byte) (((0xFF7F >> bitPos) & old) & 0x00FF);
  byte newByte = (byte) ((value << (8 - (bitPos + 1))) | old);
     input[bytePos] = newByte;
 }
 
 private byte[] hexStringToByteArray(String string) {
  int length = string.length();
  int n = (int)Math.ceil((length + 1) / 2);
  byte[] result = new byte[n];  
  for (int i = length - 1; i >= 0 ; i -= 2) { 
   if (i == 0) {
    result[i / 2] = (byte) ((Character.digit('0', 16) << 4)
      + Character.digit(string.charAt(i), 16));
   } else {
    result[i / 2] = (byte) ((Character.digit(string.charAt(i - 1), 16) << 4)
     + Character.digit(string.charAt(i), 16));
   }
  }
  return result;
 }
 
 public static String bytesToHex(byte[] bytes) {
     char[] hexChars = new char[bytes.length * 2];
     for ( int j = 0; j < bytes.length; j++ ) {
         int v = bytes[j] & 0xFF;
         hexChars[j * 2] = hexArray[v >>> 4];
         hexChars[j * 2 + 1] = hexArray[v & 0x0F];
     }
     return new String(hexChars);
 }
 
 private void printBytes(byte[] input) {    
  for (int i = 0 ; i < input.length; i++) {
   System.out.print(byteToBits(input[i]) + " ");
  }
  System.out.println();
 }
 
 private String byteToBits(byte b) {
  StringBuffer buffer = new StringBuffer();
  for (int i = 0 ; i < 8 ; i++)
   buffer.append((int)(b >> (8-(i+1)) & 0x0001));
  return buffer.toString();
 }

 private byte[] getBits(byte[] input, int startPos, int length) {
  int noOfBytes = (length-1)/8 + 1;
  byte[] output = new byte[noOfBytes];
  for (int i = 0 ; i < length ; i++) {
   int value = getBitFromArray(input, startPos + i);
   setBitInArray(output, i, value);
  }
  return output;
 } 
 
 private byte[] rotateLeft(byte[] input, int step, int length) {  
  int noOfBytes = (length - 1) / 8 + 1;
  byte[] output = new byte[noOfBytes];
  for (int i = 0 ; i < length ; i++) {
   int value = getBitFromArray(input, (i + step) % length);
   setBitInArray(output, i, value);
  }
  return output;
 }
 
 private byte[] concatBits(byte[] one, int oneLength, 
   byte[] two, int twoLength) {
  int noOfBytes = (oneLength + twoLength - 1) / 8 + 1;
  byte[] output = new byte[noOfBytes];
  int i = 0, j = 0;
  for (; i < oneLength ; i++) {
   int value = getBitFromArray(one, i);
   setBitInArray(output, j, value);
   j++;
  }  
  for (i = 0 ; i < twoLength ; i++) {
   int value = getBitFromArray(two, i);
   setBitInArray(output, j, value);
   j++;
  }
  return output;
 }
 
 private byte[][] getSubKeys(byte[] masterKey) {
  int noOfSubKeys = SHIFTS.length;
  int keySize = PC1.length;
  byte[] key = permute(masterKey, PC1);
  byte[][] subKeys = new byte[noOfSubKeys][keySize];
  byte[] leftHalf = getBits(key, 0, keySize/2);
  byte[] rightHalf = getBits(key, keySize/2, keySize/2);
  for (int i = 0 ; i < noOfSubKeys ; i++) {
   leftHalf = rotateLeft(leftHalf, SHIFTS[i], keySize/2);
   rightHalf = rotateLeft(rightHalf, SHIFTS[i], keySize/2);
   byte[] subKey = concatBits(leftHalf, keySize/2, rightHalf, keySize/2);
   subKeys[i] = permute(subKey, PC2); 
  }
  return subKeys;
 }
 
 public byte[] crypt(byte[] message, byte[] key, String operation) {
  if (message.length < 8) {
   System.out.println("Message should be atleast 64 bits");
   System.exit(1);
  }
  if (key.length != 8) {
   System.out.println("Key should be 64 bits");
   System.exit(1);
  }
  int length = message.length;
  int n = (length + 7)/8 * 8;
  byte[] cipher = new byte[n];
  if (length == 8) {
   if (mode.equals("ECB")) {
    return cryptText(message, key, operation);
   } else if (mode.equals("CBC")) {
    byte[] iv = getInitializationVector();
    message = XORBytes(message, iv);
    return cryptText(message, key, operation);
   } else if (mode.equals("OFB")) {
    byte[] nounce = getNounce();
    byte[] temp = cryptText(nounce, key, operation);
    byte[] result = XORBytes(temp, message);
    return result;
   } else if (mode.equals("CFB")) {
    
   } else {
    System.out.println("Unsupported mode of operation!");
    return null;
   }   
  }
  int i = 0;
  int k = 0;
  byte[] feedback = new byte[8];  
  if (mode.equals("CBC")) {
   feedback = getInitializationVector();
  } else if (mode.equals("OFB")) {
   feedback = getNounce();   
  } else if (mode.equals("CFB")) {
   feedback = getInitializationVectorCFB();
  }
  
  while (i < length) {
   byte[] block = new byte[8];
   byte[] result = new byte[8];
   int j = 0;
   for (; j < 8 && i < length; j++, i++) {
    block[j] = message[i];
   }
   while (j < 8) {
    /* pad with white spaces */
    block[j++] = 0x20;
   }
      
   //System.out.println("BLOCK: ");
   //printBytes(block);  
   if (mode.equals("ECB")) {
    result = cryptText(block, key, operation);
   } else if (mode.equals("CBC")) {
    if (operation.equals("encrypt")) {
     block = XORBytes(block, feedback);
     result = cryptText(block, key, operation);
     feedback = Arrays.copyOfRange(result, 0, 8);
    } else if (operation.equals("decrypt")) {
     result = cryptText(block, key, operation);
     result = XORBytes(result, feedback);
     feedback = Arrays.copyOfRange(block, 0, 8);
    }    
   } else if (mode.equals("OFB")) {
    result = cryptText(feedback, key, operation);
    feedback = Arrays.copyOfRange(result, 0, 8);
    result = XORBytes(result, block);    
   } else if (mode.equals("CFB")) {
    if (operation.equals("encrypt")) {
     result = cryptText(feedback, key, operation);
     byte[] resultPart = Arrays.copyOfRange(result, 0, 4);
     byte[] blockPart = Arrays.copyOfRange(block, 0, 4);
     byte[] temp1 = XORBytes(resultPart, blockPart);
     feedback = mergeBytes(Arrays.copyOfRange(result, 4, 8), temp1);     
     resultPart = Arrays.copyOfRange(result, 4, 8);
     blockPart = Arrays.copyOfRange(block, 4, 8);
     result = cryptText(feedback, key, operation);
     byte[] temp2 = XORBytes(resultPart, blockPart);
     feedback = mergeBytes(Arrays.copyOfRange(result, 4, 8), temp2);
     result = mergeBytes(temp1, temp2);
    } else if (operation.equals("decrypt")) {
     result = cryptText(feedback, key, "encrypt");
     byte[] resultPart = Arrays.copyOfRange(result, 0, 4);
     byte[] blockPart = Arrays.copyOfRange(block, 0, 4);
     byte[] temp1 = XORBytes(resultPart, blockPart);
     feedback = mergeBytes(Arrays.copyOfRange(result, 4, 8), blockPart);     
     resultPart = Arrays.copyOfRange(result, 4, 8);
     blockPart = Arrays.copyOfRange(block, 4, 8);
     result = cryptText(feedback, key, "encrypt");
     byte[] temp2 = XORBytes(resultPart, blockPart);
     feedback = mergeBytes(Arrays.copyOfRange(result, 4, 8), blockPart);
     result = mergeBytes(temp1, temp2);
    }    
   } else {
    System.out.println("Unsupported mode of operation!");
    return null;
   }   
   //System.out.println("RESULT: ");
   //printBytes(result);
   for (j = 0 ; j < 8 && k < cipher.length; j++, k++) {
    cipher[k] = result[j];
   }
  }
  return cipher;  
 }
 
 private byte[] getInitializationVector() {
  return hexStringToByteArray("DCBE6AE7EA5D5C61");   
 }
 
 private byte[] getInitializationVectorCFB() {
  return hexStringToByteArray("A5D5C61EFADB4351");   
 }
 
 private byte[] getNounce() {
//  char[] hexArray = "0123456789ABCDEF".toCharArray();
//  String nounceStr = "";
//  for (int i = 0 ; i < 16 ; i++) {
//   double random = Math.random();
//   int index = (int) (random * 16);
//   nounceStr += hexArray[index];   
//  }
//  return hexStringToByteArray(nounceStr);
  return hexStringToByteArray("DCBE6AE7EA5D5C61");
 } 

 private byte[] mergeBytes(byte[] in1, byte[] in2) {
  byte[] out = new byte[in1.length + in2.length];
  int i = 0;
  for (int j = 0 ; j < in1.length ; j++) {
   out[i++] = in1[j];
  }
  for (int j = 0 ; j < in2.length ; j++) {
   out[i++] = in2[j];
  }
  return out;
 }
 public byte[] cryptText(byte[] message, byte[] key, String operation) {
  if (message.length != 8) {
   System.out.println("Message should be 64 bits");
   System.exit(1);
  }
  if (key.length != 8) {
   System.out.println("Key should be 64 bits");
   System.exit(1);
  }
  byte[] result = null;
  int blockSize = IP.length;
  byte[][] subKeys = getSubKeys(key);
  int noOfRounds = subKeys.length;
  /**
   * Initial Permutation
   */
  message = permute(message, IP);
  /**
   * Split message into two halves
   */
  byte[] leftHalf = getBits(message, 0, blockSize/2);
  byte[] rightHalf = getBits(message, blockSize/2, blockSize/2);
  for (int i = 0 ; i < noOfRounds ; i++) {
   byte[] temp = rightHalf;
   /**
    * Expansion
    */
   rightHalf = permute(rightHalf, E);
   /**
    * XOR rightHalf with roundKey
    */
   byte[] roundKey = null;
   if (operation.equalsIgnoreCase("encrypt")) {
    roundKey = subKeys[i];
   } else if (operation.equalsIgnoreCase("decrypt")) {
    roundKey = subKeys[noOfRounds - i - 1];
   } else {
    System.out.println("Unsupported operation");
    System.exit(0);
   }
   rightHalf = performXOR(rightHalf, roundKey);
   /**
    * S-Box
    */
   rightHalf = sBox(rightHalf);
   /**
    * Permutation
    */
   rightHalf = permute(rightHalf, P);
   /**
    * XOR rightHalf with leftHalf
    */
   rightHalf = performXOR(rightHalf, leftHalf);
   /**
    * L(i) = R(i-1)
    */
   leftHalf = temp;
  }
  /**
   * 32 bit swap
   */
  byte[] concatHalves = concatBits(rightHalf, blockSize/2, leftHalf, blockSize/2);
  /**
   * Inverse Initial Permutation
   */
  result = permute(concatHalves, IIP);
  return result;
 }
 
 public static byte[] XORBytes(byte[] in1, byte[] in2) {  
  byte[] out = new byte[in1.length];
  for (int i = 0 ; i < in1.length ; i++) {
   out[i] = (byte)((in1[i] ^ in2[i]) & 0xff);
  }
  return out;
 }
 
 private byte[] sBox(byte[] input) {  
  /**
   * Split input to 6-bit blocks
   */
  input = split(input,6);
  byte[] output = new byte[input.length/2];
  int leftHalf = 0;  
  for (int i = 0; i < input.length ; i++) {
   byte block = input[i];   
   /**
    * row - first and last bits
    * column - 4 bits in the middle
    */
   int row = 2 * (block >> 7 & 0x0001) + (block >> 2 & 0x0001);
   int col = block >> 3 & 0x000F;
   int[] selectedSBox = getSBox(i);
   int rightHalf = selectedSBox[16 * row + col];
   if (i % 2 == 0) {
    leftHalf = rightHalf;
   } else {
    output[i/2] = (byte) (16 * leftHalf + rightHalf);
    leftHalf = 0;
   }
  }
  return output;
 }

 private int[] getSBox(int i) {
  switch (i) {
   case 0: return S1;
   case 1: return S2;
   case 2: return S3;
   case 3: return S4;
   case 4: return S5;
   case 5: return S6;
   case 6: return S7;
   case 7: return S8; 
   default: return null;   
  }
 }

 private byte[] split(byte[] input, int length) {
  int noOfBytes = (8 * input.length - 1) / length + 1;
  byte[] output = new byte[noOfBytes];
  for (int i = 0 ; i < noOfBytes ; i++) {
   for (int j = 0; j < length ; j++) {
    int value = getBitFromArray(input, length * i + j);    
    setBitInArray(output, 8 * i + j, value);
   }
  }
  return output;
 }

 public static void main(String[] args) {
  try {
   if (args.length != 1) {
    System.out.println("Usage: java < classname > < mode >"
      + "\n\t< mode > := (ECB|CBC|OFB|CFB)");
    return;
   }
   /* ECB, CBC, OFB, or CFB */   
   String mode = args[0];
   mode = mode.toUpperCase();
   DESencrypt des = new DESencrypt(mode); 
   File keyFile = new File("DESkey.txt");
   File textFile = new File("DESplaintext.txt");
   File cipherFile = new File("DESciphertext.txt");   
   FileReader keyFileReader = new FileReader(keyFile);
   BufferedReader bufferedReader = new BufferedReader(keyFileReader);
   FileInputStream textFileInputStream = new FileInputStream(textFile);
   FileOutputStream cipherFileOutputStream = new FileOutputStream(cipherFile);
   byte[] key = new byte[(int) keyFile.length()];
   String keyString = bufferedReader.readLine();
   key = des.hexStringToByteArray(keyString);
   byte[] message = new byte[(int) textFile.length()];
   textFileInputStream.read(message);        
   byte[] cipher = des.crypt(message, key, "encrypt");   
   cipherFileOutputStream.write(cipher);
   cipherFileOutputStream.flush();
   cipherFileOutputStream.close();
   bufferedReader.close();
   textFileInputStream.close();
   System.out.println("Encryption done! Please check DESciphertext.txt for output!");
  } catch(Exception exp) {
   exp.printStackTrace();
  }
 }
  
}

Decryption - DESdecrypt.java
 
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.util.Arrays;


public class DESdecrypt {
 
 private String mode = null;
 final protected static char[] hexArray = "0123456789ABCDEF".toCharArray();
 
 /* Initial Permutation */
 static final int[] IP = {
  58, 50, 42, 34, 26, 18, 10, 2,
  60, 52, 44, 36, 28, 20, 12, 4,
  62, 54, 46, 38, 30, 22, 14, 6,
  64, 56, 48, 40, 32, 24, 16, 8,
  57, 49, 41, 33, 25, 17,  9, 1,
  59, 51, 43, 35, 27, 19, 11, 3,
  61, 53, 45, 37, 29, 21, 13, 5,
  63, 55, 47, 39, 31, 23, 15, 7
 };
 /* Inverse Initial Permutation */
 static final int[] IIP = {
  40, 8, 48, 16, 56, 24, 64, 32,
  39, 7, 47, 15, 55, 23, 63, 31,
  38, 6, 46, 14, 54, 22, 62, 30,
  37, 5, 45, 13, 53, 21, 61, 29,
  36, 4, 44, 12, 52, 20, 60, 28,
  35, 3, 43, 11, 51, 19, 59, 27,
  34, 2, 42, 10, 50, 18, 58, 26,
  33, 1, 41,  9, 49, 17, 57, 25
 };
 /* Expansion Permutation */
 static final int[] E = {
  32,  1,  2,  3,  4,  5,
  4,  5,  6,  7,  8,  9,
  8,  9, 10, 11, 12, 13,
  12, 13, 14, 15, 16, 17,
  16, 17, 18, 19, 20, 21,
  20, 21, 22, 23, 24, 25,
  24, 25, 26, 27, 28, 29,
  28, 29, 30, 31, 32,  1
 };
 /* Permutation Function */
 static final int[] P = {
  16,  7, 20, 21,
  29, 12, 28, 17,
  1, 15, 23, 26,
  5, 18, 31, 10,
  2,  8, 24, 14,
  32, 27,  3,  9,
  19, 13, 30,  6,
  22, 11,  4, 25
 };
 /* S-Boxes*/
 static final int[] S1 = {
  14,  4, 13,  1,  2, 15, 11,  8,  3, 10,  6, 12,  5,  9,  0,  7,
   0, 15,  7,  4, 14,  2, 13,  1, 10,  6, 12, 11,  9,  5,  3,  8,
   4,  1, 14,  8, 13,  6,  2, 11, 15, 12,  9,  7,  3, 10,  5,  0,
  15, 12,  8,  2,  4,  9,  1,  7,  5, 11,  3, 14, 10,  0,  6, 13
 };
 static final int[] S2 = {
  15,  1,  8, 14,  6, 11,  3,  4,  9,  7,  2, 13, 12,  0,  5, 10,
   3, 13,  4,  7, 15,  2,  8, 14, 12,  0,  1, 10,  6,  9, 11,  5,
   0, 14,  7, 11, 10,  4, 13,  1,  5,  8, 12,  6,  9,  3,  2, 15,
  13,  8, 10,  1,  3, 15,  4,  2, 11,  6,  7, 12,  0,  5, 14,  9
 };
 static final int[] S3 = {
  10,  0,  9, 14,  6,  3, 15,  5,  1, 13, 12,  7, 11,  4,  2,  8,
  13,  7,  0,  9,  3,  4,  6, 10,  2,  8,  5, 14, 12, 11, 15,  1,
  13,  6,  4,  9,  8, 15,  3,  0, 11,  1,  2, 12,  5, 10, 14,  7,
   1, 10, 13,  0,  6,  9,  8,  7,  4, 15, 14,  3, 11,  5,  2, 12
 };
 static final int[] S4 = {
   7, 13, 14,  3,  0,  6,  9, 10,  1,  2,  8,  5, 11, 12,  4, 15,
  13,  8, 11,  5,  6, 15,  0,  3,  4,  7,  2, 12,  1, 10, 14,  9,
  10,  6,  9,  0, 12, 11,  7, 13, 15,  1,  3, 14,  5,  2,  8,  4,
   3, 15,  0,  6, 10,  1, 13,  8,  9,  4,  5, 11, 12,  7,  2, 14
 };
 static final int[] S5 = {
   2, 12,  4,  1,  7, 10, 11,  6,  8,  5,  3, 15, 13,  0, 14,  9,
  14, 11,  2, 12,  4,  7, 13,  1,  5,  0, 15, 10,  3,  9,  8,  6,
   4,  2,  1, 11, 10, 13,  7,  8, 15,  9, 12,  5,  6,  3,  0, 14,
  11,  8, 12,  7,  1, 14,  2, 13,  6, 15,  0,  9, 10,  4,  5,  3
 };
 static final int[] S6 = {
  12,  1, 10, 15,  9,  2,  6,  8,  0, 13,  3,  4, 14,  7,  5, 11,
  10, 15,  4,  2,  7, 12,  9,  5,  6,  1, 13, 14,  0, 11,  3,  8,
   9, 14, 15,  5,  2,  8, 12,  3,  7,  0,  4, 10,  1, 13, 11,  6,
   4,  3,  2, 12,  9,  5, 15, 10, 11, 14,  1,  7,  6,  0,  8, 13
 };
 static final int[] S7 = {
   4, 11,  2, 14, 15,  0,  8, 13,  3, 12,  9,  7,  5, 10,  6,  1,
  13,  0, 11,  7,  4,  9,  1, 10, 14,  3,  5, 12,  2, 15,  8,  6,
   1,  4, 11, 13, 12,  3,  7, 14, 10, 15,  6,  8,  0,  5,  9,  2,
   6, 11, 13,  8,  1,  4, 10,  7,  9,  5,  0, 15, 14,  2,  3, 12
 };
 static final int[] S8 = {
  13,  2,  8,  4,  6, 15, 11,  1, 10,  9,  3, 14,  5,  0, 12,  7,
   1, 15, 13,  8, 10,  3,  7,  4, 12,  5,  6, 11,  0, 14,  9,  2,
   7, 11,  4,  1,  9, 12, 14,  2,  0,  6, 10, 13, 15,  3,  5,  8,
   2,  1, 14,  7,  4, 10,  8, 13, 15, 12,  9,  0,  3,  5,  6, 11
 };
 /* Permuted Choice One */
 static final int[] PC1 = {
  57, 49, 41, 33, 25, 17,  9,
   1, 58, 50, 42, 34, 26, 18,
  10,  2, 59, 51, 43, 35, 27,
  19, 11,  3, 60, 52, 44, 36,
  63, 55, 47, 39, 31, 23, 15,
   7, 62, 54, 46, 38, 30, 22,
  14,  6, 61, 53, 45, 37, 29,
  21, 13,  5, 28, 20, 12,  4
 };
 /* Permuted Choice Two */
 static final int[] PC2 = {
  14, 17, 11, 24,  1,  5,
   3, 28, 15,  6, 21, 10,
  23, 19, 12,  4, 26,  8,
  16,  7, 27, 20, 13,  2,
  41, 52, 31, 37, 47, 55,
  30, 40, 51, 45, 33, 48,
  44, 49, 39, 56, 34, 53,
  46, 42, 50, 36, 29, 32
 };
 /* Schedule of Left Shifts */
 static final int[] SHIFTS = {
  1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1
 };
 
 public DESdecrypt() {
  this.mode = "ECB";
 }
 
 public DESdecrypt(String mode) {
  this.mode = mode;
 }
 
 private byte[] performXOR(byte[] one, byte[] two) {
  byte[] result = new byte[one.length];
  for (int i = 0 ; i < one.length ; i++) {
   result[i] = (byte) (one[i] ^ two[i]);
  }
  return result;
 }
 
 private byte[] permute(byte[] input, int[] mapping) {
  int byteCount = 1 + (mapping.length - 1) / 8;
  byte[] output = new byte[byteCount];
  int pos;
  
  for (int i = 0 ; i < mapping.length ; i++) {
   pos = mapping[i] - 1;
   int value = getBitFromArray(input, pos);
   setBitInArray(output, i, value);
  }  
  return output;
 } 

 private int getBitFromArray(byte[] array, int pos) {
  int value;
  int bytePos = pos / 8;
  int bitPos = pos % 8;  
  value = (array[bytePos] >> (8 - (bitPos + 1))) & 0x0001;  
  /* eg: right shift selected byte 5 times to get 3rd bit 
   * (bitPos = 2) at rightmost position and 
   * then AND with 0x0001*/
  return value;
 }
 
 private void setBitInArray(byte[] input, int pos, int value) {
  int bytePos = pos / 8;
  int bitPos = pos % 8;  
  byte old = input[bytePos];
  old = (byte) (((0xFF7F >> bitPos) & old) & 0x00FF);
  byte newByte = (byte) ((value << (8 - (bitPos + 1))) | old);
     input[bytePos] = newByte;
 }
 
 private byte[] hexStringToByteArray(String string) {
  int length = string.length();
  int n = (int)Math.ceil((length + 1) / 2);
  byte[] result = new byte[n];  
  for (int i = length - 1; i >= 0 ; i -= 2) { 
   if (i == 0) {
    result[i / 2] = (byte) ((Character.digit('0', 16) << 4)
      + Character.digit(string.charAt(i), 16));
   } else {
    result[i / 2] = (byte) ((Character.digit(string.charAt(i - 1), 16) << 4)
     + Character.digit(string.charAt(i), 16));
   }
  }
  return result;
 }
 
 public static String bytesToHex(byte[] bytes) {
     char[] hexChars = new char[bytes.length * 2];
     for ( int j = 0; j < bytes.length; j++ ) {
         int v = bytes[j] & 0xFF;
         hexChars[j * 2] = hexArray[v >>> 4];
         hexChars[j * 2 + 1] = hexArray[v & 0x0F];
     }
     return new String(hexChars);
 }
 
 private void printBytes(byte[] input) {    
  for (int i = 0 ; i < input.length; i++) {
   System.out.print(byteToBits(input[i]) + " ");
  }
  System.out.println();
 }
 
 private String byteToBits(byte b) {
  StringBuffer buffer = new StringBuffer();
  for (int i = 0 ; i < 8 ; i++)
   buffer.append((int)(b >> (8-(i+1)) & 0x0001));
  return buffer.toString();
 }

 private byte[] getBits(byte[] input, int startPos, int length) {
  int noOfBytes = (length-1)/8 + 1;
  byte[] output = new byte[noOfBytes];
  for (int i = 0 ; i < length ; i++) {
   int value = getBitFromArray(input, startPos + i);
   setBitInArray(output, i, value);
  }
  return output;
 } 
 
 private byte[] rotateLeft(byte[] input, int step, int length) {  
  int noOfBytes = (length - 1) / 8 + 1;
  byte[] output = new byte[noOfBytes];
  for (int i = 0 ; i < length ; i++) {
   int value = getBitFromArray(input, (i + step) % length);
   setBitInArray(output, i, value);
  }
  return output;
 }
 
 private byte[] concatBits(byte[] one, int oneLength, 
   byte[] two, int twoLength) {
  int noOfBytes = (oneLength + twoLength - 1) / 8 + 1;
  byte[] output = new byte[noOfBytes];
  int i = 0, j = 0;
  for (; i < oneLength ; i++) {
   int value = getBitFromArray(one, i);
   setBitInArray(output, j, value);
   j++;
  }  
  for (i = 0 ; i < twoLength ; i++) {
   int value = getBitFromArray(two, i);
   setBitInArray(output, j, value);
   j++;
  }
  return output;
 }
 
 private byte[][] getSubKeys(byte[] masterKey) {
  int noOfSubKeys = SHIFTS.length;
  int keySize = PC1.length;
  byte[] key = permute(masterKey, PC1);
  byte[][] subKeys = new byte[noOfSubKeys][keySize];
  byte[] leftHalf = getBits(key, 0, keySize/2);
  byte[] rightHalf = getBits(key, keySize/2, keySize/2);
  for (int i = 0 ; i < noOfSubKeys ; i++) {
   leftHalf = rotateLeft(leftHalf, SHIFTS[i], keySize/2);
   rightHalf = rotateLeft(rightHalf, SHIFTS[i], keySize/2);
   byte[] subKey = concatBits(leftHalf, keySize/2, rightHalf, keySize/2);
   subKeys[i] = permute(subKey, PC2); 
  }
  return subKeys;
 }
 
 public byte[] crypt(byte[] message, byte[] key, String operation) {
  if (message.length < 8) {
   System.out.println("Message should be atleast 64 bits");
   System.exit(1);
  }
  if (key.length != 8) {
   System.out.println("Key should be 64 bits");
   System.exit(1);
  }
  int length = message.length;
  int n = (length + 7)/8 * 8;
  byte[] cipher = new byte[n];
  if (length == 8) {
   if (mode.equals("ECB")) {
    return cryptText(message, key, operation);
   } else if (mode.equals("CBC")) {
    byte[] iv = getInitializationVector();
    message = XORBytes(message, iv);
    return cryptText(message, key, operation);
   } else if (mode.equals("OFB")) {    
    byte[] nounce = getNounce();
    byte[] temp = cryptText(nounce, key, "encrypt");
    byte[] result = XORBytes(temp, message);
    return result;
   } else if (mode.equals("CFB")) {
    
   } else {
    System.out.println("Unsupported mode of operation!");
    return null;
   }   
  }
  int i = 0;
  int k = 0;
  byte[] feedback = new byte[8];  
  if (mode.equals("CBC")) {
   feedback = getInitializationVector();
  } else if (mode.equals("OFB")) {
   feedback = getNounce();   
  } else if (mode.equals("CFB")) {
   feedback = getInitializationVectorCFB();
  }
  
  while (i < length) {
   byte[] block = new byte[8];
   byte[] result = new byte[8];
   int j = 0;
   for (; j < 8 && i < length; j++, i++) {
    block[j] = message[i];
   }
   while (j < 8) {
    /* pad with white spaces */
    block[j++] = 0x20;
   }
      
   //System.out.println("BLOCK: ");
   //printBytes(block);  
   if (mode.equals("ECB")) {
    result = cryptText(block, key, operation);
   } else if (mode.equals("CBC")) {
    if (operation.equals("encrypt")) {
     block = XORBytes(block, feedback);
     result = cryptText(block, key, operation);
     feedback = Arrays.copyOfRange(result, 0, 8);
    } else if (operation.equals("decrypt")) {
     result = cryptText(block, key, operation);
     result = XORBytes(result, feedback);
     feedback = Arrays.copyOfRange(block, 0, 8);
    }    
   } else if (mode.equals("OFB")) {
    result = cryptText(feedback, key, "encrypt");
    feedback = Arrays.copyOfRange(result, 0, 8);
    result = XORBytes(result, block);    
   } else if (mode.equals("CFB")) {
    if (operation.equals("encrypt")) {
     result = cryptText(feedback, key, operation);
     byte[] resultPart = Arrays.copyOfRange(result, 0, 4);
     byte[] blockPart = Arrays.copyOfRange(block, 0, 4);
     byte[] temp1 = XORBytes(resultPart, blockPart);
     feedback = mergeBytes(Arrays.copyOfRange(result, 4, 8), temp1);     
     resultPart = Arrays.copyOfRange(result, 4, 8);
     blockPart = Arrays.copyOfRange(block, 4, 8);
     result = cryptText(feedback, key, operation);
     byte[] temp2 = XORBytes(resultPart, blockPart);
     feedback = mergeBytes(Arrays.copyOfRange(result, 4, 8), temp2);
     result = mergeBytes(temp1, temp2);
    } else if (operation.equals("decrypt")) {
     result = cryptText(feedback, key, "encrypt");
     byte[] resultPart = Arrays.copyOfRange(result, 0, 4);
     byte[] blockPart = Arrays.copyOfRange(block, 0, 4);
     byte[] temp1 = XORBytes(resultPart, blockPart);
     feedback = mergeBytes(Arrays.copyOfRange(result, 4, 8), blockPart);     
     resultPart = Arrays.copyOfRange(result, 4, 8);
     blockPart = Arrays.copyOfRange(block, 4, 8);
     result = cryptText(feedback, key, "encrypt");
     byte[] temp2 = XORBytes(resultPart, blockPart);
     feedback = mergeBytes(Arrays.copyOfRange(result, 4, 8), blockPart);
     result = mergeBytes(temp1, temp2);
    }    
   } else {
    System.out.println("Unsupported mode of operation!");
    return null;
   }   
   //System.out.println("RESULT: ");
   //printBytes(result);
   for (j = 0 ; j < 8 && k < cipher.length; j++, k++) {
    cipher[k] = result[j];
   }
  }
  return cipher;  
 }
 
 private byte[] getInitializationVector() {
  return hexStringToByteArray("DCBE6AE7EA5D5C61");   
 }
 
 private byte[] getInitializationVectorCFB() {
  return hexStringToByteArray("A5D5C61EFADB4351");   
 }
 
 private byte[] getNounce() {
//  char[] hexArray = "0123456789ABCDEF".toCharArray();
//  String nounceStr = "";
//  for (int i = 0 ; i < 16 ; i++) {
//   double random = Math.random();
//   int index = (int) (random * 16);
//   nounceStr += hexArray[index];   
//  }
//  return hexStringToByteArray(nounceStr);
  return hexStringToByteArray("DCBE6AE7EA5D5C61");
 } 

 private byte[] mergeBytes(byte[] in1, byte[] in2) {
  byte[] out = new byte[in1.length + in2.length];
  int i = 0;
  for (int j = 0 ; j < in1.length ; j++) {
   out[i++] = in1[j];
  }
  for (int j = 0 ; j < in2.length ; j++) {
   out[i++] = in2[j];
  }
  return out;
 }
 public byte[] cryptText(byte[] message, byte[] key, String operation) {
  if (message.length != 8) {
   System.out.println("Message should be 64 bits");
   System.exit(1);
  }
  if (key.length != 8) {
   System.out.println("Key should be 64 bits");
   System.exit(1);
  }
  byte[] result = null;
  int blockSize = IP.length;
  byte[][] subKeys = getSubKeys(key);
  int noOfRounds = subKeys.length;
  /**
   * Initial Permutation
   */
  message = permute(message, IP);
  /**
   * Split message into two halves
   */
  byte[] leftHalf = getBits(message, 0, blockSize/2);
  byte[] rightHalf = getBits(message, blockSize/2, blockSize/2);
  for (int i = 0 ; i < noOfRounds ; i++) {
   byte[] temp = rightHalf;
   /**
    * Expansion
    */
   rightHalf = permute(rightHalf, E);
   /**
    * XOR rightHalf with roundKey
    */
   byte[] roundKey = null;
   if (operation.equalsIgnoreCase("encrypt")) {
    roundKey = subKeys[i];
   } else if (operation.equalsIgnoreCase("decrypt")) {
    roundKey = subKeys[noOfRounds - i - 1];
   } else {
    System.out.println("Unsupported operation");
    System.exit(0);
   }
   rightHalf = performXOR(rightHalf, roundKey);
   /**
    * S-Box
    */
   rightHalf = sBox(rightHalf);
   /**
    * Permutation
    */
   rightHalf = permute(rightHalf, P);
   /**
    * XOR rightHalf with leftHalf
    */
   rightHalf = performXOR(rightHalf, leftHalf);
   /**
    * L(i) = R(i-1)
    */
   leftHalf = temp;
  }
  /**
   * 32 bit swap
   */
  byte[] concatHalves = concatBits(rightHalf, blockSize/2, leftHalf, blockSize/2);
  /**
   * Inverse Initial Permutation
   */
  result = permute(concatHalves, IIP);
  return result;
 }
 
 public static byte[] XORBytes(byte[] in1, byte[] in2) {  
  byte[] out = new byte[in1.length];
  for (int i = 0 ; i < in1.length ; i++) {
   out[i] = (byte)((in1[i] ^ in2[i]) & 0xff);
  }
  return out;
 }
 
 private byte[] sBox(byte[] input) {  
  /**
   * Split input to 6-bit blocks
   */
  input = split(input,6);
  byte[] output = new byte[input.length/2];
  int leftHalf = 0;  
  for (int i = 0; i < input.length ; i++) {
   byte block = input[i];   
   /**
    * row - first and last bits
    * column - 4 bits in the middle
    */
   int row = 2 * (block >> 7 & 0x0001) + (block >> 2 & 0x0001);
   int col = block >> 3 & 0x000F;
   int[] selectedSBox = getSBox(i);
   int rightHalf = selectedSBox[16 * row + col];
   if (i % 2 == 0) {
    leftHalf = rightHalf;
   } else {
    output[i/2] = (byte) (16 * leftHalf + rightHalf);
    leftHalf = 0;
   }
  }
  return output;
 }

 private int[] getSBox(int i) {
  switch (i) {
   case 0: return S1;
   case 1: return S2;
   case 2: return S3;
   case 3: return S4;
   case 4: return S5;
   case 5: return S6;
   case 6: return S7;
   case 7: return S8; 
   default: return null;   
  }
 }

 private byte[] split(byte[] input, int length) {
  int noOfBytes = (8 * input.length - 1) / length + 1;
  byte[] output = new byte[noOfBytes];
  for (int i = 0 ; i < noOfBytes ; i++) {
   for (int j = 0; j < length ; j++) {
    int value = getBitFromArray(input, length * i + j);    
    setBitInArray(output, 8 * i + j, value);
   }
  }
  return output;
 }

 public static void main(String[] args) {
  try {
   if (args.length != 1) {
    System.out.println("Usage: java < classname > < mode >"
      + "\n\t< mode > := (ECB|CBC|OFB|CFB)");
    return;
   }
   /* ECB, CBC, OFB, or CFB */
   String mode = args[0];
   mode = mode.toUpperCase();
   DESdecrypt des = new DESdecrypt(mode); 
   File keyFile = new File("DESkey.txt");
   File textFile = new File("DESplaintext.txt");
   File cipherFile = new File("DESciphertext.txt");   
   FileReader keyFileReader = new FileReader(keyFile);
   BufferedReader bufferedReader = new BufferedReader(keyFileReader);
   FileInputStream cipherFileInputStream = new FileInputStream(cipherFile);
   FileOutputStream textFileOutputStream = new FileOutputStream(textFile);
   byte[] key = new byte[(int) keyFile.length()];
   String keyString = bufferedReader.readLine();
   key = des.hexStringToByteArray(keyString);
   byte[] cipher = new byte[(int) cipherFile.length()];
   cipherFileInputStream.read(cipher);        
   byte[] message = des.crypt(cipher, key, "decrypt");   
   textFileOutputStream.write(message);
   textFileOutputStream.flush();
   textFileOutputStream.close();
   bufferedReader.close();
   cipherFileInputStream.close();
   System.out.println("Decryption done! Please check DESplaintext.txt for output!");
  } catch(Exception exp) {
   exp.printStackTrace();
  }
 }
  
}

Output
dhanoopbhaskar@dhanoop-laptop:~/workspace$ java DESkeygen
Key generated and saved in DESkey.txt
dhanoopbhaskar@dhanoop-laptop:~/workspace$ java DESencrypt
Usage: java <classname> <mode>
<mode> := (ECB|CBC|OFB|CFB)
dhanoopbhaskar@dhanoop-laptop:~/workspace$ java DESencrypt ecb
Encryption done! Please check DESciphertext.txt for output!
dhanoopbhaskar@dhanoop-laptop:~/workspace$ java DESdecrypt ecb
Decryption done! Please check DESplaintext.txt for output!
dhanoopbhaskar@dhanoop-laptop:~/workspace$ java DESencrypt cbc
Encryption done! Please check DESciphertext.txt for output!
dhanoopbhaskar@dhanoop-laptop:~/workspace$ java DESdecrypt cbc
Decryption done! Please check DESplaintext.txt for output!
dhanoopbhaskar@dhanoop-laptop:~/workspace$ java DESencrypt ofb
Encryption done! Please check DESciphertext.txt for output!
dhanoopbhaskar@dhanoop-laptop:~/workspace$ java DESdecrypt ofb
Decryption done! Please check DESplaintext.txt for output!
dhanoopbhaskar@dhanoop-laptop:~/workspace$ java DESencrypt cfb
Encryption done! Please check DESciphertext.txt for output!
dhanoopbhaskar@dhanoop-laptop:~/workspace$ java DESdecrypt cfb
Decryption done! Please check DESplaintext.txt for output!
dhanoopbhaskar@dhanoop-laptop:~/workspace$ java DESdecrypt cfb
Decryption done! Please check DESplaintext.txt for output!
dhanoopbhaskar@dhanoop-laptop:~/workspace$ 

About Input/Output Files
DESkeygen.java - (output) DESkey.txt 

DESencrypt.java - (input) DESkey.txt & DESplaintext.txt (output) DESciphertext.txt 
DESdecrypt.java - (input) DESkey.txt & DESciphertext.txt (output) DESplaintext.txt

Contact Form

Name

Email *

Message *