网络安全学习笔记-Hill算法的实现,GUI界面演示,含有逆矩阵求解过程

前言:代码说明

该代码由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();
    }
}


4⃣️输入样例

在这里插入图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿维的博客日记

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值