大整数未按 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 的正值的歧义。这需要一些处理,但可以通过比较 BigInteger
与 BigInteger.ZERO
.
来预测
问题 3:(可移植性)
convertStringToBigInteger
中的这一行假设 8 位 个字符 。
b.shiftLeft(8);
byte
在 Java 中是 8 位的,但字符可以是 8 位或 16 位,看到更新允许 32 位 unicode char
s也是。
迭代 String#getBytes()
的结果会更安全......或者更好的是,跳过到字符串的转换,并将中间值保留为字节数组,或 BigIntegers
(使用 BigInteger #toByteArray)
小事
您可以使用 BigInteger.ZERO
而不是 new BigInteger("0")
如果您缩进代码,我们将能够更轻松地阅读您的代码。
我正在尝试加密和解密,包括 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 的正值的歧义。这需要一些处理,但可以通过比较 BigInteger
与 BigInteger.ZERO
.
问题 3:(可移植性)
convertStringToBigInteger
中的这一行假设 8 位 个字符 。
b.shiftLeft(8);
byte
在 Java 中是 8 位的,但字符可以是 8 位或 16 位,看到更新允许 32 位 unicode char
s也是。
迭代 String#getBytes()
的结果会更安全......或者更好的是,跳过到字符串的转换,并将中间值保留为字节数组,或 BigIntegers
(使用 BigInteger #toByteArray)
小事
您可以使用 BigInteger.ZERO
而不是 new BigInteger("0")
如果您缩进代码,我们将能够更轻松地阅读您的代码。