hill算法,ejml矩阵操作库,SimpleMatrix
hill算法简介
希尔密码是运用基本矩阵论原理的替换密码,由Lester S. Hill在1929年发明。
每个字母当作26进制数字:A=0, B=1, C=2… 一串字母当成n维向量,跟一个n×n的矩阵相乘,再将得出的结果模26。
注意用作加密的矩阵(即密匙)在 必须是可逆的,否则就不可能解码。只有矩阵的行列式和26互质,才是可逆的。
hill算法加密原理
先设计一个字母数字映射表:
- 设定密钥矩阵为K={{6, 24, 1},{13, 16, 10},{20, 17, 15}},这矩阵可以看需求定义,但是必须是可逆。(矩阵可逆的简单的判断方法:矩阵的行列式不等于零)
- 现在假设有个明文文本 “IAMHILL”, 需要对这个明文加密,首先将这个明文中的每个字符用数字来表示出来,比如字符I=9,A=1,…, 最终 {9,1,13,8,9,12,12},接下来讲这个序列转换成行数为3的矩阵,并将其称明文矩阵,如果元素不够,补充空元素(#)。所以明文矩阵A={{9, 1, 13},{8, 9, 12},{12, 0 0}}
- 接下来密钥矩阵K和明文矩阵A相乘,结果就是密文矩阵,矩阵乘法我这里不说了。相乘后密文矩阵C={{24, 14, 2}, {1, 1, 23}, {2, 17, 22}}
- 然后将这个密文矩阵C中数字用字母表示出来, 结果为密文 = “XNBAAWBQV”
hill解密算法原理
- 密文为"XNBAAWBQV", 首先将密文中的每个字母用数字表示出来。C={{9, 1, 13},{8, 9, 12},{12, 0 0}}。并将其转换成矩阵
- 求出密钥矩阵的逆矩阵, K1 = {{8, 5, 10}, {21, 8, 21}, {21, 12, 8}}
- 密钥矩阵的逆矩阵K1 和 密文矩阵C 相乘, 结果为一个矩阵,且该矩阵里面的元素可能大于26,所以我们要对每个元素进行mod 26获取明文矩A={{9, 1, 13},{8, 9, 12},{12, 0 0}}
- 将明文矩阵A的每个元素用数字表示出来, “IAMHILL##”, 然后将里面的“#”删掉即可完成解密算法。
hill算法的实现与代码
package hili_virgina;
import java.util.HashMap;
import java.util.Map;
import org.ejml.simple.SimpleMatrix;
public class Hili {
Map<String, Integer> ch_num_map = new HashMap<>(); //字母-数字映射字典
Map<Integer, String> num_ch_map = new HashMap<>(); //数字-字母映射字典
String[] ch = {"#","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"};
// 密钥矩阵
SimpleMatrix key_martix = new SimpleMatrix(new double[][] {{6,24,1},{13,16,10},{20,17,15}});
public Hili() {
super();
init(null);
}
public Hili(String key_str) {
init(null);
this.key_str = key_str;
int a = (int)Math.ceil(Math.sqrt(key_str.length()));
// 将字符串用数字数组表示出来
double[] key_double = new double[a*a];
for (int i = 0; i < a*a; i++) {
char key_ch = 0;
int key_ch_ascii = 0;
try{
key_ch = key_str.charAt(i);
}catch (StringIndexOutOfBoundsException e) {
System.out.println(e);
key_ch_ascii = 0;
}
key_ch_ascii = this.ch_num_map.get(String.valueOf(key_ch));
key_double[i] = key_ch_ascii;
}
// 生成对应与密钥字符串的数字化矩阵
this.key_martix = new SimpleMatrix(a, a, true, key_double);
}
public Hili(Map<String, Integer> ch_num_map , String key_str, SimpleMatrix key_martix) {
super();
init(null);
this.ch_num_map = ch_num_map ;
this.key_str = key_str;
this.key_martix = key_martix;
}
public void init(Map<String, Integer> ch_num_map) {
/*负责初始化两个映射表*/
if (ch_num_map != null) {
this.ch_num_map = ch_num_map;
}else {
for (int i = 0; i < ch.length; i++) {
this.ch_num_map.put(ch[i], i);
this.num_ch_map.put(i, ch[i]);
}
}
}
public SimpleMatrix build_cipher(String raw_text) {
/*将明文文本转换矩阵并生成一个密文矩阵并返回*/
int a = raw_text.length() / this.key_martix.numRows();
if(raw_text.length() % this.key_martix.numRows() != 0) {
a = a+1;
}
// 将字符串用数字数组表示出来
double[] raw_double = new double[this.key_martix.numRows()*a];
for (int i = 0; i < raw_double.length; i++) {
char raw_ch = 0;
int raw_ch_ascii = 0;
try{
raw_ch = raw_text.charAt(i);
raw_ch_ascii = this.ch_num_map.get(String.valueOf(raw_ch));
}catch (StringIndexOutOfBoundsException e) {
System.out.println("因为文本长度和密钥矩阵的列数不匹配,所以补了空字符");
raw_ch_ascii = 0;
}
raw_double[i] = raw_ch_ascii;
}
// 生成对应与明文字符串的数字化矩阵
SimpleMatrix raw_martix = new SimpleMatrix(this.key_martix.numRows(), a, true, raw_double);
// 密钥矩阵和明文矩阵相乘
SimpleMatrix cipher_martix = this.key_martix.mult(raw_martix);
// 将密文矩阵以26求余数
for (int i = 0; i < cipher_martix.numRows(); i++) {
for (int j = 0; j < cipher_martix.numCols(); j++) {
int x_ij = (int)cipher_martix.get(i, j);
int r = x_ij % 26;
cipher_martix.set(i, j, r);
}
}
return cipher_martix;
}
public SimpleMatrix unbuild_cipher(String cipher_text) {
/*将密文文本转换矩阵,进行解密操作,并返回明文矩阵*/
int a = cipher_text.length() / this.key_martix.numRows();
if(cipher_text.length() % this.key_martix.numRows() != 0) {
a = a+1;
}
// 将字符串用数字数组表示出来
double[] cipher_double = new double[this.key_martix.numRows()*a];
for (int i = 0; i < cipher_double.length; i++) {
char cipher_ch = 0;
int cipher_ch_ascii = 0;
try{
cipher_ch = cipher_text.charAt(i);
cipher_ch_ascii = this.ch_num_map.get(String.valueOf(cipher_ch));
}catch (StringIndexOutOfBoundsException e) {
System.out.println("因为文本长度和密钥矩阵的列数不匹配,所以补了空字符");
cipher_ch_ascii = 0;
}
cipher_double[i] = cipher_ch_ascii;
}
// 生成对应与密文字符串的数字化矩阵
SimpleMatrix cipher_martix = new SimpleMatrix(this.key_martix.numRows(), a, true, cipher_double);
// 求出密钥的逆矩阵
SimpleMatrix key_martix_invert = this.getInvert(key_martix);
// 密钥矩阵的逆矩阵和密文矩阵相乘, 并获得明文矩阵
SimpleMatrix raw_martix = key_martix_invert.mult(cipher_martix);
// 将明文矩阵以26求余数
for (int i = 0; i < raw_martix.numRows(); i++) {
for (int j = 0; j < raw_martix.numCols(); j++) {
int x_ij = 0;
double ij = raw_martix.get(i, j);
x_ij = (int) Math.round(ij);
int r = x_ij % 26;
if(r<0) {
r = r+26;
}
raw_martix.set(i, j, r);
}
}
return raw_martix;
}
public SimpleMatrix getInvert(SimpleMatrix matrix) {
/**
* 负责求逆矩阵
*/
int d = (int)matrix.determinant();
while (d>26) {
d = d % 26;
}
int r1 = 0;
switch (d) {
case 1:
r1 = 1;
break;
case 3:
r1 = 9;
break;
case 5:
r1 = 21;
break;
case 7:
r1 = 15;
break;
case 9:
r1 = 3;
break;
case 11:
r1 = 19;
break;
case 15:
r1 = 7;
break;
case 17:
r1 = 23;
break;
case 19:
r1 = 11;
break;
case 21:
r1 = 5;
break;
case 23:
r1 = 17;
break;
case 25:
r1 = 25;
break;
default:
System.out.println("d 倒数不存在");
}
int detk = (int) matrix.determinant();
SimpleMatrix k = matrix.invert().scale(detk);
SimpleMatrix key2 = k.scale(r1);
for (int i = 0; i < key2.numRows(); i++) {
for (int j = 0; j < key2.numCols(); j++) {
int x_ij = (int)key2.get(i, j);
double x_ij1 = key2.get(i, j);
x_ij = (int) Math.round(x_ij1);
int r = x_ij % 26;
if(r<0) {
r = r+26;
}
key2.set(i, j, r);
}
}
return key2;
}
public String toString(SimpleMatrix matrix) {
/*负责将矩阵转换为文本*/
String text = "";
for (int i = 0; i < matrix.numRows(); i++) {
for (int j = 0; j < matrix.numCols(); j++) {
int num = (int)matrix.get(i, j);
text = text + this.num_ch_map.get(num);
}
}
return text;
}
public static void main(String[] args) {
Hili hili = new Hili();
System.out.println("key matrix(密钥矩阵):");
hili.key_martix.print();
System.out.println("*******************加密*******************");
SimpleMatrix cipher_matrix = hili.build_cipher("IAMHILL");
System.out.println("cipher matrix(加密矩阵):");
cipher_matrix.print();
System.out.println("cipher matrix to text(加密矩阵转换文本):");
String cipher_text = hili.toString(cipher_matrix);
System.out.println(cipher_text);
System.out.println("*******************解密*******************");
SimpleMatrix raw_martix = hili.unbuild_cipher(cipher_text);
System.out.println("raw matrix(明文矩阵):");
raw_martix.print();
System.out.println("raw matrix to text(明文矩阵转换为文本):");
String raw_text = hili.toString(raw_martix);
System.out.println(raw_text);
}
}