Heart beat number 0822 2020-11-09 22:19:01

Hill Password is a traditional cryptosystem . Encryption principle ： Choose a second-order invertible integer matrix A be called The encryption matrix of the password , This is the key of this encryption system . The encryption process ：

Plaintext letters are grouped in pairs , for example The encryption matrix is a second order matrix , Plaintext is just a group of two letters , If the last group is not enough （ The plaintext length is odd ）, Add any letters to make a double , Form a two-dimensional vector group a. Calculation of matrix A Multiply by the vector group a, Get a new two-dimensional column vector b, Check the alphabet and get two letters, which are cipher letters .

in other words , The encryption process is ： Plaintext --> Mapping to a digital matrix --> Encrypted matrix --> Map to string （ Ciphertext ）

The decryption process is the same , It's just a matrix decryption in the middle ,Hill Password is a traditional cryptosystem .

According to this process , The function codes of each stage are as follows ：

First create a class ,HillCrypto,

The member variables are encryption key matrix and decryption key matrix , Alphanumeric mapping and numeric to alphanumeric mapping

Initialization phase , Instantiate the above member variables , The mapping table is larger , So it's written in a local file for reuse , When creating a map, you need to read the local file .

The contents of the document are as follows ： The code is as follows ：

```import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
public class HillCrypto {
private Map<Character, Integer> table;
private Map<Integer, Character> getPlainMap;
private int[][] encryption = {{1, 1},{0, 3}};
private int[][] decryption;
public HillCrypto(String tableFilePath) {
// TODO Auto-generated constructor stub
int mrow = encryption.length;int mcolumn = encryption.length;
this.decryption = new int[mrow][mcolumn];
// The inverse of a second-order matrix , If it's a higher order , Use other methods , For example, the inverse matrix is obtained by dividing the cosine by the determinant , For the determinant, see my other blogs .
decryption = (encryption * 27 / (encryption*encryption - encryption*encryption)) % 26;
decryption = - (encryption * 27 / (encryption*encryption - encryption*encryption)) % 26;
decryption = - (encryption * 27 / (encryption*encryption - encryption*encryption)) % 26;
decryption = (encryption * 27 / (encryption*encryption - encryption*encryption)) % 26;
// All the matrices of the algorithm need to take the remainder after being calculated
for (int i = 0; i < decryption.length; i++) {
for (int j = 0; j < decryption.length; j++) {
if (decryption[i][j] < 0) {
decryption[i][j] += 26;
}
}
}
this.print(decryption);
this.getPlainMap = this.mapReverse(table);
}
private void print(int[][] matrix) {
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix.length; j++) {
System.out.print(matrix[i][j]+", ");
}
System.out.println();
}
}
// map The key values of the
private Map<Integer, Character> mapReverse(Map<Character, Integer> table){
Iterator<Character> it = table.keySet().iterator();
Map<Integer, Character> result = new HashMap<Integer, Character>();
while (it.hasNext()) {
Character character = (Character) it.next();
result.put(table.get(character), character);
}
return result;
}
/**
* Read a file locally to create the alphabet , for example A->0, B->1,...,Z->25
* @param tableFilePath
* @return
*/
private Map<Character, Integer> readFile(String tableFilePath) {
File file = new File(tableFilePath);
Map<Character, Integer> map = new HashMap<Character, Integer>();
try {
String line = "";
String[] kv = null;
while ((line = br.readLine())!= null) {
kv = line.split(",");
// System.out.println(" Read key value pairs ：<"+kv+", "+kv+">");
map.put(kv.charAt(0), Integer.parseInt(kv));
}
br.close();
fr.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return map;
}
}```

Ciphertext is a string , According to the map table read , In pairs, it turns into a number matrix ：

