[Java] Basierend auf dem naiven Bayes'schen Algorithmus zum Knacken des Verschlüsselungsalgorithmus zum Ersetzen zufälliger Zeichen basierend auf der Hash-Tabelle

[Java] Basierend auf dem naiven Bayes'schen Algorithmus zum Knacken des Verschlüsselungsalgorithmus zum Ersetzen zufälliger Zeichen basierend auf der Hash-Tabelle.
  Lesen Sie ihn nicht, dieser Artikel ist falsch. Auch das erhaltene Ergebnis ist nicht das korrekte Ergebnis. Ich habe mich geirrt, denn die Prämisse dieses Entschlüsselungsalgorithmus besteht darin, ihn zu berechnen, wenn die Hash-Tabelle bereits bekannt ist. Tatsächlich sollte man sich zur Analyse des Chiffretexts nur auf Statistiken stützen, daher sollte die Anzahl der zum tatsächlichen Knacken erforderlichen Chiffretextzeichen größer sein als die in diesem Artikel berechnete Zahl

Vorwort

  In diesem Artikel wird erläutert, wie Sie mithilfe des naiven Bayes'schen Algorithmus das Modell trainieren, um den Verschlüsselungsalgorithmus zum Ersetzen zufälliger Zeichen zu knacken, und die Sicherheit des Verschlüsselungsalgorithmus anhand der Statistiken der entschlüsselten Daten analysieren.


Zusammenfassung

  In diesem Artikel werden der Verschlüsselungsalgorithmus zur zufälligen Zeichenersetzung basierend auf einer Hash-Tabelle und seine Sicherheitsprobleme untersucht, der naive Bayes'sche Algorithmus zum Knacken des Verschlüsselungsalgorithmus verwendet und die Ergebnisse des Knackens analysiert und diskutiert. Die Forschungsergebnisse zeigen, dass die Sicherheit des Verschlüsselungsalgorithmus unzureichend ist und leicht geknackt werden kann. In diesem Artikel werden Verbesserungsmaßnahmen vorgeschlagen, um die Sicherheit des Algorithmus zu verbessern.

Schlüsselwörter: Hash-Tabelle, Verschlüsselung durch zufällige Zeichenersetzung, naiver Bayesianischer Algorithmus, Sicherheit


1. Codeteil

Der Codeteil sieht so aus:

import javax.swing.*;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.List;
import java.util.*;

public class Main {
    
    
    private static final int WIDTH = 600;
    private static final int HEIGHT = 400;
    private static final int BORDER_GAP = 30;
    private static final Color LINE_COLOR = Color.BLUE;
    private static final Stroke GRAPH_STROKE = new BasicStroke(2f);
    private static final int GRAPH_POINT_WIDTH = 6;


