java实现hill加密与解密算法

hill算法简介

希尔密码是运用基本矩阵论原理的替换密码,由Lester S. Hill在1929年发明。
每个字母当作26进制数字:A=0, B=1, C=2… 一串字母当成n维向量,跟一个n×n的矩阵相乘,再将得出的结果模26。
注意用作加密的矩阵(即密匙)在 必须是可逆的,否则就不可能解码。只有矩阵的行列式和26互质,才是可逆的。

hill算法加密原理

先设计一个字母数字映射表:
字母映射表

  1. 设定密钥矩阵为K={{6, 24, 1},{13, 16, 10},{20, 17, 15}},这矩阵可以看需求定义,但是必须是可逆。(矩阵可逆的简单的判断方法:矩阵的行列式不等于零)
    在这里插入图片描述
  2. 现在假设有个明文文本 “IAMHILL”, 需要对这个明文加密,首先将这个明文中的每个字符用数字来表示出来,比如字符I=9,A=1,…, 最终 {9,1,13,8,9,12,12},接下来讲这个序列转换成行数为3的矩阵,并将其称明文矩阵,如果元素不够,补充空元素(#)。所以明文矩阵A={{9, 1, 13},{8, 9, 12},{12, 0 0}}
    在这里插入图片描述
  3. 接下来密钥矩阵K和明文矩阵A相乘,结果就是密文矩阵,矩阵乘法我这里不说了。相乘后密文矩阵C={{24, 14, 2}, {1, 1, 23}, {2, 17, 22}}
    在这里插入图片描述
  4. 然后将这个密文矩阵C中数字用字母表示出来, 结果为密文 = “XNBAAWBQV”

hill解密算法原理

  1. 密文为"XNBAAWBQV", 首先将密文中的每个字母用数字表示出来。C={{9, 1, 13},{8, 9, 12},{12, 0 0}}。并将其转换成矩阵
    在这里插入图片描述
  2. 求出密钥矩阵的逆矩阵, K1 = {{8, 5, 10}, {21, 8, 21}, {21, 12, 8}}
    在这里插入图片描述
  3. 密钥矩阵的逆矩阵K1 和 密文矩阵C 相乘, 结果为一个矩阵,且该矩阵里面的元素可能大于26,所以我们要对每个元素进行mod 26获取明文矩A={{9, 1, 13},{8, 9, 12},{12, 0 0}}
    在这里插入图片描述
  4. 将明文矩阵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);
	
	
	}
		
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值