java:使用从PEM文件读取的RSA公钥解密数据时,如何避免IllegalBlockSizeException



我使用以下openssl命令生成私钥/公钥对,并使用openssl加密(短(消息:

openssl genrsa -out /root/priv.pem
openssl rsa -in /root/priv.pem -out /root/pub.pem -pubout
echo "hello" | openssl rsautl -encrypt -pubin -inkey /root/pub.pem | base64 > cipher.txt

然后我尝试使用以下java代码来解密加密的消息:

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.Scanner;
import org.apache.commons.cli.*;
import org.apache.commons.cli.Option;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
//import org.bouncycastle.util.io.pem.PemReader;
import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.openssl.PEMKeyPair;
//import org.bouncycastle.openssl.PasswordFinder;
import javax.crypto.Cipher;
import java.security.Security;
import java.security.KeyPair;
import java.security.Key;
import java.security.KeyFactory;
import java.security.spec.RSAPrivateCrtKeySpec;
public class DecryptRSA {
public static void main( String [] args ) throws Exception {
String priv_key_path = System.getProperty( "user.home" ) + "/priv.pem";
String cypher_file_path = null;
String cypher = "";
String plain = null;
/*
* Parse the command line
*/
Options options = new Options();
Option cypher_file = new Option( "c", "cypher_file_path", true, "path to cypher file" );
options.addOption( cypher_file );
Option  priv_key = new Option( "k", "priv_key_path", true, "path to private key file" );
options.addOption( priv_key );
CommandLineParser clp = new DefaultParser();
HelpFormatter helpformatter = new HelpFormatter();
CommandLine cmd = null;
try {
cmd = clp.parse( options, args );
} catch ( ParseException e ) {
System.out.println( e.getMessage() );
helpformatter.printHelp( "DecryptRSA", options );
System.exit(1);
}
cypher_file_path = cmd.getOptionValue("c");
/*
* Read cypher text
*/ 
if ( cypher_file_path == null ) {
BufferedReader input = new BufferedReader(new InputStreamReader( System.in ) );
String input_line = null;
while( ( input.readLine() ) != null ) {    
cypher += input_line;
}
}
else {
cypher = new Scanner( new File( cypher_file_path ) ).useDelimiter("\Z").next();
}
System.out.println( cypher );
String priv_key_path_tmp = cmd.getOptionValue("k");
if ( priv_key_path_tmp != null ) {
priv_key_path = priv_key_path_tmp;
}
/*
* Decrypt the cipher text
*/
//Security.addProvider( new BouncyCastleProvider() );
Security.addProvider( new org.bouncycastle.jce.provider.BouncyCastleProvider() );
File key_file = new File( priv_key_path );
KeyPair kp = getKeyPairFromFile( key_file ); 
byte[] cypher_bytes = cypher.getBytes( StandardCharsets.UTF_8 );
plain = decrypt( kp.getPrivate(), cypher_bytes ); 
System.out.println( plain );
}

private static KeyPair getKeyPairFromFile( File key_file ) throws IOException {
FileReader fileReader = new FileReader( key_file );
PEMParser pemParser = new PEMParser(new FileReader( key_file ));
Object object = pemParser.readObject();
JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider("BC");
KeyPair kp;
kp = converter.getKeyPair((PEMKeyPair) object);
return kp;  
}
private static String decrypt( Key decrypt_key, byte[] buf ) {
try {
Cipher crypt_algo;
crypt_algo = Cipher.getInstance("RSA");
crypt_algo.init( Cipher.DECRYPT_MODE, decrypt_key );
byte[] utf8 = crypt_algo.doFinal( buf );
return new String( utf8, "UTF8" );
} catch ( Exception e ) {
e.printStackTrace();
}
return null;
}
}

使用运行时

java DecryptRSA -c cipher.txt -k /root/priv.pem

我得到

psOI9G6Y9oDnIJ5ru3myk18eoS6KKROzED3JYa3cwJVjfDY2q/MRSWgsaLEcAXX8Ngc9PSYXtCAS
oQkWf9hXbAbsFGnvHcbDEcB5GBssN7jfP+gtmv0meYpzk/mBAHXBV76ShA+oVor/Jw7NJPAJp32Q
NhAiT9RC/oOjSut+z94xHpRq1CfYiIit8sIvhMh8BLV/W3nJdyOsS2WlYAS3kmx9oaIsFkIIK6DP
ybLOVwRMV7Pit65o2Vts678fbis3ca+SaY9o/ZOZhu2j0YiF9DFVkVUJtFaiI3QlUzJVticTQd5p
zvrP2uFYAsEnBxX1zpOcUXI5XdvYH4UTpx4DYQ==
javax.crypto.IllegalBlockSizeException: Data must not be longer than 256 bytes
at com.sun.crypto.provider.RSACipher.doFinal(RSACipher.java:344)
at com.sun.crypto.provider.RSACipher.engineDoFinal(RSACipher.java:389)
at javax.crypto.Cipher.doFinal(Cipher.java:2164)
at DecryptRSA.decrypt(DecryptRSA.java:148)
at DecryptRSA.main(DecryptRSA.java:117)
null

我总是遇到这种例外,无论用openssl加密的密钥(用长度为8192字节的密钥进行实验(或原始文本(用一个字符进行尝试(有多长。

我的主要问题是:

  1. 此错误消息真的是由于众所周知的RSA对消息大小的限制,还是我在这里做错了什么,导致引发了相同的异常?

  2. 有没有一种方法可以毫不费力地修改代码,使我能够使用,例如AES加密的RSA密钥,它应该克服消息大小的限制,以及如何实现这一点?

您没有解码基64编码的加密消息。在解密cypher_bytes之前,请先进行解码。

更改

byte[] cypher_bytes = cypher.getBytes( StandardCharsets.UTF_8 );

byte[] cypher_bytes = Base64.getDecoder().decode(cypher);

最新更新