前言:代码说明
该代码由client,server,Hill三个类组成,client发送信息到server,Hill是加密算法的主要实现,含有main函数,可以独立演示加密算法,也可以配合client和server的代码共同实现GUI的界面,downcalculate是开头的两个三重for循环是求解逆矩阵的关键所在!!
1⃣️Hill.java的实现
package 实验1.古典密码3;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.Scanner;
import static java.lang.Integer.valueOf;
public class Hill implements Serializable {
private LinkedHashMap<Character, Integer> ctoi;
public static void main(String[] args) {
// Scanner sc=new Scanner("")
Hill h1 = new Hill("HILL", "8 6 9 5;6 9 5 10;5 8 4 9;10 6 11 4");
// Hill h2=new Hill("hwgz", "8 6 9 5;6 9 5 10;5 8 4 9;10 6 11 4");
}
private StringBuilder cipher;//密文
private ArrayList<StringBuilder> key;//密钥
private StringBuilder plaintext;//明文
private double[][] kmatrix;//K矩阵
private double[] plainVector;
private double[] kVector;
private ArrayList<Character> decodeCh;
public Hill(String pt, String k) {
decodeCh=new ArrayList<>();
plaintext = new StringBuilder(pt.toLowerCase());
kmatrix = split(k);
initplainVector();
multiply();
inv(kmatrix);
}
private double[][] split(String s) {
String[] row = s.split("\\s*;\\s*");
double[][] matrix = new double[row.length][row.length];
for (int i = 0; i < row.length; ++i) {
String[] snum = row[i].split("\\s+");
for (int j = 0; j < snum.length; j++) {
matrix[i][j] = valueOf(snum[j]);//把每个字符串都转换成数字
}
}
return matrix;
}
private void initplainVector() {
plainVector = new double[plaintext.length()];
for (int i = 0; i < plaintext.length(); i++) {
plainVector[i] = ctoi.get(plaintext.charAt(i));
}
}
public void printMatrix(int[][] m) {
for (int i = 0; i < m.length; i++) {
for (int j = 0; j < m[i].length; j++) {
System.out.printf("%3d", m[i][j]);
}
System.out.println();
}
}
public void printMatrix(double[][]m){
for (var item : m)
{
for (var item1 : item)
{
System.out.printf("%12.4f",item1);
}
System.out.println();
}
}
private void initMap() {
ctoi = new LinkedHashMap<>();
for (int i = 0; i < 26; i++) {
ctoi.put((char) ('a' + i), i);
}
}
/**
* 相乘结果保存在kv里面,作为矩阵K
*/
private void multiply() {
final int col_res = kmatrix[0].length;
kVector = new double[col_res];
for (int k = 0; k < kmatrix.length; k++) {
for (int i = 0; i < kmatrix[0].length; i++) {//从0列到km的len-1列
int sum = 0;
for (int j = 0; j < kmatrix.length; j++) {//从左矩阵挨个元素的和右矩阵的列元素相乘
sum += plainVector[j] * kmatrix[j][i];
}
kVector[i] = sum;
}
}
for (int i = 0; i < kVector.length; i++) {
kVector[i] %= 26;
}
}
{
initMap();
}
public void inv(double[][] m) {
final int row = m.length;
final int col = m[0].length;
double[][] ans;
ArrayList<Double> plainVector;
if (row != col) {
System.err.println("该矩阵不是方阵,不可逆!!");
System.exit(0);
}
double[][] res = new double[row][col << 1];
for (int i = 0; i < m.length; i++) {
res[i] = Arrays.copyOf(m[i], m[i].length << 1);
}
for (int i = 0, j = col; i < m.length; ) {
res[i++][j++] = 1;
}
ans=downcalculate(res);
plainVector=multiply(kVector, ans);
printAns(plainVector);
}
private double[][] downcalculate(double[][] m) {
double[][] ans=new double[m.length][m.length];//行数
for (int j = 0; j < m[0].length; j++) {
for (int i = j+1; i < m.length; i++) {
double fact=m[i][j]/m[j][j];
for (int k = j; k < m[0].length; k++) {
m[i][k]+=(-fact*m[j][k]);
}
}
}
for (int j = m.length-1; j >= 0; j--) {
for (int i = j-1; i >= 0; i--) {
double fact=m[i][j]/m[j][j];
for (int k = m[0].length-1; k >= 0; k--) {
m[i][k]+=(-fact*m[j][k]);
}
}
}
for (int i = 0; i < (m[0].length>>1); i++) {
double reverse_num=1/m[i][i];
for (int j = 0; j < m[0].length; j++) {
m[i][j]*=reverse_num;
}
}
System.out.println();
printMatrix(m);
/**
* ans就是K^-1,
*/
for (int i = 0 ; i < m.length; i++) {
ans[i]=Arrays.copyOfRange(m[i],m[i].length/2 , m[i].length);
for (int k = 0; k < ans[i].length; k++) {
ans[i][k]=modNum(ans[i][k]);//求mod26
}
}
System.out.println();
printMatrix(ans);
return ans;
}
private double modNum(double a){
if (a>0){
return a%26;
}else {
int c=(int) Math.rint(a);//上取整后强转为int
while (c<0){
c+=26;
c%=26;
}
return c;
}
}
public ArrayList<Double> multiply(double[] m1,double[][] m2){
ArrayList<Double>ans=new ArrayList<>();
for (int i = 0; i < m2[0].length; i++) {
double sum=0;
for (int j = 0; j < m2.length; j++) {
sum+=m1[j]*m2[j][i];
}
sum%=26;
ans.add(sum);
}
return ans;
}
public Hill(double[] kv){
double[][] m2 = {// ni ju z
{23, 20, 5, 1},
{2, 11, 18, 1},
{2, 20, 6, 25},
{25, 2, 22, 25}
};
decodeCh=new ArrayList<>();
kmatrix=m2;
kVector=Arrays.copyOf(kv, kv.length);
ArrayList<Double> a=multiply(kVector, m2);
printAns(a);
}
public void printAns(ArrayList<Double> a){
for (var item : a)
{
System.out.printf("%c",(char)(97+Math.rint(item)));
decodeCh.add((char)(97+Math.rint(item)));
}
}
public ArrayList<Character> getDecodeCh() {
return decodeCh;
}
public double[] getkVector() {
return kVector;
}
public void setkVector(double[] kVector) {
this.kVector = kVector;
}
public String getCipher(){
StringBuilder s=new StringBuilder();
for (var item : kVector)
{//数字=>字母
s.append((char) ((int) item+'a'));
}
return s.toString();
}
}
2⃣️Client.java的代码
package 实验1.古典密码3;
import javax.swing.*;
import java.awt.*;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Client extends JFrame {
private Socket s;
private JLabel ptLa;
private JTextField pltx;
private JButton send;
private JPanel p;
{
p=new JPanel();
send=new JButton("发送");
ptLa=new JLabel("明文:");
pltx=new JTextField(20);
p.add(ptLa);
p.add(pltx);
add(p,BorderLayout.NORTH);
add(send,BorderLayout.SOUTH);
send.addActionListener(e->{
try {
String mw=pltx.getText();
PrintWriter pw=new PrintWriter(s.getOutputStream());
Hill h=new Hill(mw, "8 6 9 5;6 9 5 10;5 8 4 9;10 6 11 4");
StringBuilder sb=new StringBuilder();
for (int i = 0; i < h.getkVector().length; i++) {
if (i!=h.getkVector().length-1){
sb.append((int) (double)Double.valueOf(h.getkVector()[i])+":");
}else {
sb.append((int) (double)Double.valueOf(h.getkVector()[i]));
}
}
pw.println(sb.toString());
pw.flush();
} catch (IOException e1) {
e1.printStackTrace();
}
});
pack();
setVisible(true);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
public Client(){
try {
s=new Socket("127.0.0.1",8888);
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
new Client();
}
}
3⃣️server.java的代码
package 实验1.古典密码3;
import javax.swing.*;
import java.awt.*;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Scanner;
import static java.lang.Double.*;
public class Server extends JFrame {
ServerSocket ss;
Socket s;
private JLabel ptLa;
private JTextField ptF;
private JButton get;
private JPanel p;
private JPanel center;
private JLabel la2;
private JTextField jtf2;
{
p=new JPanel();
center=new JPanel();
la2=new JLabel("密文");
jtf2=new JTextField(20);
ptLa=new JLabel("明文:");
ptF=new JTextField(20);
get=new JButton("一键解密🔓");
p.add(ptLa);
p.add(ptF);
center.add(la2);
center.add(jtf2);
add(p,BorderLayout.NORTH);
add(center,BorderLayout.CENTER);
add(get,BorderLayout.SOUTH);
get.addActionListener(e-> {
try {
String cnt;
BufferedReader br=new BufferedReader(new InputStreamReader(s.getInputStream(),"utf-8"));
cnt=br.readLine();
if (cnt==null||cnt.equals("")){
return;
}
String[] kv=cnt.split(":");
double[] dkv=new double[kv.length];
int i=0;
for (var item : kv)
{
dkv[i++]=valueOf(item);
}
Hill h=new Hill(dkv);
ArrayList<Character> a=h.getDecodeCh();
Character[] c=new Character[a.size()];
a.toArray(c);
StringBuilder s=new StringBuilder();
for (var item : c)
{
s.append(item);
}
ptF.setText(s.toString());
jtf2.setText(h.getCipher());
} catch (IOException e1) {
e1.printStackTrace();
}
});
pack();
setVisible(true);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
Server(){
super("解密🔓");
try {
ss=new ServerSocket(8888);
s=ss.accept();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
new Server();
}
}