    public static void main(String[] args) {
    
    

        //读取哈希表
        Map<Character, List<Character>> hashTable;
        try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("hashtable.ser"))) {
    
    
            hashTable = (Map<Character, List<Character>>) ois.readObject();
        } catch (IOException | ClassNotFoundException e) {
    
    
            e.printStackTrace();
            return;
        }
        NaiveBayes naiveBayes = null;
        ArrayList<Double> accuracyList = new ArrayList<>();
        ArrayList<Integer> lengthList = new ArrayList<>();
        for (int times = 0; times < 1000000; times += 1000) {
    
    
            lengthList.add(times);
            int length = 1;
            //生成10000个长度为100的字符串
            Random random = new Random();

            List<String> originalStrings = getOriginalStrings(times, length, random);

            List<String> encryptedStrings = getEncryptedStrings(hashTable, originalStrings, random);

            Map<String, String> dataSet = getStringStringMap(originalStrings, encryptedStrings);

            //使用朴素贝叶斯算法训练出一个解密的模型
            naiveBayes = new NaiveBayes();
            naiveBayes.train(dataSet);

            accuracyList.add(accuracyTest(hashTable, length, random, naiveBayes));
            if (accuracyList.get(accuracyList.size() - 1) > 0.99) {
    
    
                System.out.println("准确率(0~1): " + accuracyList.get(accuracyList.size() - 1));
                System.out.println("截取密文长度:" + times + '\n');
                break;
            }
        }
        drawGraph(accuracyList, lengthList, 20000, 0.1);

        Scanner scanner = new Scanner(System.in);

        System.out.println("请输入要解密的密文:");
        String encryptedString = scanner.nextLine();

        System.out.println("解密结果:\n" + naiveBayes.predict(encryptedString));
    }

    private static List<String> getOriginalStrings(int times, int length, Random random) {
    
    
        List<String> originalStrings = new ArrayList<>();
        for (int i = 0; i < times; i++) {
    
    
            StringBuilder sb = new StringBuilder();
            for (int j = 0; j < length; j++) {
    
    
                int r = random.nextInt(36);
                if (r < 26) {
    
    
                    sb.append((char) ('a' + r));
                } else if (r < 35) {
    
    
                    sb.append((char) ('0' + r - 26));
                } else {
    
    
                    sb.append(' ');
                }
            }
            originalStrings.add(sb.toString());
        }
        return originalStrings;
    }

    private static List<String> getEncryptedStrings(Map<Character, List<Character>> hashTable, List<String> originalStrings, Random random) {
    
    
        //将这些字符串通过哈希表进行加密
        List<String> encryptedStrings = new ArrayList<>();
        for (String originalString : originalStrings) {
    
    
            StringBuilder sb = new StringBuilder();
            for (char c : originalString.toCharArray()) {
    
    
                sb.append(hashTable.get(c).get(random.nextInt(hashTable.get(c).size())));
            }
            encryptedStrings.add(sb.toString());
        }
        return encryptedStrings;
    }

    private static Map<String, String> getStringStringMap(List<String> originalStrings, List<String> encryptedStrings) {
    
    
        //将生成的密文和原字符串一一对应起来
        Map<String, String> dataSet = new HashMap<>();
        for (int i = 0; i < originalStrings.size(); i++) {
    
    
            dataSet.put(encryptedStrings.get(i), originalStrings.get(i));
        }
        return dataSet;
    }

    private static double accuracyTest(Map<Character, List<Character>> hashTable, int length, Random random, NaiveBayes naiveBayes) {
    
    
        int timesTest = 100000;
        //生成10000个随机字符,用哈希表进行加密后,再用训练出的模型进行解密
        List<String> testStrings = getOriginalStrings(timesTest, length, random);
        //用哈希表加密
        List<String> testEncryptedStrings = getEncryptedStrings(hashTable, testStrings, new Random());
        //用训练出的模型进行解密
        List<String> testDecryptedStrings = new ArrayList<>();
        for (String testEncryptedString : testEncryptedStrings) {
    
    
            testDecryptedStrings.add(naiveBayes.predict(testEncryptedString));
        }

        //将解密结果与原字符进行对比,评测模型的准确度并打印到输出台上
        int correctCount = 0;
        for (int i = 0; i < testStrings.size(); i++) {
    
    
            if (testStrings.get(i).equals(testDecryptedStrings.get(i))) {
    
    
                correctCount++;
            }
        }
        return correctCount / (double) timesTest;
    }

    public static void drawGraph(ArrayList<Double> accuracyList, ArrayList<Integer> lengthList, int xUnitLength, double yUnitLength) {
    
    
        JFrame frame = new JFrame("统计测试");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(WIDTH, HEIGHT);

        JPanel panel = new JPanel() {
    
    
            @Override
            protected void paintComponent(Graphics g) {
    
    
                super.paintComponent(g);
                Graphics2D g2 = (Graphics2D) g;

                g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
                setBackground(Color.WHITE);

                //绘制坐标系
                g2.drawLine(BORDER_GAP, getHeight() - BORDER_GAP, BORDER_GAP, BORDER_GAP);
                g2.drawLine(BORDER_GAP, getHeight() - BORDER_GAP, getWidth() - BORDER_GAP, getHeight() - BORDER_GAP);

                //绘制数据点和连线
                int pointX, pointY, prevPointX = 0, prevPointY = 0;
                for (int i = 0; i < accuracyList.size(); i++) {
    
    
                    pointX = (int) ((double) (getWidth() - 2 * BORDER_GAP) / (lengthList.size() - 1) * i + BORDER_GAP);
                    pointY = (int) ((getHeight() - 2 * BORDER_GAP) * (1 - accuracyList.get(i)) + BORDER_GAP);
                    g2.setColor(LINE_COLOR);
                    g2.setStroke(GRAPH_STROKE);
                    if (i > 0) {
    
    
                        g2.drawLine(prevPointX, prevPointY, pointX, pointY);
                    }
                    g2.fillOval(pointX - GRAPH_POINT_WIDTH / 2, pointY - GRAPH_POINT_WIDTH / 2, GRAPH_POINT_WIDTH, GRAPH_POINT_WIDTH);
                    prevPointX = pointX;
                    prevPointY = pointY;
                    //在x轴上绘制坐标值
                    if (lengthList.get(i) % xUnitLength == 0) {
    
    
                        g2.drawString(String.format("%,d", lengthList.get(i)), pointX, getHeight() - BORDER_GAP / 2);
                    }
                }

                //在y轴上绘制坐标值
                for (int i = 0; i <= 10; i++) {
    
    
                    int y = (int) ((getHeight() - 2 * BORDER_GAP) * (1 - i * 0.1) + BORDER_GAP);
                    g2.drawString(String.format("%.1f", i * yUnitLength), BORDER_GAP / 2, y);
                }

                //在x轴下标注密文长度
                g2.drawString("密文长度", getWidth() / 2, getHeight() - BORDER_GAP / 4);

                //在y轴旁边标注准确率
                AffineTransform origTransform = g2.getTransform();
                AffineTransform at = new AffineTransform();
                at.rotate(-Math.PI / 2);
                g2.setTransform(at);
                g2.drawString("准确率", -getHeight() / 2, BORDER_GAP / 2);
                g2.setTransform(origTransform);
            }

            @Override
            public Dimension getPreferredSize() {
    
    
                return new Dimension(WIDTH, HEIGHT);
            }
        };

        frame.add(panel);
        frame.setVisible(true);
    }

    private static class NaiveBayes {
    
    
        private Map<String, Map<Character, Integer>> featureCount;
        private Map<String, Integer> labelCount;

        public NaiveBayes() {
    
    
            featureCount = new HashMap<>();
            labelCount = new HashMap<>();
        }

        public void train(Map<String, String> dataSet) {
    
    
            for (Map.Entry<String, String> entry : dataSet.entrySet()) {
    
    
                String encryptedString = entry.getKey();
                String originalString = entry.getValue();
                for (int i = 0; i < encryptedString.length(); i++) {
    
    
                    String feature = encryptedString.substring(i, i + 1);
                    char label = originalString.charAt(i);
                    if (!featureCount.containsKey(feature)) {
    
    
                        featureCount.put(feature, new HashMap<>());
                    }
                    if (!featureCount.get(feature).containsKey(label)) {
    
    
                        featureCount.get(feature).put(label, 0);
                    }
                    featureCount.get(feature).put(label, featureCount.get(feature).get(label) + 1);
                }
                if (!labelCount.containsKey(originalString)) {
    
    
                    labelCount.put(originalString, 0);
                }
                labelCount.put(originalString, labelCount.get(originalString) + 1);
            }
        }

        public String predict(String encryptedString) {
    
    
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < encryptedString.length(); i++) {
    
    
                String feature = encryptedString.substring(i, i + 1);
                char label = 'a';
                int maxCount = 0;
                //若找不到字符对应的指针,则解出的密文赋与*字符
                if (!featureCount.containsKey(feature)) {
    
    
                    sb.append('*');
                    continue;
                }
                for (Map.Entry<Character, Integer> entry : featureCount.get(feature).entrySet()) {
    
    
                    if (entry.getValue() > maxCount) {
    
    
                        maxCount = entry.getValue();
                        label = entry.getKey();
                    }
                }
                sb.append(label);
            }
            return sb.toString();
        }
    }
}

