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


1. Einleitung

1.1 Hintergrund

  In der modernen Gesellschaft kommt der Übermittlung und Vertraulichkeit von Informationen eine besondere Bedeutung zu. Um die Datensicherheit zu gewährleisten, verwenden Menschen häufig verschiedene Verschlüsselungsalgorithmen, um Informationen zu verschlüsseln. Allerdings steigt auch die Gefahr, dass herkömmliche Verschlüsselungsalgorithmen von Angreifern geknackt werden. Daher ist es sehr wichtig, einen sichereren Verschlüsselungsalgorithmus zu entwickeln.
  

1.2 Zweck

  Der Zweck dieses Artikels besteht darin, einen einfachen Verschlüsselungsalgorithmus basierend auf Hash-Tabellen vorzustellen. Ich denke jedoch, dass dieser Algorithmus eine hohe Sicherheit und Praktikabilität aufweisen sollte. Der Artikel befasst sich ausführlich mit dem Design und der Implementierung des Algorithmus.


2. Algorithmusdesign

2.1 HashTableCreator-Klasse

  Bei diesem Algorithmus müssen wir zunächst eine Hash-Tabelle erstellen, um die Zuordnungsbeziehung zu speichern. Die HashTableCreator-Klasse wird zum Erstellen von Hash-Tabellen verwendet. Wir können 26 Buchstaben, 10 Zahlen und ein Leerzeichen in der Hash-Tabelle speichern, also insgesamt 37 Zeichen. Für jedes Zeichen generieren wir zufällig eine Liste mit 1771 verschiedenen Zeichen und ordnen die Liste und die Zeichen einer Hash-Tabelle zu.
  

2.2 MessageEncryptor-Klasse

  Die MessageEncryptor-Klasse wird zum Verschlüsseln und Entschlüsseln von Nachrichten verwendet. Diese Klasse nimmt zufällige Zeichen, die jedem Eingabezeichen entsprechen, aus der Hash-Tabelle und kombiniert sie zu einer verschlüsselten Zeichenfolge. Um die Nachricht zu entschlüsseln, müssen wir das verschlüsselte Zeichen mit dem Wert in der Hash-Tabelle vergleichen und bestimmen, welches Zeichen es darstellt.


3. Algorithmusimplementierung

3.1 Implementierung der HashTableCreator-Klasse

  Diese Klasse verwendet HashMap zum Speichern der Hash-Tabelle und die Random-Klasse zum Generieren zufälliger Zeichen. In der Schleife generieren wir für jedes Zeichen eine Liste mit 1771 unterschiedlichen Zeichen und schreiben die Hash-Tabelle mithilfe der ObjectOutputStream-Klasse in eine Datei.

Der Codeteil lautet wie folgt:

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.*;

public class HashTableCreator {
    
    
    public static void main(String[] args) {
    
    
        Map<Character, List<Character>> hashTable = new HashMap<>();
        int numChars = 1771;
        Random rand = new Random();
        Set<Character> existingChars = new HashSet<>();

        for (char c = 'a'; c <= 'z'; c++) {
    
    
            List<Character> charList = new ArrayList<>();
            for (int i = 0; i < numChars; i++) {
    
    
                char randChar;
                do {
    
    
                    randChar = (char) (rand.nextInt(65535));
                    //随机取unicode编码字符
                } while (existingChars.contains(randChar));
                charList.add(randChar);
                existingChars.add(randChar);
            }
            hashTable.put(c, charList);
        }

        for (char c = '0'; c <= '9'; c++) {
    
    
            List<Character> charList = new ArrayList<>();
            for (int i = 0; i < numChars; i++) {
    
    
                char randChar;
                do {
    
    
                    randChar = (char) (rand.nextInt(65535));
                } while (existingChars.contains(randChar));
                charList.add(randChar);
                existingChars.add(randChar);
            }
            hashTable.put(c, charList);
        }

        List<Character> spaceList = new ArrayList<>();
        for (int i = 0; i < numChars; i++) {
    
    
            char randChar;
            do {
    
    
                randChar = (char) (rand.nextInt(65535));
            } while (existingChars.contains(randChar));
            spaceList.add(randChar);
            existingChars.add(randChar);
        }
        hashTable.put(' ', spaceList);

        try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("hashtable.ser"))) {
    
    
            oos.writeObject(hashTable);
        } catch (IOException e) {
    
    
            e.printStackTrace();
        }
    }
}


  

