我使用以下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
我总是会遇到这种异常,无论密钥(用长度为8192字节的密钥进行实验)还是用openssl加密的原始文本(用一个字符尝试过)多久。
我的主要问题是:
此错误消息是否真的是由于众所周知的RSA消息大小限制引起的,还是我在这里做错了什么,所以引发了相同的异常?
是否有一种方法可以轻松修改代码,以便能够使用,例如应该克服消息大小限制的AES加密RSA密钥,如何实现?
答案 0 :(得分:0)
您不对base 64编码的加密消息进行解码。在解密cypher_bytes
之前,请先解码。
更改
byte[] cypher_bytes = cypher.getBytes( StandardCharsets.UTF_8 );
到
byte[] cypher_bytes = Base64.getDecoder().decode(cypher);