1
votes

I use the following openssl commands to generate a private/public key pair and encrypt a (short) message using openssl as well:

    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

Then I try to use the following java code to decrypt the encrypted message:

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;

   }
}

When run using

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

I get

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

I get always this kind of exception, no matter how long the key (experimented with keys of length 8192 bytes) or the original text (tried it with one single character), that was encrypted with openssl is.

My primary questions are:

  1. Is this error message really due to the well known RSA limit on message size or am I doing something wrong here so that the same exception is thrown?

  2. Is there a way to modify the code with little effort so that I will be able to use, e.g. an AES-encrypted RSA key which should overcome the message size limit and how could this be achieved?

1

1 Answers

0
votes

You are not decoding the base 64 encoded encrypted message. Before you decrypt cypher_bytes, decode first.

Change

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

to

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