3.2 Implementierung der MessageEncryptor-Klasse

  In dieser Klasse verwende ich die ObjectInputStream-Klasse, um die Hash-Tabelle aus der Datei zu lesen. Dann verwenden wir die Scanner-Klasse, um die zu verschlüsselnde Nachricht aus der Standardeingabe zu lesen und sie als Reihe von Zeichenfolgen zur Verschlüsselung zu verarbeiten. Als nächstes verwenden wir die Random-Klasse, um zufällig ein Zeichen aus der Hash-Tabelle zum Verschlüsseln auszuwählen. Das Entschlüsseln einer Nachricht ist die Umkehrung der Verschlüsselung. Wir verwenden die StringBuilder-Klasse, um verschlüsselte und entschlüsselte Nachrichten zu erstellen.

Der Codeteil lautet wie folgt:

import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Scanner;

public class MessageEncryptor {
    
    
    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;
        }

        System.out.print("请输入要加密的明文:");
        Scanner scanner = new Scanner(System.in);
        String message = scanner.nextLine();

        //对明文做处理,只保留字母、数字和空格,并把字母转换为小写
        message = message.replaceAll("[^a-zA-Z0-9\\s]", "").toLowerCase();

        StringBuilder encryptedMessage = new StringBuilder();
        for (char c : message.toCharArray()) {
    
    
            encryptedMessage.append(hashTable.get(c).get(new Random().nextInt(hashTable.get(c).size()))); // choose one of the characters at random
        }
        System.out.println("密文: " + encryptedMessage);

        StringBuilder decryptedMessage = new StringBuilder();
        for (char c : encryptedMessage.toString().toCharArray()) {
    
    
            if (c == hashTable.get(' ').get(0)) {
    
    
                decryptedMessage.append(' ');
            } else {
    
    
                for (Map.Entry<Character, List<Character>> entry : hashTable.entrySet()) {
    
    
                    if (entry.getValue().contains(c)) {
    
    
                        decryptedMessage.append(entry.getKey());
                        break;
                    }
                }
            }
        }
        System.out.println("解密: " + decryptedMessage.toString());
    }
}


4. Algorithmusleistung

4.1 Sicherheit

  Durch die zufällige Generierung einer Liste von Zeichen und die Verwendung einer Hash-Tabelle zur Zuordnung von Zeichen zu zufälligen Zeichen kann möglicherweise die Sicherheit des Algorithmus gewährleistet werden. Für einen Angreifer ist es schwierig, die Zuordnungsbeziehung in der Hash-Tabelle zu erraten, sodass es schwierig ist, die verschlüsselte Nachricht zu entschlüsseln.
  

4.2 Praktikabilität

  Unser Algorithmus ist sehr einfach, leicht zu implementieren und zu verwenden. Da in der Hash-Tabelle 37 Zeichen gespeichert sind, ist es möglich, viele Arten von Nachrichten zu verschlüsseln, darunter Buchstaben, Zahlen und Sonderzeichen. Gleichzeitig sind die Werte in der Hash-Tabelle zufällig, sodass für jedes Zeichen unterschiedliche verschlüsselte Nachrichten generiert werden können, was die Sicherheit erhöht.
  

