当前位置: 首页 > 知识库问答 >
问题:

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

戚奇略
2023-03-14

我使用以下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字节的密钥进行实验)或原始文本(用一个字符进行尝试)有多长。

我的主要问题是:

>

  • 这个错误消息真的是由于众所周知的RSA消息大小限制,还是我在这里做错了什么,所以引发了同样的异常?

    是否有一种方法可以轻松修改代码,以便我能够使用,例如AES加密的RSA密钥,该密钥应能克服邮件大小限制?如何实现这一点?

  • 共有1个答案

    王季萌
    2023-03-14

    您没有解码base 64编码的加密消息。在解密密码字节之前,请先解码。

    改变

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

    byte[] cypher_bytes = Base64.getDecoder().decode(cypher);
    
     类似资料:
    • 问题内容: 我需要从文件中读取RSA私钥以对JWT进行签名。我发现了一些有关如何将生成的RSA密钥保存到磁盘的示例,但是没有任何示例显示如何基于文件中的预生成密钥来构建密钥结构。 密钥是这样生成的: 示例密钥: 问题答案: 的组合和应该做的伎俩: 如果您坐在的是PKCS#8编码密钥,则可以执行以下操作:

    • 我正在使用openssl库,我想用BIO从. pem文件中读取公钥。我尝试了这个,但我的rsa变量仍然未初始化: 当我调试应用程序时,它向我显示如下内容: 我的文件有效,密钥是按照PKCS#1格式生成的。我用asn1解析器解析了它。

    • 我使用RSA_public_encrypt函数发送加密数据到套接字。我正在读取公钥。使用"pkey=PEM_read_PUBKEY(f, NULL, NULL, NULL);"函数的PEM文件。从上面的函数中检索的pkey是类型EVP_PKEY*,我不能在函数RSA_public_encrypt中使用。(RSA_public_encrypt使用RSA*类型密钥) 如何将EVP_PKEY*PKEY转

    • 问题内容: 我有PEM格式+ PKCS#1(我想)的RSA公钥: 我想在Python中获取其ASN1编码版本的SHA1摘要。第一步应该是读取此密钥,但是我在PyCrypto中无法做到这一点: PyCrypto的文档说支持PEM + PKCS#1,所以我很困惑。我也尝试过M2Crypto,但事实证明M2Crypto不支持PKCS#1,而仅支持X.509。 问题答案: PyCrypto支持 PKCS#

    • 我想使用java从pfx文件中提取有关RSA公钥的信息。 我有一个pfx文件,并转换为x509 Pem文件。从pem文件,使用下面的命令在终端: 我可以查看公钥指数和模值 主题公钥信息: 如何在java中提取上述信息? 输入:PFX文件和密码 输出:公钥指数和模值。 我使用下面的代码来提取公钥指数和模数,但我没有得到使用openssl提取的值。我怀疑java.security.cert.证书是否使

    • 我知道这很难...但我使用OpenSSL以一种非常标准的方式加密文件。该文件使用RSA-2048公钥在AES-256中加密。我想在Java中使用私钥解密文件。我研究了很长时间,尝试了很多方法,但似乎都行不通。我只是找到相关的问题与工作的解决方案,但不是确切地为我的问题。 我使用以下命令生成public-/private-key-pair: