大整数未按 java 中的预期转换为字符串

Big integer not getting converted to String as expected in java

我正在尝试加密和解密,包括 XOR 函数。对于某些输入集,Big Integer 正在正确转换为加密文本(密码)并且能够对其进行解密。但是对于某些输入集,大整数不会转换回加密文本(密码)。我在想我哪里出错了。

示例(密码转换回加密文本)输入:"client1"

正在加密...
加密:w]h"iÐÿ
二进制密文:111011101011101011010000010001001101001110100000001011111111111
用于二进制 XORing 的密钥:100010111010101
二进制异或密文:111011101011101011010000010001001101001110100000101001000101010
用于二进制反向异或的密钥:100010111010101
xoring111011101011101011010000010001001101001110100000001011111111111
后以二进制检索密文 通过异或运算取回密文 w]h"iÐÿ
解密:client1
解密文本:client1

示例(未转换为加密文本)输入:"client2"

正在加密...
加密:5^ÉœÇZ!R
二进制密文:11010101011110110010010101001111000111010110100010000101010010
用于二进制 XORing 的密钥:100010111010101
二进制异或密文:11010101011110110010010101001111000111010110100110010010000111
用于二进制反向异或的密钥:100010111010101
xoring11010101011110110010010101001111000111010110100010000101010010
后以二进制检索密文 通过异或 5^ÉSÇZ!R

检索回密文

这是我的代码。

import java.math.BigInteger;
import java.security.*;
import javax.crypto.*;

public class MainClass {
    private static String algorithm = "DESede";

    public static void main(String[] args) throws Exception {
        String toEncrypt = "client2";

        System.out.println("Encrypting...");
        BigInteger encrypted1 = encrypt(toEncrypt, "password");

        String decrypted = decrypt(encrypted1, "password");
        System.out.println("Decrypted text: " + decrypted);

    }

    public static BigInteger XOR(String s) throws Exception {
        BigInteger message = convertStringToBigInteger(s);

        SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
        int seed = 10;
        random.setSeed(seed);

        byte[] keyStream = new byte[2];
        random.nextBytes(keyStream);
        BigInteger key = new BigInteger(keyStream);

        BigInteger cipherText = message.xor(key);
        System.out.println("cipher text in binary: " + message.toString(2));
        System.out.println("Key used for XORing in binary: " + key.toString(2));
        System.out.println("XORed Cipher text in binary: " + cipherText.toString(2));
        return cipherText;
    }

    public static String InverseXOR(BigInteger s) throws Exception {
        SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
        int seed = 10;
        random.setSeed(seed);

        byte[] keyStream = new byte[2];
        random.nextBytes(keyStream); //generate random bytes in put in keyStream
        BigInteger key = new BigInteger(keyStream);

        BigInteger receivedMessage = s.xor(key);
        System.out.println("Key used for Inverse XORing in binary: " + key.toString(2));
        System.out.println("retrieved cipher text in binary after xoring" + receivedMessage.toString(2));
        String receivedMessageString = convertBigIntegerToString(receivedMessage);
        System.out.println("Cipher Text retrieved back by xoring " + receivedMessageString);
        return receivedMessageString;
    }

    private static String convertBigIntegerToString(BigInteger b) {
        String s = new String();
        while (b.compareTo(BigInteger.ZERO) == 1) {
            BigInteger c = new BigInteger("11111111", 2);
            int cb = (b.and(c)).intValue();
            Character cv = new Character((char) cb);
            s = (cv.toString()).concat(s);
            b = b.shiftRight(8);
        }
        return s;
    }

    private static BigInteger convertStringToBigInteger(String s) {
        BigInteger b = new BigInteger("0");
        for (int i = 0; i < s.length(); i++) {
            Integer code = new Integer((int) s.charAt(i));
            BigInteger c = new BigInteger(code.toString());
            b = b.shiftLeft(8);
            b = b.or(c);
        }
        return b;
    }

    public static BigInteger encrypt(String toEncrypt, String key) throws Exception {

        SecureRandom sr = new SecureRandom(key.getBytes());
        KeyGenerator kg = KeyGenerator.getInstance(algorithm);
        kg.init(sr);
        SecretKey sk = kg.generateKey();

        Cipher cipher = Cipher.getInstance(algorithm);

        cipher.init(Cipher.ENCRYPT_MODE, sk);

        byte[] encrypted = cipher.doFinal(toEncrypt.getBytes());
        String encrypt = new String(encrypted);
        System.out.println("Encrypted : " + encrypt);
        BigInteger XoredData = XOR(encrypt);
        return XoredData;

    }

    public static String decrypt(BigInteger encrypted1, String key) throws Exception {
        String encryptedCipher = InverseXOR(encrypted1);
        byte[] encryptedByte = encryptedCipher.getBytes();

        SecureRandom sr = new SecureRandom(key.getBytes());
        KeyGenerator kg = KeyGenerator.getInstance(algorithm);
        kg.init(sr);
        SecretKey sk = kg.generateKey();

        Cipher cipher = Cipher.getInstance(algorithm);
        cipher.init(Cipher.DECRYPT_MODE, sk);
        byte[] decrypted = cipher.doFinal(encryptedByte);
        String decrypt = new String(decrypted);
        System.out.println("Dencrypted : " + decrypt);
        return decrypt;
    }
}

如有任何帮助,我们将不胜感激。谢谢!!!

问题 1:(可移植性)

请注意 SecureRandom(seed) 并不总是取决于种子。
当几乎 100% 提供相同的种子时,您获得相同的密钥这一事实意味着您在 Windows.

上 运行

您在 XOR() 中使用的构造可能更便于携带。即

SecureRandom random = SecureRandom.getInstance("SHA1PRNG"); 
random.setSeed(seed);

问题 2:(可能是您所看到内容的来源)

来自 JavaString(byte [] bytes) 的文档:

Constructs a new String by decoding the specified array of bytes using the platform's default charset. [...] The behavior of this constructor when the given bytes are not valid in the default charset is unspecified.

... 并且您正在向它提供密文,其中可能包含此类无效字节序列。

您可能想测试 Arrays.equals(new String(encrypted).getBytes(), encrypted) 是否在转换中丢失了任何内容。如果您绝对必须将其设置为 String,那么请查看 "base64 encoding"。它正是为将任意字节转换为合法字符编码而设计的。

或者,您可能希望将密文保留为字节数组,或者使用 BigInteger(byte []) 构造函数初始化 BigInteger

一个额外的警告:注意 BigInteger 是一个 signed bigint class,因此 toByteArray 方法可能会在必要时添加前导零消除已设置 MSb 的正值的歧义。这需要一些处理,但可以通过比较 BigIntegerBigInteger.ZERO.

来预测

问题 3:(可移植性)

convertStringToBigInteger 中的这一行假设 8 位 个字符

b.shiftLeft(8);

byte在 Java 中是 8 位的,但字符可以是 8 位或 16 位,看到更新允许 32 位 unicode chars也是。

迭代 String#getBytes() 的结果会更安全......或者更好的是,跳过到字符串的转换,并将中间值保留为字节数组,或 BigIntegers(使用 BigInteger #toByteArray)

小事

您可以使用 BigInteger.ZERO 而不是 new BigInteger("0")

如果您缩进代码,我们将能够更轻松地阅读您的代码。