4.3 Leistung

  Ich habe einige Benchmarks durchgeführt, um die Leistung des Algorithmus zu bewerten. Die Testumgebung ist Windows 11, der Prozessor ist ein Intel® Core™ i5-12500H der 12. Generation mit 2,50 GHz und der Speicher beträgt 16 GB. Im Test wurden 100.000 Strings der Länge 100 zur Ver- und Entschlüsselung zufällig generiert und die Ausführungszeit aufgezeichnet. Die Testergebnisse zeigen, dass die durchschnittliche Verschlüsselungszeit 0,0117 Millisekunden und die durchschnittliche Entschlüsselungszeit 2,41997 Millisekunden beträgt. Da unser Algorithmus sehr einfach ist, weist er im praktischen Einsatz eine gute Reaktionsfähigkeit auf.

  Die Testklasse ist die BenchmarkTest-Klasse und der Code lautet wie folgt:

import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.List;
import java.util.Map;
import java.util.Random;

public class BenchmarkTest {
    
    
    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;
        }

        int numTests = 100000;
        int messageLength = 100;

        long encryptionTime = 0;
        long decryptionTime = 0;

        for (int i = 0; i < numTests; i++) {
    
    
            String message = generateRandomString(messageLength);

            long startTime = System.currentTimeMillis();
            String encryptedMessage = encryptMessage(hashTable, message);
            long endTime = System.currentTimeMillis();

            encryptionTime += endTime - startTime;

            startTime = System.currentTimeMillis();
            String decryptedMessage = decryptMessage(hashTable, encryptedMessage);
            endTime = System.currentTimeMillis();

            decryptionTime += endTime - startTime;
        }

        double averageEncryptionTime = (double) encryptionTime / numTests;
        double averageDecryptionTime = (double) decryptionTime / numTests;

        System.out.println("平均加密时间: " + averageEncryptionTime + " milliseconds");
        System.out.println("平均解密时间: " + averageDecryptionTime + " milliseconds");
    }

    private static String generateRandomString(int length) {
    
    
        String chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 ";
        StringBuilder sb = new StringBuilder();
        Random random = new Random();
        for (int i = 0; i < length; i++) {
    
    
            int index = random.nextInt(chars.length());
            sb.append(chars.charAt(index));
        }
        return sb.toString();
    }

    private static String encryptMessage(Map<Character, List<Character>> hashTable, String message) {
    
    
        message = message.replaceAll("[^a-zA-Z0-9\\s]", "").toLowerCase();

        StringBuilder encryptedMessage = new StringBuilder();
        for (char c : message.toCharArray()) {
    
    
            encryptedMessage.append(hashTable.get(c).get(new Random().nextInt(hashTable.get(c).size())));
        }
        return encryptedMessage.toString();
    }

    private static String decryptMessage(Map<Character, List<Character>> hashTable, String encryptedMessage) {
    
    
        StringBuilder decryptedMessage = new StringBuilder();
        for (char c : encryptedMessage.toCharArray()) {
    
    
            if (c == hashTable.get(' ').get(0)) {
    
    
                decryptedMessage.append(' ');
            } else {
    
    
                for (Map.Entry<Character, List<Character>> entry : hashTable.entrySet()) {
    
    
                    if (entry.getValue().contains(c)) {
    
    
                        decryptedMessage.append(entry.getKey());
                        break;
                    }
                }
            }
        }
        return decryptedMessage.toString();
    }
}

Die Testergebnisse sind in der Abbildung dargestellt:
Fügen Sie hier eine Bildbeschreibung ein


5. Algorithmusanzeige

Wie nachfolgend dargestellt:
Fügen Sie hier eine Bildbeschreibung ein


6. Fazit

  In diesem Artikel wird ein einfacher Verschlüsselungsalgorithmus vorgestellt, der auf einer Hash-Tabelle basiert. Was die Leistung angeht, habe ich Benchmarks durchgeführt und gute Ergebnisse erzielt. Da es sich bei meinem Algorithmus jedoch um einen symmetrischen Verschlüsselungsalgorithmus handelt, kann es zu einigen Schwierigkeiten bei der Schlüsselverteilung und -verwaltung kommen. Und ich weiß nicht, ob dieser Algorithmus eine hohe Sicherheit und Praktikabilität aufweist oder ob er für viele Arten der Nachrichtenverschlüsselung geeignet ist. Wenn jemand bereit ist, kann er ihn auch für mich testen, vielen Dank.

Supongo que te gusta

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