2. Verschlüsselungsalgorithmus zur zufälligen Zeichenersetzung basierend auf einer Hash-Tabelle

Der Verschlüsselungsprozess des Hash-Tabellen-basierten Verschlüsselungsalgorithmus zum Ersetzen zufälliger Zeichen ist wie folgt:

  1. Generieren Sie zufällig einen Zeichensatz mit 37 Zeichen, darunter 26 englische Buchstaben, 10 Zahlen von 0 bis 9 und ein Leerzeichen.
  2. Jedem Zeichen wird zufällig ein Unicode-codiertes Zeichen zugewiesen, insgesamt werden 1771 Zeichen zugewiesen und diese Zeichen werden in einer Hash-Tabelle gespeichert;
  3. Wenn eine Verschlüsselung erforderlich ist, wird jedes Zeichen im Klartext durch andere Zeichen in der Hash-Tabelle ersetzt, d. h. ein Zeichen in der Hash-Tabelle wird zufällig zum Ersetzen ausgewählt.

Weitere Informationen zu diesem Verschlüsselungsalgorithmus finden Sie in einem meiner vorherigen Artikel:

[Java] Verschlüsselungsalgorithmus zur zufälligen Zeichenersetzung basierend auf einer Hash-Tabelle – warum nicht?


3. Trainingsmodell basierend auf dem Naive Bayes'schen Algorithmus

  Die naive Bayes'sche Klassifizierung ist eine Klassifizierungsmethode, die auf dem Bayes'schen Theorem und der Annahme einer merkmalsbedingten Unabhängigkeit basiert. Es kann zur Klassifizierung von Eingabedaten verwendet werden. Dabei wird davon ausgegangen, dass die Merkmale unabhängig voneinander sind, was die Berechnungen vereinfacht.

  In diesem Code wird der Naive-Bayes-Algorithmus zum Entschlüsseln der verschlüsselten Zeichenfolge verwendet. Verwenden Sie zunächst eine Zufallsfunktion, um eine bestimmte Anzahl von Originalzeichenfolgen zu generieren, und verschlüsseln Sie diese über eine Hash-Tabelle, um Chiffretextpaare zu generieren. Anschließend wird ein entschlüsseltes Modell mit Naive Bayes trainiert.

