diff --git a/src/java/BlockCipher.java b/src/java/BlockCipher.java new file mode 100644 index 0000000..1794d4a --- /dev/null +++ b/src/java/BlockCipher.java @@ -0,0 +1,41 @@ +package src.java; + +public interface BlockCipher +{ + +/** + * Returns this block cipher's block size in bytes. + * + * @return Block size. + */ +public int blockSize(); + +/** + * Returns this block cipher's key size in bytes. + * + * @return Key size. + */ +public int keySize(); + +/** + * Set the key for this block cipher. key must be an array of bytes + * whose length is equal to keySize(). + * + * @param key Key. + */ +public void setKey + (byte[] key); + +/** + * src.java.Encrypt the given plaintext. text must be an array of bytes + * whose length is equal to blockSize(). On input, text + * contains the plaintext block. The plaintext block is encrypted using the + * key specified in the most recent call to setKey(). On output, + * text contains the ciphertext block. + * + * @param text Plaintext (on input), ciphertext (on output). + */ +public void encrypt + (byte[] text); + +} \ No newline at end of file diff --git a/src/java/Decrypt.java b/src/java/Decrypt.java new file mode 100644 index 0000000..cbbd366 --- /dev/null +++ b/src/java/Decrypt.java @@ -0,0 +1,206 @@ +package src.java; /** + * src.java.Decrypt.java + * version : ak + * Revision: $log ak$ + */ + +import src.java.utils.Utils; + +/** + * This program is an implementation of block cipher Speck. + * It decrypts the given ciphertext by XORing with key generated + * from 22 round key scheduler + * + * @author Ajinkya Kale + * + */ + +public class Decrypt { + + short [] k0= new short[22]; // stores subkeys + short [] l0 =new short [22]; // stores L0 values + short [] l1 = new short[22]; // stores L1 values + short [] l2 = new short [22]; // stores L2 values + byte[] key; // stoes key + byte[] plaintext; // stores plaintext + + /** + * Constructor initilizing key and plaintext + */ + public Decrypt(byte [] key, byte []plaintext) { + this.key= key; + this.plaintext=plaintext; + } + + + /** + * This method sets the initial values of the key k0,lo,l1,l2 + */ + + public void setKey(byte[] key) { + long key_1= Utils.packLongBigEndian(key, 0); + k0[0]= (short)(key_1 & 0x000000000000FFFFL); + l0[0]= (short)((key_1 & 0x00000000FFFF0000L)>>16); + l1[0]= (short)((key_1 & 0x0000FFFF00000000L)>>32); + l2[0]= (short)((key_1 & 0xFFFF000000000000L)>>48); + } + + /** + * returns blocksize + */ + + public int blockSize() { + return 32; + } + + /** + * returns keysize + */ + + public int keySize() { + return 64; + } + + /** + * This method produceds 22 subkeys required to generate ciphertext + * + */ + public void key_schedule1(){ + int count=1; + int l=1,k=1,m=1,j=1; + int first=0, second=0, third=0; + for(int i=0; i<21;i++){ + if( count==1){ + l0[l]= (short)((k0[i] + l_right_rotate(l0[first]))^ (short)i); + k0[j] = (short)( k_left_rotate(k0[i])^ l0[l]); + l++; + j++; + first++; + } + + if(count ==2){ + l1[k]= (short) ((k0[i] + l_right_rotate(l1[second]))^ (short)i); + k0[j] =(short) ( k_left_rotate(k0[i]) ^ l1[k]); + k++; + j++; + second++; + } + if(count == 3){ + l2[m]= (short) ((k0[i] +l_right_rotate(l2[third]))^(short)i); + k0[j]= (short) ((k_left_rotate(k0[i])) ^ l2[m]); + m++; + j++; + third++; + } + count++; + if(count>3){ + count=1; + } + } + } + + /** + * This method perfoms right rotation by 7 + * @param s + * @return temp + */ + private short l_right_rotate(short s) { + short x= (short) ((s& 0x0000FFFF)>>7); + short y= (short) ((s& 0x0000FFFF)<<9); + short temp = (short) (y|x); + return temp; + } + + /** + * This method performs left rotation by 2 + * @param s + * @return temp + */ + private short k_left_rotate(short s){ + short y= (short)( (s& 0x0000FFFF)<<2); + short x= (short)((s& 0x0000FFFF)>>14); + short temp = (short) (y|x); + return temp; + } + + /** + * This method performs right rotate vy 2 positions + * @param s + * @return temp + */ + private short right_rotate_by_2(short s){ + short y= (short)( (s& 0x0000FFFF)>>2); + short x= (short)((s& 0x0000FFFF)<<14); + short temp = (short) (y|x); + return temp; + } + + /** + * This method perform left rotation by 7 + * @param s + * @return temp + */ + private short left_rotate_by_7(short s){ + short x= (short) ((s& 0x0000FFFF)<<7); + short y= (short) ((s& 0x0000FFFF)>>9); + short temp = (short) (y|x); + return temp; + } + + /** + * This method decrypts the ciphertext using the subkey in reverse order. + * Decryption consists of 22 rounds + */ + + public void decrypt(byte [] text){ + int dec=0; + int ciphertext = Utils.packIntBigEndian(text, 0); + short x = (short) ((ciphertext & 0xFFFF0000)>>16); + short y = (short) ((ciphertext & 0x0000FFFF)); + + for(int i=21; i>=0 ; i--){ + short value1= (short)(x ^ y); + y= right_rotate_by_2((short)(x ^ y)); + short value2= (short) (x ^ k0[i]); + short value3 = (short)((x ^ k0[i])- y); + x= (short)(left_rotate_by_7((short)((x ^ k0[i])- y))); + dec = x<<16 | ( y&0x0000FFFF); + + } + byte[] temp2 = Utils.toByteArray(Utils.toString(dec)); + text[0]= temp2[0]; + text[1]= temp2[1]; + text[2]= temp2[2]; + text[3]= temp2[3]; + + } + + /** + *This method is executed if args are not sufficient. + * program exits here. + */ + private static void usage() { + System.err.println ("Usage: java src.java.EncryptFile "); + System.err.println (" = ciphertext file name"); + System.err.println (" = Key (64 hex digits)"); + System.exit (1); + } + /** + * This is main program + * @param args commandline arguments + */ + public static void main(String[] args) { + if(args.length !=2){ + usage(); + } + byte[] key =Utils.toByteArray(args[0]); + byte[] plaintext = Utils.toByteArray(args[1]); + Decrypt s= new Decrypt(key, plaintext); + s.setKey(key); + s.key_schedule1(); + s.decrypt(plaintext); + System.out.println(Utils.toString(plaintext)); // this prints the plaintext output + + } + +} diff --git a/src/java/DecryptFile.java b/src/java/DecryptFile.java new file mode 100644 index 0000000..f1b859e --- /dev/null +++ b/src/java/DecryptFile.java @@ -0,0 +1,122 @@ +package src.java;/* + * src.java.Encrypt.java + * Version : $ak$ + * Revision: log $ak$ + */ + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; +import src.java.utils.Utils; + +/** + * This program Decrypts the file, in ECB mode. + * This is an implementation of block cipher SPECK + * @author Ajinkya Kale + * + */ + +public class DecryptFile { + /** + * This is main program + * @param args commandline arguments + */ + public static void main(String[] args) throws IOException{ + if(args.length!=3){ + usage(); + } + + + File plaintext= new File (args[1]); // plaintext file + File ciphertext= new File( args[2]); // cipher text file + byte [] key = Utils.toByteArray(args[0]); // key + InputStream cipher_t= new BufferedInputStream + (new FileInputStream (plaintext)); + OutputStream plain_t = new BufferedOutputStream + (new FileOutputStream (ciphertext)); + + Path path = Paths.get(plaintext.getAbsolutePath()); + byte [] p = Files.readAllBytes(path); // reads all the bytes of file + + Decrypt e = new Decrypt(key, p); + e.setKey(key); // sets the key + e.key_schedule1(); // generates subkeys + + int iter=0; + while( iter != p.length){ // decrypts the 4 bytes at a time + int prev= iter; + byte [] temp = {(byte) (p[iter]) ,(byte)(p[++iter]), (byte)(p[++iter]), (byte)(p[++iter])}; + int temp2= Utils.packIntBigEndian(temp, 0); + Utils.unpackIntBigEndian(temp2, temp, 0); + e.decrypt(temp); + p[prev]= temp[0]; + p[++prev]= temp[1]; + p[++prev]= temp[2]; + p[++prev]= temp[3]; + prev=0; + iter++; + } + + byte [] t = remove_padding(p); // orginaml plaintext without padding + // writies plaintext without padding to the file + int c=0; + while(c!= t.length){ + plain_t.write(t[c]); + c++; + } + plain_t.close(); + cipher_t.close(); + + } + + /** + * This method removes padding from ciphertext + * @param ciphertext byte array + * @return temp + */ + public static byte[] remove_padding(byte [] ciphertext_ ){ + int i=ciphertext_.length-1; + int counter=0; + List u = new ArrayList(); + byte[] temp; + + while(ciphertext_[i]== 0x0000){ + counter++; + i--; + } + + + for( int j=0; j<(ciphertext_.length-(counter+1)); j++){ + u.add(ciphertext_[j]); + } + + temp= new byte[ciphertext_.length-(counter+1)]; + + for(int k=0; k< temp.length; k++){ + temp[k]= u.get(k); + } + return temp; + + } + + /** + * Print a usage message and exit. + */ + private static void usage() { + System.err.println ("Usage: java src.java.DecryptFile "); + System.err.println ("<ptfile> = Plaintext file name"); + System.err.println ("<ctfile> = Ciphertext file name"); + System.err.println ("<key> = Key(64 hex digits)"); + System.exit (1); + } +} diff --git a/src/java/Encrypt.java b/src/java/Encrypt.java new file mode 100644 index 0000000..1f84407 --- /dev/null +++ b/src/java/Encrypt.java @@ -0,0 +1,171 @@ +package src.java;/* + * src.java.Encrypt.java + * Version : $ak$ + * Revision: log $ak$ + */ + + +import src.java.utils.Utils; + +/** + * This program is an implementation of block cipher Speck. + * It encryptes the given plaintext by XORing with key generated + * from 22 round key scheduler + * + * @author Ajinkya Kale + * + */ +public class Encrypt implements BlockCipher{ + + short [] k0= new short[22]; // stores subkeys Ki + short [] l0 =new short [22]; // stores L0 values, 16 bits of key + short [] l1 = new short[22]; // stores L1 values, 16 bits of key + short [] l2 = new short [22];// stores L2 values, 16 bits of key + byte [] plaintext; // stores plaintext + byte[] key; // stores key + + /** + * consturctor initializes the key and plaintext + */ + public Encrypt(byte [] key, byte []plaintext) { + this.key= key; + this.plaintext=plaintext; + } + + /** + * returns blocksize + */ + public int blockSize() { + return 32; + } + /** + * returns keysize + */ + public int keySize() { + return 64; + } + + /** + * This method sets the initial values of the key K0,L0,L1,L2 + */ + + public void setKey(byte[] key) { + long key_1= Utils.packLongBigEndian(key, 0); + k0[0]= (short)(key_1 & 0x000000000000FFFFL); + l0[0]= (short)((key_1 & 0x00000000FFFF0000L)>>16); + l1[0]= (short)((key_1 & 0x0000FFFF00000000L)>>32); + l2[0]= (short)((key_1 & 0xFFFF000000000000L)>>48); + } + + + /** + * This method encrypts the plaintext using the subkey. + * Encryption consists of 22 rounds + */ + public void encrypt(byte[] text) { + int you =0; + int plaintext = Utils.packIntBigEndian(text, 0); + short x =(short)((plaintext & 0xFFFF0000)>>16) ; + short y =(short)((plaintext & 0x0000FFFF)); + for(int i=0; i<22 ;i++){ + x= (short) ((( l_right_rotate(x) + y)^ this.k0[i]) ); + y = (short) (k_left_rotate(y)^x); + you = x<<16|(y & 0x0000FFFF); + } + Utils.unpackIntBigEndian (you, text, 0); + + } + + /** + * This method produceds the 22 subkeys required to generate ciphertext + * + */ + public void key_schedule(){ + + int count=1; // marker + int l=1,k=1,m=1,j=1; // index for l0, l1, l2 and k respetively + int first=0, second=0, third=0; + for(int i=0; i<21;i++){ // rounds + if( count==1){ + l0[l]= (short)((k0[i] + l_right_rotate(l0[first]))^ (short)i);// GF addition is nothing but XOR + k0[j] = (short)( k_left_rotate(k0[i])^ l0[l]); + l++; + j++; + first++; + } + + if(count ==2){ + l1[k]= (short) ((k0[i] + l_right_rotate(l1[second]))^ (short)i); + k0[j] =(short) ( k_left_rotate(k0[i]) ^ l1[k]); + k++; + j++; + second++; + } + if(count == 3){ + l2[m]= (short) ((k0[i] +l_right_rotate(l2[third]))^(short)i); + k0[j]= (short) ((k_left_rotate(k0[i])) ^ l2[m]); + m++; + j++; + third++; + } + count++; + if(count>3){ + count=1; + } + } + } + + /** + * This method performs right rotation. + * @param s + * @return temp + */ + + private short l_right_rotate(short s) { + short x= (short) ((s& 0x0000FFFF)>>7); + short y= (short) ((s& 0x0000FFFF)<<9); + short temp = (short) (y|x); + return temp; + } + + /** + * This method perform left rotation. + * @param s + * @return temp + */ + private short k_left_rotate(short s){ + short y= (short)( (s& 0x0000FFFF)<<2); + short x= (short)((s& 0x0000FFFF)>>14); + short temp = (short) (y|x); + return temp; + } + + /** + * Prints the useage error message + */ + private static void usage(){ + System.err.println ("Usage: java src.java.EncryptFile <key> <plaintext>"); + System.err.println ("<ptfile> = Plaintext file name"); + System.err.println ("<key> = Key (64 hex digits)"); + System.exit (1); + } + + /** + * This is main program + * @param args commandline arguments + */ + public static void main(String[] args) { + if(args.length !=2){ + usage(); + } + byte[] key = Utils.toByteArray(args[0]); + byte[] plaintext = Utils.toByteArray(args[1]); + Encrypt s= new Encrypt(key, plaintext); + s.setKey(key); + s.key_schedule(); + s.encrypt(plaintext); + System.out.println(Utils.toString(plaintext)); // printing the ciphertext output + + } + +} diff --git a/src/java/EncryptFile.java b/src/java/EncryptFile.java new file mode 100644 index 0000000..54c282f --- /dev/null +++ b/src/java/EncryptFile.java @@ -0,0 +1,116 @@ +package src.java;/* + * src.java.Encrypt.java + * Version : $ak$ + * Revision: log $ak$ +*/ + +import src.java.utils.Utils; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; + +/** + * This program encrypts the file, in ECB mode. + * This is an implementation of bloack cipher SPECK + * @author Ajinkya Kale + * + */ + +public class EncryptFile { + /** + * This is main program + * @param args commandline arguments + */ + public static void main(String[] args) throws IOException{ + + if( args.length!=3){ + usage(); + } + File plaintext= new File (args[1]); // plaintext file + + File ciphertext= new File( args[2]); // ciphertext file in which ciphertext will be stored + byte [] key = Utils.toByteArray(args[0]); // key for encryption + + InputStream plain_t = new BufferedInputStream + (new FileInputStream (plaintext)); + OutputStream cipher_t = new BufferedOutputStream + (new FileOutputStream (ciphertext)); + + Path path = Paths.get(plaintext.getAbsolutePath()); + byte[] p = Files.readAllBytes(path); // reads all bytes from file + + List<Byte> d = new ArrayList<Byte>(); + for( int i=0 ;i< p.length;i++){ + d.add(p[i]); + } + d.add((byte) 0x80); // adding padding + + if(d.size() % 4 !=0){ // padding + while(d.size()%4 !=0 ){ + d.add((byte)0x00); + } + } + byte [] padded = (byte[])pad_array(d); // padded array of bytes + int len = padded.length; + Encrypt e = new Encrypt(key, padded); + e.setKey(key); // sets the key + e.key_schedule(); // generates 22 subkyes + int iter=0; + while( iter != padded.length){ // encrytion of 4 bytes ata time + int prev= iter; + byte [] temp = {(byte) (padded[iter]) ,(byte)(padded[++iter]), (byte)(padded[++iter]), (byte)(padded[++iter])}; + int temp2= Utils.packIntBigEndian(temp, 0); + Utils.unpackIntBigEndian(temp2, temp, 0); + e.encrypt(temp); + padded[prev]= temp[0]; + padded[++prev]= temp[1]; + padded[++prev]= temp[2]; + padded[++prev]= temp[3]; + prev=0; + iter++; + } + + + int f=0; + // writing encrypted ciphertex to file + while(f!= padded.length){ + cipher_t.write(padded[f]); + f++; + } + + plain_t.close(); + cipher_t.close(); + + } + + /** + * This method converts the padded list to array of byte with padding + * @param d List of Bytes + * @return temp + */ + private static byte[] pad_array(List<Byte> d) { + byte [] temp = new byte[d.size()]; + for( int i=0; i< temp.length; i++){ + temp[i]= (byte)d.get(i); + } + return temp; + } + private static void usage() { + System.err.println ("Usage: java src.java.EncryptFile <key> <plaintext> <ciphertext>"); + System.err.println ("<ptfile> = Plaintext file name"); + System.err.println ("<ctfile> = Ciphertext file name"); + System.err.println ("<key> = Key (64 hex digits)"); + System.exit (1); + } +} diff --git a/src/java/utils/Utils.java b/src/java/utils/Utils.java new file mode 100644 index 0000000..b4f973f --- /dev/null +++ b/src/java/utils/Utils.java @@ -0,0 +1,159 @@ +package src.java.utils; + +public class Utils { + + //HexUtils + private static final char[] int2hex = new char[] + {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; + + public static String toString + (int val) + { + StringBuilder buf = new StringBuilder (8); + buf.append (int2hex[(val >> 28) & 0xF]); + buf.append (int2hex[(val >> 24) & 0xF]); + buf.append (int2hex[(val >> 20) & 0xF]); + buf.append (int2hex[(val >> 16) & 0xF]); + buf.append (int2hex[(val >> 12) & 0xF]); + buf.append (int2hex[(val >> 8) & 0xF]); + buf.append (int2hex[(val >> 4) & 0xF]); + buf.append (int2hex[(val ) & 0xF]); + return buf.toString(); + } + + public static String toString + (byte[] val) + { + return toString (val, 0, val.length); + } + + public static String toString + (byte[] val, + int off, + int len) + { + if (off < 0 || len < 0 || off + len > val.length) + { + throw new IndexOutOfBoundsException(); + } + StringBuilder buf = new StringBuilder (2*len); + while (len > 0) + { + buf.append (int2hex[(val[off] >> 4) & 0xF]); + buf.append (int2hex[(val[off] ) & 0xF]); + ++ off; + -- len; + } + return buf.toString(); + } + + public static byte[] toByteArray + (String str) + { + int n = (str.length() + 1) / 2; + byte[] val = new byte [n]; + toByteArray (str, val, 0, val.length); + return val; + } + + public static void toByteArray + (String str, + byte[] val, + int off, + int len) + { + if (off < 0 || len < 0 || off + len > val.length) + { + throw new IndexOutOfBoundsException(); + } + int stroff = str.length() - 1; + int valoff = off + len - 1; + int result; + while (len > 0 && stroff >= 0) + { + result = hex2int (str.charAt (stroff)); + -- stroff; + if (stroff >= 0) result += hex2int (str.charAt (stroff)) << 4; + -- stroff; + val[valoff] = (byte) result; + -- valoff; + -- len; + } + while (len > 0) + { + val[valoff] = (byte) 0; + -- valoff; + -- len; + } + } + + private static int hex2int + (char digit) + { + switch (digit) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + return digit - '0'; + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + return digit - 'a' + 10; + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + return digit - 'A' + 10; + default: + throw new IllegalArgumentException + ("Not a hexadecimal digit: '" + digit + "'"); + } + } + + //PackingUtils + public static long packLongBigEndian + (byte[] src, + int srcPos) + { + if (srcPos + 8 > src.length) throw new IndexOutOfBoundsException(); + long rv = 0L; + for (int i = 0; i <= 7; ++ i) + rv |= (src[srcPos+i] & 0xFFL) << ((7 - i)*8); + return rv; + } + + public static int packIntBigEndian + (byte[] src, + int srcPos) + { + if (srcPos + 4 > src.length) throw new IndexOutOfBoundsException(); + int rv = 0; + for (int i = 0; i <= 3; ++ i) + rv |= (src[srcPos+i] & 0xFF) << ((3 - i)*8); + return rv; + } + + public static void unpackIntBigEndian + (int src, + byte[] dst, + int dstPos) + { + if (dstPos + 4 > dst.length) throw new IndexOutOfBoundsException(); + for (int i = 0; i <= 3; ++ i) + dst[dstPos+i] = (byte)(src >> ((3 - i)*8)); + } + +}