``` /**
* The ciphertext is transformed into two-dimensional vector according to the mapping table
* @return
*/
private int[][] getVectorFromString(String text){
int textLength = text.length();
// System.out.println(" The length of ciphertext is :" + textLength);
int row = textLength;
if (row % 2 != 0) {
row = (row + 1) / 2;
int column = this.encryption.length;
int[][] vector = new int[row][column];
for (int i = 0; i < row-1; i++) {
for (int j = 0; j < column; j++) {
vector[i][j] = this.table.get(text.charAt(i*column + j));
}
}
vector[row-1][column-2] = this.table.get(text.charAt((row-1)*column + column-2));
// this.print(vector);
vector[row-1][column-1] = this.table.get('A');
return this.transpose(vector);
}else {
row = row / 2;
int column = this.encryption.length;
int[][] vector = new int[row][column];
for (int i = 0; i < row; i++) {
for (int j = 0; j < column; j++) {
vector[i][j] = this.table.get(text.charAt(i*column + j));
}
}
return this.transpose(vector);
}
}
// Find matrix transposition
public int[][] transpose(int[][] matrix){
int row = matrix.length;
int column = matrix.length;
int[][] newmatrix = new int[column][row];
for (int i = 0; i < row; i++) {
for (int j = 0; j < column; j++) {
newmatrix[j][i] = matrix[i][j];
}
}
return newmatrix;
}
```

Both encryption and decryption require matrix multiplication

``` // The result of multiplying a matrix by a vector
public int[][] transform(int[][] matrix, int[][] vector) {
int mrow = matrix.length;
int mcolumn = matrix.length;
int column = vector.length;
int[][] result = new int[mcolumn][column];
for (int k = 0; k < column; k++) {
for (int i = 0; i < mcolumn; i++) {
for (int j = 0; j < mrow; j++) {
result[i][k] += matrix[i][j] * vector[j][k];
// System.out.printf("result[%d][%d] = %d\n", i, k, result[i][k]);
}
}
}
for (int i = 0; i < mcolumn; i++) {
for (int j = 0; j < column; j++) {
result[i][j] %= 26;
}
}
return result;
}```

From the number matrix back look up the mapping table to get the string

``` public char[] getPlain(int[][] table) {
int row = table.length;
int column = table.length;
char[] plaintext = new char[row*column];
for (int i = 0; i < column; i++) {
for (int j = 0; j < row; j++) {
plaintext[i*row+j] = this.getPlainMap.get(table[j][i]);
}
}
return plaintext;
}```

Then we use an example to demonstrate the process of encryption and decryption ：

``` public static void main(String[] args) {
String tableFilePath = "src/zhaoke/table.csv";
// Encryption key

String originPlain = "JAVAISTHEBESTLANGUAGEINTHEWORLD";
System.out.println(" Plaintext ："+originPlain);
HillCrypto hc = new HillCrypto(tableFilePath);
// The encryption process
// First, strings are mapped to numbers
int[][] plainNum = hc.getVectorFromString(originPlain);
// hc.print(plainNum);
// And then use the encryption matrix to encrypt
int[][] encryptedPlain = hc.transform(hc.encryption, plainNum);
// And then mapping it to a string is ciphertext
String cipherPlain = new String(hc.getPlain(encryptedPlain));
System.out.println(" Encrypted ciphertext "+cipherPlain);
// The decryption process
// First, it maps to a number
int[][] cipherNum = hc.getVectorFromString(cipherPlain);
// hc.print(cipherNum);
// Use decryption matrix to decrypt
int[][] newtable = hc.transform(hc.decryption, cipherNum);
// Then it maps to plaintext
String plainText = new String(hc.getPlain(newtable));
System.out.println(" The decrypted plaintext is : "+plainText);
}```

Execution results ：

``` Plaintext ：JAVAISTHEBESTLANGUAGEINTHEWORLD
Encrypted ciphertext KCWCBEBXGFXEFJOPBKHUNAHHMOLSDJEC
The decrypted plaintext is : JAVAISTHEBESTLANGUAGEINTHEWORLDA```

You can see that the result is correct , It shows that the algorithm is effective , As for why one more A, That's because the plaintext length is odd , In order to map to a two-dimensional vector, we need to round up , A random letter is added to the table lookup phase to make up a double, so there is one more A, But it doesn't affect that we can see that plaintext is "Java is the best language in the world".