Шифрование одноразового блокнота в java

Я создал одноразовое шифрование в java, но у меня есть две проблемы:

  1. В шифровании, как я могу сделать размер ключа гибким в соответствии с размером открытого текста и сгенерированным случайным образом, например, размер открытого текста составляет 4 буквы, поэтому размер ключа массива должен быть 32-битным, потому что каждый письмо имеет 8 бит.

  2. В расшифровке, как я могу читать файлы и эти два файла в двоичной форме, а затем выполнять XOR между ними, а затем распечатывать его как форму ASCLL.


Мой код:

public class onetimepad {

    public static void main(String[] args) throws Exception {

        int[] key = generate8BitKey();

        Scanner in = new Scanner(System.in);
        System.out.println(" One Time Pad encryption and decryption ");
        System.out.println(" For encryption Enter 1 ");
        System.out.println(" For decryption Enter 2 ");
        System.out.println(" Exit Enter 3 ");
        int a = in.nextInt();

        switch (a) {
            case 1:

                File input = new File("message.txt");
                Scanner sc = new Scanner(input);
                String msg = sc.nextLine();
                System.out.println("Key:    ");

                //Write the Key in file.
                PrintWriter writer2 = new PrintWriter("Output.txt", "UTF-8");
                writer2.println("------ Key ------- ");
                for (int i : key) {

                    System.out.print(key[i]);
                    writer2.print(key[i]);

                }
                writer2.close();

                System.out.println();
                String ciphertext = encrypt(msg, key);
                System.out.println("Encrypted Message: " + ciphertext);
                 break;
            case 2:
                 File input2 = new File("ciphertext.txt");
                Scanner sc2 = new Scanner(input2);
                String msg2 = sc2.nextLine();
                File input3 = new File("Key.txt");
                Scanner sc3 = new Scanner(input3);
                String msg3 = sc2.nextLine();


                 System.out.println("Decrypted Message: " + decrypt(msg3, key));
                break;
            default:
        }

    }// End the main.

    //------------------- Methods.
    public static String encrypt(String msg, int[] key) {
        int[] binmsg = stringToBinary(msg);
        int[] result = xor(binmsg, repeatArray(key, msg.length()));
        String r = "";
        for (int i : result) {
            r += (char) (result[i] + '0');
        }

        return r;
    }

    //---------------------
    public static String decrypt(String ciphertext, int[] key) {
        int[] bin = new int[ciphertext.length()];
        for (int i = 0; i < ciphertext.length(); i++) {
            bin[i] = ciphertext.charAt(i) - '0';
        }
       int[] result = xor(bin, repeatArray(key, bin.length / 8));
        return binaryToString(result);
    }

    //---------------------
    public static int[] stringToBinary(String msg) {
        int[] result = new int[msg.length() * 8];
        for (int i = 0; i < msg.length(); i++) {
            String bin = Integer.toBinaryString((int) msg.charAt(i));
            while (bin.length() < 8) {
                bin = "0" + bin;
            }
            for (int j = 0; j < bin.length(); j++) {
                result[i * 8 + j] = bin.charAt(j) - '0';
            }
        }
        return result;
    }

    //---------------------
    public static String binaryToString(int[] bin) {
        String result = "";
        for (int i = 0; i < bin.length / 8; i++) {
            String c = "";
            for (int j = 0; j < 8; j++) {
                c += (char) (bin[i * 8 + j] + '0');
            }
            result += (char) Integer.parseInt(c, 2);
        }
        return result;
    }

    //---------------------
    public static int[] generate8BitKey() {
        int[] key = new int[8];
        for (int i = 0; i < 8; i++) {
            SecureRandom sr = new SecureRandom();
            key[i] = sr.nextInt(2);
        }
        return key;
    }

    //---------------------
    public static int[] xor(int[] a, int[] b) {
        int[] result = new int[a.length];
        for (int i = 0; i < a.length; i++) {
            result[i] = a[i] == b[i] ? 0 : 1;
        }
        return result;
    }

   //---------------------
   public static int[] repeatArray(int[] a, int n) {
        int[] result = new int[a.length * n];
        for (int i = 0; i < result.length; i++) {
            result[i] = a[i % a.length];  // mod 
        }
        return result;
    }

}

person abdurrhman al jedaani    schedule 19.10.2018    source источник
comment
Одноразовый блокнот - это действительно случайная последовательность. ГСЧ в компьютере не предоставляют одноразовых блокнотов. Вы создали потоковый шифр.   -  person S.L. Barth    schedule 19.10.2018
comment
Я считаю, что вам не следует создавать новый экземпляр SecureRandom каждый раз, когда вы извлекаете 8 бит. Это медленно и, возможно, даже не безопаснее.   -  person Adder    schedule 19.10.2018
comment
Требуется ли хранить каждый бит в 32-битном целом числе? Кажется более логичным использовать один байт на каждые 8 ​​бит. В этом случае ответ Q1: вернуть массив байтов определенного размера. Точно так же вы можете просто зашифровать / расшифровать байты в файлах, используя FileInputStream и FileOutputStream, отвечая на Q2.   -  person Maarten Bodewes    schedule 22.10.2018


Ответы (1)


Во-первых, попробуйте переписать ваше приложение, чтобы использовать правильные типы данных, то есть вы будете работать с типом byte[] с битами как битами. Тогда его легко читать, писать, xor, кодировать, декодировать. Без него очень немногие люди попытаются понять ваши собственные конструкции. Так что я буду предполагать, что вы это сделаете.

Далее - действительно нет смысла реализовывать собственные операции кодирования (например, stringToBinary), ищите простые способы кодирования ваших данных в hex или base64. Для Hex вы можете использовать org.apache.commons.codec.binary.Hex, для Base64 у вас уже есть java.util.Base64 класс. Он будет более читабельным для вас и всех, кто готов помочь.

В шифровании, как я могу сделать размер ключа гибким в соответствии с размером открытого текста и сгенерированным случайным образом, например, размер открытого текста составляет 4 буквы, поэтому размер ключа массива должен быть 32-битным, потому что каждый письмо имеет 8 бит.

Предполагая, что вы наконец переписали свое приложение для работы с байтовыми массивами, вы можете написать

SecureRandom sr = new SecureRandom();
byte[] keyBytes = new bytes[4];
sr.nextBytes (keyBytes);

Это сгенерирует 4 байта с высокой энтропией. Однако есть проблема со всем подходом:

  • Чтобы расшифровать данные, вам нужно будет сохранить ключ длины сообщения, и вы можете использовать ключ только один раз с одним сообщением (это функция одноразового блокнота).

  • Представьте, что у вас есть гораздо более длинное сообщение, скажем, в килобайтах. SecureRandom может очень медленно генерировать ключ произвольной (большей) длины или может генерировать не совсем случайные данные. Короче говоря - вот почему используются ГПСЧ (часто я вижу, что в качестве ГПСЧ используются потоковые шифры ChaCha или Salsa20) для генерации произвольной длины случайно просматриваемых данных из начального ключа.

В расшифровке, как я могу читать файлы и эти два файла в двоичной форме, а затем выполнять XOR между ними, а затем распечатывать его как форму ASCLL.

После того, как вы переписываете свое приложение для использования byte[] типов, тогда (как уже прокомментировал Маартен) у вас есть FileInputStream и FileOutputStream в вашем распоряжении (и это легко выполнить XOR байтов a ^ b)

person gusto2    schedule 23.10.2018