Modelltrainingsprozess:

  1. Durchlaufen Sie jedes Paar aus Chiffretext und Originaltext im Datensatz, verwenden Sie jedes Zeichen des Originaltexts als Beschriftung und verwenden Sie jedes Zeichen des Chiffretexts als Merkmal, berechnen Sie die Häufigkeit jedes Merkmals in jeder Beschriftung und speichern Sie sie in der Zähler des Features und seine Beschriftungsmitte.

  2. Für jedes Etikett wird die Anzahl der Vorkommen im Trainingssatz gezählt und im Etikettenzähler gespeichert.

  3. Verwenden Sie die Bayes'sche Formel, um die Wahrscheinlichkeit jedes Merkmals zu berechnen, das jeder Beschriftung entspricht, und speichern Sie die Berechnungsergebnisse im Modell.

  Nach Abschluss des Trainings kann das Modell für den eingegebenen Chiffretext verwendet werden, um die Beschriftungswahrscheinlichkeit zu berechnen, die jedem Merkmal entspricht, und dann wird die Beschriftung mit der höchsten Wahrscheinlichkeit als Entschlüsselungsergebnis verwendet.


4. Der naive Bayes'sche Algorithmus knackt den Verschlüsselungsalgorithmus zur zufälligen Zeichenersetzung basierend auf der Hash-Tabelle

  1. Bereiten Sie den Datensatz vor:
      Generieren Sie zufällig eine bestimmte Anzahl von Zeichenfolgen, ersetzen Sie dann zufällige Zeichen durch die Hash-Tabelle, stellen Sie eine entsprechende Beziehung zwischen dem erhaltenen Chiffretext und der Originalzeichenfolge her und verwenden Sie diese als Trainingsdatensatz.

  2. Erstellen Sie ein Modell:
      Erstellen Sie mit dem naiven Bayes'schen Algorithmus ein Trainingsmodell und berechnen Sie die Wahrscheinlichkeit, dass jedes Zeichen durch ein anderes Zeichen ersetzt wird.

  3. Knacken und berechnen Sie die Genauigkeitsrate:
      Generieren Sie erneut zufällig eine ausreichende Anzahl von Zeichenfolgen und verschlüsseln Sie sie außerdem mit einem Hash-Tabellen-basierten Verschlüsselungsalgorithmus zum Ersetzen zufälliger Zeichen, um einen Testsatz zu erhalten. Gemäß dem trainierten Modell wird der naive Bayes'sche Algorithmus verwendet, um den Chiffretext des Testsatzes zu knacken, und die Genauigkeit des Modells wird berechnet und gezählt.


