我正在尝试加密和解密包括XOR功能。对于某些输入集,Big Integer正在被正确转换为加密文本(密码)并且能够解密它。但是对于某些输入集,Big Integer不会转换回加密文本(密码)。我想知道我哪里出错了。
示例(密码转换回加密文本)输入:“client1”
加密...
加密: w] h“iÐÿ
二进制密文:111011101011101011010000010001001101001110100000001011111111111
用于二进制异或的密钥:100010111010101
二进制的XORed Cipher文本:111011101011101011010000010001001101001110100000101001000101010
用于二进制逆XOR的键:100010111010101
在xoring111011101011101011010000010001001101001110100000001011111111111之后检索到的二进制密文
通过xoring w] h“iÐÿ来检索密文
不加密:client1
解密文本:client1
示例(未转换为加密文本)输入:“client2”
加密...
加密: 5 ^ÉœÇZ!R
二进制密文:11010101011110110010010101001111000111010110100010000101010010
用于二进制异或的密钥:100010111010101
XORed Cipher二进制文本:11010101011110110010010101001111000111010110100110010010000111
用于二进制逆XOR的键:100010111010101
xoring11010101011110110010010101001111000111010110100010000101010010后检索到的二进制密文
xoring 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;
}
}
非常感谢任何帮助。感谢!!!
答案 0 :(得分:1)
问题1:(可移植性)
请注意,SecureRandom(seed)
并不总是取决于种子
在提供相同的种子时,你获得相同密钥的事实几乎100%意味着你在Windows上运行它。
您在XOR()
中使用的构造可能更具可移植性。即。
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
random.setSeed(seed);
问题2:(也许是您所看到的来源)
来自String(byte [] bytes)
的Javadoc:
使用平台的默认字符集解码指定的字节数组,构造一个新的String。 [...] 当指定的字节在默认字符集中无效时,此构造函数的行为未指定。
...并且你正在为它提供cipertext,它可能包含这样的无效字节序列。
您可能想要测试Arrays.equals(new String(encrypted).getBytes(), encrypted)
是否在转换中丢失任何内容。如果您必须将其设为String
,请查看“base64编码”。它的设计完全是为了将任意字节转换为合法的字符编码。
或者,您可能希望将密文保留为字节数组,或者使用BigInteger
构造函数初始化BigInteger(byte [])
。
一个谨慎的注意事项:请注意,BigInteger是一个签名的 bigint类,因此toByteArray
方法可以在必要时添加前导零,以消除其MSb集合的正值的歧义。这需要一些处理,但可以通过将BigInteger
与BigInteger.ZERO
进行比较来预测。
问题3:(可移植性)
convertStringToBigInteger
中的这一行假定为8位字符。
b.shiftLeft(8);
byte
在Java中是8位,但字符可以是8位或16位,我也不会惊讶地看到更新允许32位unicode char
。
迭代String#getBytes()
的结果会更安全......或者更好的是,跳过转换为字符串,并将中间词保留为字节数组,或BigIntegers
(使用BigInteger#toByteArray )
次要事情
您可以使用BigInteger.ZERO
代替new BigInteger("0")
如果您缩进代码,我们将能够更轻松地阅读您的代码。