## 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;
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.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
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 */
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");
FileInputStream textFileInputStream = new FileInputStream(textFile);
FileOutputStream cipherFileOutputStream = new FileOutputStream(cipherFile);
byte[] key = new byte[(int) keyFile.length()];
key = aes.hexStringToByteArray(keyString);
byte[] message = new byte[(int) textFile.length()];
byte[] cipher = aes.encrypt(message, key);
cipherFileOutputStream.write(cipher);
cipherFileOutputStream.flush();
cipherFileOutputStream.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.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
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 */
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");
FileInputStream cipherFileInputStream = new FileInputStream(cipherFile);
FileOutputStream textFileOutputStream = new FileOutputStream(textFile);
byte[] key = new byte[(int) keyFile.length()];
key = aes.hexStringToByteArray(keyString);
byte[] cipher = new byte[(int) cipherFile.length()];
byte[] message = aes.decrypt(cipher, key);
textFileOutputStream.write(message);
textFileOutputStream.flush();
textFileOutputStream.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
Key generated and saved in AESkey.txt
Usage: java < classname > < mode >
< mode > := (ECB|CBC|OFB|CFB)
Encryption done! Please check AESciphertext.txt for output!
Decryption done! Please check AESplaintext.txt for output!
Encryption done! Please check AESciphertext.txt for output!
Decryption done! Please check AESplaintext.txt for output!
Encryption done! Please check AESciphertext.txt for output!
Decryption done! Please check AESplaintext.txt for output!
Encryption done! Please check AESciphertext.txt for output!
Decryption done! Please check AESplaintext.txt for output!

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.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
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() {
}

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");
FileInputStream textFileInputStream = new FileInputStream(textFile);
FileOutputStream cipherFileOutputStream = new FileOutputStream(cipherFile);
byte[] key = new byte[(int) keyFile.length()];
key = des.hexStringToByteArray(keyString);
byte[] message = new byte[(int) textFile.length()];
byte[] cipher = des.crypt(message, key, "encrypt");
cipherFileOutputStream.write(cipher);
cipherFileOutputStream.flush();
cipherFileOutputStream.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.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
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() {
}

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");
FileInputStream cipherFileInputStream = new FileInputStream(cipherFile);
FileOutputStream textFileOutputStream = new FileOutputStream(textFile);
byte[] key = new byte[(int) keyFile.length()];
key = des.hexStringToByteArray(keyString);
byte[] cipher = new byte[(int) cipherFile.length()];
byte[] message = des.crypt(cipher, key, "decrypt");
textFileOutputStream.write(message);
textFileOutputStream.flush();
textFileOutputStream.close();
cipherFileInputStream.close();
System.out.println("Decryption done! Please check DESplaintext.txt for output!");
} catch(Exception exp) {
exp.printStackTrace();
}
}

}
```

Output
Key generated and saved in DESkey.txt
Usage: java <classname> <mode>
<mode> := (ECB|CBC|OFB|CFB)
Encryption done! Please check DESciphertext.txt for output!
Decryption done! Please check DESplaintext.txt for output!
Encryption done! Please check DESciphertext.txt for output!
Decryption done! Please check DESplaintext.txt for output!
Encryption done! Please check DESciphertext.txt for output!
Decryption done! Please check DESplaintext.txt for output!
Encryption done! Please check DESciphertext.txt for output!
Decryption done! Please check DESplaintext.txt for output!
Decryption done! Please check DESplaintext.txt for output!

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

### AES Implementation in Java

AES.java

```
import java.util.Arrays;

public class AES {

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;

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 AES() {
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 */
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[BLOCK_LENGTH];
for (int i = 0 ; i < BLOCK_LENGTH ; i++) {
out[i] = (byte)((in1[i] ^ in2[i]) & 0xff);
}
return out;
}

public byte[] encrypt(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[] decrypt(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 {
AES aes = new AES();
byte[] plainText = aes.hexStringToByteArray("0123456789abcdeffedcba9876543210");
System.out.println("PLAIN TEXT: " + bytesToHex(plainText));
System.out.println("KEY: " + bytesToHex(key));
byte[] cipher = aes.encrypt(plainText, key);
System.out.println("CIPHER TEXT: " + bytesToHex(cipher));
plainText = aes.decrypt(cipher, key);
System.out.println("DECRYPTED CIPHER TEXT: " + bytesToHex(plainText));

}
}
```
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) AES.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 AES.bytesToHex(this.getWord());
}
}

```
Output

PLAIN TEXT: 0123456789ABCDEFFEDCBA9876543210
CIPHER TEXT: FF0B844A0853BF7C6934AB4364148FB9
DECRYPTED CIPHER TEXT: 0123456789ABCDEFFEDCBA9876543210

## Contact Form

Name

Email *

Message *

### 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 mo...