5. Sicherheitsanalyse

  Der Code wird durch den naiven Bayes'schen Algorithmus geknackt und die Beziehungskurve zwischen der Anzahl der Chiffretextzeichen und der Genauigkeitsrate wird statistisch gezeichnet. Wie nachfolgend dargestellt:

  Aus der Kurve in der Abbildung ist ersichtlich, dass das Modell, wenn es etwa 60.000 Chiffretextzeichen abfängt, 60–70 % des Chiffretexts knacken kann. Beim Abfangen von etwa 100.000 Chiffretextzeichen können etwa 80 % des Chiffretexts entschlüsselt werden. Also weniger Sicherheit.


6. Machbare Verbesserungsmethoden

Hier sind zwei mögliche Möglichkeiten, den Verschlüsselungsalgorithmus zu verbessern, um seine Sicherheit zu erhöhen:

  1. Erhöhen Sie die Anzahl der Zeichen im Zeichensatz: Die Größe des ursprünglichen Zeichensatzes beträgt 37. Sie können die Anzahl der Zeichensätze erhöhen, um die Sicherheit der Verschlüsselung zu erhöhen. Bei dieser Methode muss jedoch berücksichtigt werden, ob ein bestimmtes Zeichen verwendet werden soll Fügen Sie es konzentriert dem Charakter hinzu. Wenn es nicht erforderlich ist, ein bestimmtes Zeichen im Klartext zu verwenden, muss es nicht hinzugefügt werden. Daher halte ich es für unpraktisch, die Sicherheit der Verschlüsselung auf diese Weise zu erhöhen.

  2. Erhöhen Sie die Anzahl der jedem Zeichen zugewiesenen Zeichen: Die ursprüngliche Anzahl der zugewiesenen Zeichen beträgt 1771, und die Sicherheit der Verschlüsselung kann verbessert werden, indem die Anzahl der jedem Zeichen zugewiesenen Zeichen erhöht wird. Und diese Steigerung kann unbegrenzt sein, das heißt, wenn die Anzahl der zugewiesenen Zeichen groß genug ist, kann die Sicherheit der Verschlüsselungsmethode unendlich verbessert werden.


7. Zusammenfassung

  In diesem Artikel werden der Verschlüsselungsalgorithmus zur zufälligen Zeichenersetzung basierend auf einer Hash-Tabelle und seine Sicherheitsprobleme untersucht, der naive Bayes'sche Algorithmus zum Knacken des Verschlüsselungsalgorithmus verwendet und die Ergebnisse des Knackens analysiert und diskutiert. Die Ergebnisse zeigen, dass die Sicherheit des Verschlüsselungsalgorithmus unzureichend ist und er leicht geknackt werden kann.

Supongo que te gusta

Origin blog.csdn.net/weixin_57807777/article/details/129146843
Recomendado
Clasificación