使用自己的 RSA 实现加密纯文本



我试图使用我自己的 RSA 在 Java 中的实现来加密和解密一个字符串,最终是一个包含明文的文件。我尝试在SO和网络上遵循无数的例子,其中人们使用内置的Java RSA函数或他们自己的算法实现,但无法让其中任何一个工作,因为解密的文本永远不会匹配原始字符串。

我不知道我是否在文本的编码/解码方面做错了什么,java.xml.*尝试使用默认的 UTF-8 和 Base64 编码器,但也没有运气。我没有使用任何填充,我不知道这是否是它工作所必需的,我只是使用任意键长度,我尝试更改其大小,但也没有使事情正常工作。这只是对我自己的练习,没有人的信息会受到这个或任何东西的保护。但我不确定问题是什么,所以这是我的代码,它试图加密/解密一个简单的字符串:

BigInteger ONE = new BigInteger("1");
SecureRandom rand = new SecureRandom();
BigInteger d;
BigInteger e;
BigInteger n;
BigInteger p = BigInteger.probablePrime(10, rand); // 10 is arbitrary, have tried different numbers
BigInteger q = BigInteger.probablePrime(10, rand);
BigInteger phi = (p.subtract(ONE)).multiply(q.subtract(ONE));
n = p.multiply(q); //10 bits * 10 bits = ??? bits for key length
e = new BigInteger("65537"); //public key exponent 
d = e.modInverse(phi); //private key exponent
String string = "this is a test";
byte[] bytes = string.getBytes();
BigInteger plainText = new BigInteger(bytes);
BigInteger cipherText = plainText.modPow(e, n);
BigInteger originalMessage = cipherText.modPow(d, e);
System.out.println(string.getBytes());
System.out.println(cipherText);
System.out.println(originalMessage);

每次运行程序时,输出对所有三件事都有不同的值: 但它们总是以相同的相对形式:

[B@52d85409
157529
24312

几点说明:

  1. 您的模数(示例中的n)至少需要与要加密的信息量一样长。这是 RSA 的警告之一,这就是为什么像 AES 这样的东西更适合像文件这样的长流。下面我选择了128pq的范围,而不是10,其他值也可以工作。
  2. 这是cipherText.modPow(d, n)
  3. 您必须将 BigInteger 转换回字符串才能正确打印,因此:new String(originalMessage.toByteArray())

把所有的东西放在一起:

BigInteger ONE = new BigInteger("1");
SecureRandom rand = new SecureRandom();
BigInteger d, e, n;
BigInteger p = BigInteger.probablePrime(128, rand);
BigInteger q = BigInteger.probablePrime(128, rand);
BigInteger phi = (p.subtract(ONE)).multiply(q.subtract(ONE));
n = p.multiply(q);
e = new BigInteger("65537");
d = e.modInverse(phi);
String string = "this is a test";
BigInteger plainText = new BigInteger(string.getBytes());
BigInteger cipherText = plainText.modPow(e, n);
BigInteger originalMessage = cipherText.modPow(d, n);
String decrypted = new String(originalMessage.toByteArray());
System.out.println("original: " + string);
System.out.println("decrypted: " + decrypted);

是的,但 E 应该是一个随机数,对 phi 相对质数。所以,E 应该等于这样的东西:

BigInteger e = new BigInteger("65537"); //to make the compiler happy
BigInteger counter = (BigInteger.probablePrime(128, random)).mod(phi);
while(counter.intValue() > 2)
{
if((e.gcd(phi)).intValue() == 1)
{
e = counter;
break;
}
counter = counter.subtract(BigInteger.ONE);
}

此外,在解密不起作用之前,您可以输入的最大字符数为 32。所以要小心。

最新更新