使用 java RSA 加密,使用 BigInteger 解密
encryption with java RSA and decryption with BigInteger
所以我想弄清楚如何在 java 中加密和解密 RSA。使用 javas API 进行加密,使用 biginteger 进行解密。我完成了,但 biginteger 有时会给我奇怪的输出。这是我的代码:
import java.math.BigInteger;
import java.security.InvalidKeyException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.Security;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
public class cryptoAndBigIntegerFIX {
public static void main(String[] args) throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeyException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, InvalidKeySpecException{
Security.addProvider(new BouncyCastleProvider());
System.out.println("input <> encrypted <> decrypted");
cryptoAndBigIntegerFIX.keygen();
BigInteger encryptbytes;
BigInteger decryptbytes;
//Multiple tests with powers of 3 for some reason :D
for(int i=1;i<1000;i*=3){
encryptbytes = cryptoAndBigIntegerFIX.encrypt(new BigInteger(""+i));
System.out.print(i + " <> " + encryptbytes.intValue() + " <> ");
decryptbytes = cryptoAndBigIntegerFIX.decrypt(encryptbytes);
System.out.println(decryptbytes.intValue());
}
}
public static RSAPrivateKey priv;
public static RSAPublicKey pub;
public static void keygen() throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeySpecException{
KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
generator.initialize(512);
KeyPair keyPair = generator.generateKeyPair();
priv = (RSAPrivateKey) keyPair.getPrivate();
pub = (RSAPublicKey) keyPair.getPublic();
}
//Encrypt with javas API
public static BigInteger encrypt(BigInteger bg) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, NoSuchProviderException{
byte[] encoded;
Cipher cipher=Cipher.getInstance("RSA/ECB/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, pub);
encoded=cipher.doFinal(bg.toByteArray());
return new BigInteger(encoded);
}
//Decrypt manually
public static BigInteger decrypt(BigInteger bg){
BigInteger decoded = bg.modPow(priv.getPrivateExponent(),priv.getModulus());
return decoded;
}
}
给出的输出是:
input <> encrypted <> decrypted
1 <> 1 <> 1
3 <> 1088098617 <> 3
9 <> 1947497039 <> 9
27 <> -1665331145 <> 27
81 <> -1064046970 <> 81
243 <> -599005266 <> 243
729 <> -1534949160 <> 729
这是正确的,因为我正在尝试加密和解密三的幂。
但有时它会给出错误的输出,如:
input <> encrypted <> decrypted
1 <> 1 <> 1
3 <> 1693488667 <> 3
9 <> -924345856 <> 9
27 <> 777525903 <> 144224668
81 <> -1602799071 <> 765474161
243 <> -227258229 <> 243
729 <> 1097077312 <> 296615835
哪个很奇怪?知道我的代码有什么问题吗?这是 biginteger 的问题还是我生成密钥的方式的问题?
您的代码中有两个错误,请在正确的输出中修复这些结果:
- RSA returns 表示 unsigned(大端)值编码的字节数组,而
BigInteger
构造函数需要 signed(大端)值;
- 你使用
intValue
将你的 ~512 位整数转换为 32 位 int
,这是一个 narrowing 转换(即你失去了大部分信息);
要解决此问题,请在您的主程序中使用以下代码:
for (int i = 1; i < 1000; i *= 3) {
encryptbytes = encrypt(new BigInteger("" + i));
decryptbytes = decrypt(encryptbytes);
System.out.printf("%d <> %d <> %d%n", i, encryptbytes, decryptbytes); // <-- CHANGED
}
并像这样修正你的 encrypt
方法:
public static BigInteger encrypt(BigInteger bg) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, NoSuchProviderException{
byte[] encoded;
Cipher cipher=Cipher.getInstance("RSA/ECB/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, pub);
encoded=cipher.doFinal(bg.toByteArray());
// always return a positive number, all numbers in RSA range from 0 to N, the modulus
return new BigInteger(1, encoded); // <-- CHANGED
}
输出:
1 <> 1 <> 1
3 <> 5391244976364305547335484748020521942086098609617330384518129302949818422340576199311962549547267600132422679070440104879858341377467952359964277978034437 <> 3
9 <> 6124821216540311592072512276604516925109106437800474377305024835746311326643844937438898166014089888517013623381274703706957136996030394061334489396421471 <> 9
27 <> 7417955231776825208837885603385850571492475371613109504900294367112291012186031184819506881671785651668774452694772296927652149185293472327267855826108811 <> 27
81 <> 4379633872520787556108807271103986910459839084415924804306544674047140392288351081810043910720852387318488882506988222018682090612584816530149697340650488 <> 81
243 <> 7246933972891920591130671309726014055879369415307203680175037003794552795366338573568427805702031164261947749468386326443821678079330776559688467025349997 <> 243
729 <> 1545447812776244759821683256943744637177323415383752406121617316817182282617298911713206245407992744746920675542053503316837741108184755354755351275313816 <> 729
其他读者的警告:永远不要使用 plaintext/raw RSA(Java 中的 "RSA/ECB/NoPadding"
),它是不安全的。尝试使用 RSA OAEP 的混合密码系统。 不要 copy/paste上面的代码。
所以我想弄清楚如何在 java 中加密和解密 RSA。使用 javas API 进行加密,使用 biginteger 进行解密。我完成了,但 biginteger 有时会给我奇怪的输出。这是我的代码:
import java.math.BigInteger;
import java.security.InvalidKeyException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.Security;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
public class cryptoAndBigIntegerFIX {
public static void main(String[] args) throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeyException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, InvalidKeySpecException{
Security.addProvider(new BouncyCastleProvider());
System.out.println("input <> encrypted <> decrypted");
cryptoAndBigIntegerFIX.keygen();
BigInteger encryptbytes;
BigInteger decryptbytes;
//Multiple tests with powers of 3 for some reason :D
for(int i=1;i<1000;i*=3){
encryptbytes = cryptoAndBigIntegerFIX.encrypt(new BigInteger(""+i));
System.out.print(i + " <> " + encryptbytes.intValue() + " <> ");
decryptbytes = cryptoAndBigIntegerFIX.decrypt(encryptbytes);
System.out.println(decryptbytes.intValue());
}
}
public static RSAPrivateKey priv;
public static RSAPublicKey pub;
public static void keygen() throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeySpecException{
KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
generator.initialize(512);
KeyPair keyPair = generator.generateKeyPair();
priv = (RSAPrivateKey) keyPair.getPrivate();
pub = (RSAPublicKey) keyPair.getPublic();
}
//Encrypt with javas API
public static BigInteger encrypt(BigInteger bg) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, NoSuchProviderException{
byte[] encoded;
Cipher cipher=Cipher.getInstance("RSA/ECB/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, pub);
encoded=cipher.doFinal(bg.toByteArray());
return new BigInteger(encoded);
}
//Decrypt manually
public static BigInteger decrypt(BigInteger bg){
BigInteger decoded = bg.modPow(priv.getPrivateExponent(),priv.getModulus());
return decoded;
}
}
给出的输出是:
input <> encrypted <> decrypted
1 <> 1 <> 1
3 <> 1088098617 <> 3
9 <> 1947497039 <> 9
27 <> -1665331145 <> 27
81 <> -1064046970 <> 81
243 <> -599005266 <> 243
729 <> -1534949160 <> 729
这是正确的,因为我正在尝试加密和解密三的幂。 但有时它会给出错误的输出,如:
input <> encrypted <> decrypted
1 <> 1 <> 1
3 <> 1693488667 <> 3
9 <> -924345856 <> 9
27 <> 777525903 <> 144224668
81 <> -1602799071 <> 765474161
243 <> -227258229 <> 243
729 <> 1097077312 <> 296615835
哪个很奇怪?知道我的代码有什么问题吗?这是 biginteger 的问题还是我生成密钥的方式的问题?
您的代码中有两个错误,请在正确的输出中修复这些结果:
- RSA returns 表示 unsigned(大端)值编码的字节数组,而
BigInteger
构造函数需要 signed(大端)值; - 你使用
intValue
将你的 ~512 位整数转换为 32 位int
,这是一个 narrowing 转换(即你失去了大部分信息);
要解决此问题,请在您的主程序中使用以下代码:
for (int i = 1; i < 1000; i *= 3) {
encryptbytes = encrypt(new BigInteger("" + i));
decryptbytes = decrypt(encryptbytes);
System.out.printf("%d <> %d <> %d%n", i, encryptbytes, decryptbytes); // <-- CHANGED
}
并像这样修正你的 encrypt
方法:
public static BigInteger encrypt(BigInteger bg) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, NoSuchProviderException{
byte[] encoded;
Cipher cipher=Cipher.getInstance("RSA/ECB/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, pub);
encoded=cipher.doFinal(bg.toByteArray());
// always return a positive number, all numbers in RSA range from 0 to N, the modulus
return new BigInteger(1, encoded); // <-- CHANGED
}
输出:
1 <> 1 <> 1
3 <> 5391244976364305547335484748020521942086098609617330384518129302949818422340576199311962549547267600132422679070440104879858341377467952359964277978034437 <> 3
9 <> 6124821216540311592072512276604516925109106437800474377305024835746311326643844937438898166014089888517013623381274703706957136996030394061334489396421471 <> 9
27 <> 7417955231776825208837885603385850571492475371613109504900294367112291012186031184819506881671785651668774452694772296927652149185293472327267855826108811 <> 27
81 <> 4379633872520787556108807271103986910459839084415924804306544674047140392288351081810043910720852387318488882506988222018682090612584816530149697340650488 <> 81
243 <> 7246933972891920591130671309726014055879369415307203680175037003794552795366338573568427805702031164261947749468386326443821678079330776559688467025349997 <> 243
729 <> 1545447812776244759821683256943744637177323415383752406121617316817182282617298911713206245407992744746920675542053503316837741108184755354755351275313816 <> 729
其他读者的警告:永远不要使用 plaintext/raw RSA(Java 中的 "RSA/ECB/NoPadding"
),它是不安全的。尝试使用 RSA OAEP 的混合密码系统。 不要 copy/paste上面的代码。