S Hill Cipher is one of the basic substitution Hill Cipher scheme. According to Wikipedia:
Basic algorithm of Hill Cipher works with some matrix operation in modulo arithmetic Plain text is first broken into chunks of length n. Each chunk is then modulo multiplicated with a nxn matrix acting as key. The resulting chunks of text are then concatenated to from Cipher text. For decryption the nxn key is taken modulo inverse to from decryption key. Cipher text is then modulo multiplicated in the same manner as the plain text was, to get the Plain text back.
Here is a Java program written to perform Encryption and Decryption using Hill Cipher. This program uses modulo 95 to cover the whole printable ASCII range.
The HillCipher class uses a HillMatrix class and a Converter class to perform arithmetic and conversion operations respectively.
HillMatrix Class:
Converter Class:
Now here is the HillCipher class:
In classical cryptography, the Hill cipher is a polygraphic substitution cipher based on linear algebra. Invented by Lester S. Hill in 1929, it was the first polygraphic cipher in which it was practical (though barely) to operate on more than three symbols at once.
Basic Algorithm:
Basic algorithm of Hill Cipher works with some matrix operation in modulo arithmetic Plain text is first broken into chunks of length n. Each chunk is then modulo multiplicated with a nxn matrix acting as key. The resulting chunks of text are then concatenated to from Cipher text. For decryption the nxn key is taken modulo inverse to from decryption key. Cipher text is then modulo multiplicated in the same manner as the plain text was, to get the Plain text back.
Here is a Java program written to perform Encryption and Decryption using Hill Cipher. This program uses modulo 95 to cover the whole printable ASCII range.
The HillCipher class uses a HillMatrix class and a Converter class to perform arithmetic and conversion operations respectively.
HillMatrix Class:
package encryption.hillcipher; import java.math.BigInteger; public class HillMatrix { private int row; private int column; private int matrix[][]; private final int RANGE = 95; public HillMatrix(int row, int col){ this.row = row; this.column = col; matrix = new int[row][col]; for( int i=0;i<row;i++){ for(int j=0;j<col;j++){ matrix[i][j]=0; } } } public void set(int i, int j, int val){ matrix[i][j]=val; } public int get(int i, int j){ return matrix[i][j]; } public int getrowindex(){ return row; } public int getcolumnindex(){ return column; } public HillMatrix cross(HillMatrix B){ if(this.column != B.getrowindex()){ return null; } HillMatrix C = new HillMatrix(this.row,B.getcolumnindex()); for(int i=0;i<this.row;i++){ for(int j=0;j<B.getcolumnindex();j++){ for(int k=0;k<this.column;k++){ C.set(i, j, C.get(i, j) + this.get(i, k) * B.get(k, j)); } } } return C; } private int det(HillMatrix m){ int res=0; if(m.getcolumnindex() == 2){ res = m.get(0, 0)*m.get(1, 1) - m.get(1, 0)*m.get(0, 1); return (res); } for(int i=0;i<m.getcolumnindex();i++){ res = (int) (res + Math.pow(-1, i) * cofac(i,0,m) * m.get(0,i)); } return (res); } private int cofac( int i, int j,HillMatrix m){ int res; int index = m.getcolumnindex()-1; int deci = 0; int decj ; HillMatrix submat = new HillMatrix(index,index); for(int k=0;k<index+1;k++){ decj=0; if( k == j) { deci=1; continue; } for(int l=0;l<index+1;l++){ if( l == i){ decj=1; continue; } submat.set(k-deci, l-decj, m.get(k, l)); } } res = det(submat); return res; } public int det(){ return det(this); } public int cofac(int i, int j){ return cofac(i,j,this); } public HillMatrix inv(){ HillMatrix in = new HillMatrix(row , column); int invdet = moduloinv(det(this)); int temp; for(int i=0; i<row ; i++){ for(int j=0;j<column;j++){ temp = cofac(i,j,this)* (int) Math.pow(-1,i+j); in.set(i, j, modulus(temp*invdet)); } } return in; } public HillMatrix transpose(){ HillMatrix m = new HillMatrix(row,column); for(int i=0;i<row;i++){ for(int j=0;j<column;j++){ m.set(i, j, get(j,i)); } } return m; } private int modulus(int in){ int res; if(in < 0){ return RANGE - (Math.abs(in)%RANGE); } res = Math.abs(in) % RANGE; return res; } private int moduloinv(int in){ BigInteger bi = new BigInteger(String.valueOf(in)); try{ bi = bi.modInverse(new BigInteger(String.valueOf(RANGE))); } catch(Exception e){ System.out.println("Key is not inversable..!"); System.exit(-1); } return bi.intValue(); } public HillMatrix mod(){ HillMatrix m = new HillMatrix(row,column); for(int i=0;i<row;i++){ for(int j=0;j<column;j++){ m.matrix[i][j] = matrix[i][j]%RANGE; } } return m; } public boolean IsInvertable(){ int det = det(this); if( det != 0 && moduloinv(det) != 0) { return true; } return false; } }
Converter Class:
package encryption.hillcipher; public class Converter{ private static final int OFFSET = 32; public static int ToInt(char ch){ return ((int)ch-OFFSET); } public static char ToChar(int in){ return (char)(in + OFFSET); } }
Now here is the HillCipher class:
public class HillCipher { HillMatrix key; int keyLenght; public HillCipher(String keyText){ int l = keyText.length(); l=(int)Math.sqrt(l); keyLenght = l; key = new HillMatrix(keyLenght,keyLenght); l = 0; for(int i=0;i<keyLenght;i++){ for(int j=0;j<keyLenght;j++){ key.set(i, j, Converter.ToInt(keyText.charAt(l++))); } } } public StringBuffer Encrypt(StringBuffer pText){ StringBuffer cText = new StringBuffer(); HillMatrix enc = new HillMatrix(keyLenght,1); int n = keyLenght -(pText.length() % keyLenght); for(int i=0;i<n;i++){ pText.append('x'); } n = 0; while(n <pText.length()){ for(int i=0;i<keyLenght;i++){ enc.set(i, 0, Converter.ToInt(pText.charAt(n++))); } enc = key.cross(enc); enc = enc.mod(); for(int i=0;i<keyLenght;i++){ cText.append(Converter.ToChar(enc.get(i, 0))); } } return cText; } public StringBuffer Decrypt(StringBuffer cText){ StringBuffer pText = new StringBuffer(); HillMatrix dec = new HillMatrix(keyLenght,1); HillMatrix invKey = key.inv(); int n = cText.length() % keyLenght; for(int i = 0 ; i< n ;i++){ cText.append('x'); } n = 0; while(n <cText.length()){ for(int i =0;i<keyLenght;i++){ dec.set(i, 0, Converter.ToInt(cText.charAt(n++))); } dec = invKey.cross(dec); dec = dec.mod(); for(int i=0;i<keyLenght;i++){ pText.append(Converter.ToChar(dec.get(i, 0))); } } return pText; } public static boolean IsDecryptable(String keyText){ int l = keyText.length(); l=(int)Math.sqrt(l); HillMatrix newkey = new HillMatrix(l,l); int n = 0; for(int i=0;i<l;i++){ for(int j=0;j<l;j++){package encryption.hillcipher; public class Converter{ private static final int OFFSET = 32; public static int ToInt(char ch){ return ((int)ch-OFFSET); } public static char ToChar(int in){ return (char)(in + OFFSET); } } newkey.set(i, j, Converter.ToInt(keyText.charAt(n++))); } } return newkey.IsInvertable(); } }