Java中的一次性密码加密

3
我已经在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;
    }

}

1
一次性密码本是一个真正随机的序列。计算机中的随机数生成器并不提供一次性密码本。您所创建的是流密码。 - S.L. Barth
2
我认为你不应该每次获取8位时都创建一个新的SecureRandom实例。这样做会很慢,而且可能并不安全。 - Adder
需要在32位整数中存储每个比特吗?使用每8位的一个字节似乎更合理。在这种情况下,Q1的答案是:返回特定大小的字节数组。同样,您可以使用FileInputStreamFileOutputStream加密/解密文件中的字节,回答Q2。 - Maarten Bodewes
1个回答

1
首先 - 尝试重写应用程序以使用正确的数据类型,这意味着您将使用byte[]类型处理位。然后,读取、写入、异或、编码和解码变得容易。如果没有这样做,很少有人会尝试理解您自己的结构。因此,我进一步假设您会这样做。
接下来 - 实现自己的编码操作(例如stringToBinary)实际上没有任何意义,寻找简单的方法将数据编码为十六进制或base64。对于十六进制,您可以使用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可能会非常缓慢地生成任意(更长)长度的密钥,或者它可能会产生不真正随机的数据。长话短说 - 这就是为什么使用PRNG(我经常看到使用ChaCha或Salsa20流密码作为PRNG)来从初始密钥生成任意长度的随机看数据。
在解密时,我如何从两个文件中读取这两个文件并以二进制形式进行XOR,然后将其打印为ASCLL格式。
一旦您重写应用程序以使用byte[]类型,那么(如Maarten已经评论的那样),您可以使用FileInputStream和FileOutputStream(很容易对字节进行XORa ^ b)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接