【问题标题】:RSA decryption error with PKCS#1: javax.crypto.IllegalBlockSizeException: Data must not be longer than 256 bytesPKCS#1 的 RSA 解密错误:javax.crypto.IllegalBlockSizeException:数据不得超过 256 字节
【发布时间】:2019-07-23 07:51:10
【问题描述】:

我在尝试解密消息时遇到了这个问题。

错误

An exception or error caused a run to abort: Data must not be longer than 256 bytes 
javax.crypto.IllegalBlockSizeException: Data must not be longer than 256 bytes

我的代码如下。

package com.smth.what.api

import java.security.spec.X509EncodedKeySpec
import java.security.{KeyFactory, PrivateKey, PublicKey}

import javax.crypto.Cipher
import org.apache.commons.codec.binary.Base64

object Encryptor {
  private val publicKeyString: String = System.getenv("PUB_KEY")
  private val privateKeyString: String = System.getenv("PRIV_KEY")

  private val publicKey = readPemPublicKey(publicKeyString)
  private val privateKey = readPemPrivateKey(privateKeyString)

  private def readPemPublicKey(publicKey: String): PublicKey = {
    val pemPublicKey = publicKey.replace("\n", "")
      .replace("-----BEGIN PUBLIC KEY-----", "")
      .replace("-----END PUBLIC KEY-----", "")
      .replace(" ", "")

    val publicKeyBytes: Array[Byte] = Base64.decodeBase64(pemPublicKey)
    val publicKeySpec = new X509EncodedKeySpec(publicKeyBytes)

    val keyFactory = KeyFactory.getInstance("RSA")

    keyFactory.generatePublic(publicKeySpec)
  }

  private def readPemPrivateKey (privateKey: String): PrivateKey = {
    val pemPrivateKey = privateKey.replace("\n", "")
      .replace("-----BEGIN RSA PRIVATE KEY-----", "")
      .replace("-----END RSA PRIVATE KEY-----", "")
      .replace(" ", "")

    val privateKeyBytes: Array[Byte] = Base64.decodeBase64(pemPrivateKey)

    val keyFactory = KeyFactory.getInstance("RSA")

    import java.security.spec.RSAPrivateCrtKeySpec

    import sun.security.util.DerInputStream

    val derReader = new DerInputStream(privateKeyBytes)
    val seq = derReader.getSequence(0)
    val modulus = seq(1).getBigInteger
    val publicExp = seq(2).getBigInteger
    val privateExp = seq(3).getBigInteger
    val prime1 = seq(4).getBigInteger
    val prime2 = seq(5).getBigInteger
    val exp1 = seq(6).getBigInteger
    val exp2 = seq(7).getBigInteger
    val crtCoef = seq(8).getBigInteger

    val keySpec = new RSAPrivateCrtKeySpec(modulus, publicExp, privateExp, prime1, prime2, exp1, exp2, crtCoef)

    keyFactory.generatePrivate(keySpec)
  }

  def encrypt(inputString: String, key: PublicKey = publicKey): String = {
    val cipher: Cipher = Cipher.getInstance("RSA")
    cipher.init(Cipher.ENCRYPT_MODE, key)

    new String(cipher.doFinal(inputString.getBytes("UTF-8")))
  }

  def decrypt(inputString: String, key: PrivateKey = privateKey): String = {
    val cipher: Cipher = Cipher.getInstance("RSA")
    cipher.init(Cipher.DECRYPT_MODE, key)

    val inputStringBytes = inputString.getBytes("UTF-8")

    new String(cipher.doFinal(inputStringBytes))

  }
}

我的密钥大小是2048。它是通过openssl genrsa.pem 输出生成的。

我使用 IntelliJ 的环境变量来提供公钥和私钥(通过编辑配置,复制和粘贴它们)。

错误来自这一行 new String(cipher.doFinal(inputStringBytes)) 来自 decrypt 函数。

我一直在阅读一些stackoverflow 的帖子(例如这个one),但是我仍然不明白发生了什么。

如果可能的话,我想要一个非常基本的解释,因为加密/解密对我来说是一个新领域。

【问题讨论】:

  • 您确定您正在从 DER 流中读取属性值吗?根据the specthis blog post,您可能缺少一些参数。此外,某些实现可能会在密钥中添加更多行,例如outlined in this thread,尤其是在密钥被加密时。这里使用一个已经存在的库,比如 BouncyCastle 可能更安全
  • 使用String() 尝试保存任意值的字节数组是一个会导致数据损坏的错误。如果出于某种原因必须将加密结果编码为字符串,则使用 base-64 编码之类的东西。此代码还包含Cipher = Cipher.getInstance("RSA") 的非常常见的 Java 加密反模式。 总是指定完整的转换字符串algorithm/mode/padding,而不仅仅是algorithm

标签: java scala encryption private-key public-key


【解决方案1】:

在尝试了不同的事情之后,有效的方法是将Base64 编码应用于加密消息,然后在解密加密消息时使用Base64 解码。这与@James K Polk 评论所说的一致。

查看更新后的代码(仅适用于 encryptdecrypt 函数,其余部分保持不变)

  def encrypt(inputString: String, key: PublicKey = publicKey): String = {

    cipher.init(Cipher.ENCRYPT_MODE, key)

    val encrypted: Array[Byte] = cipher.doFinal(inputString.getBytes())

    Base64.encodeBase64String(encrypted)
  }

  def decrypt(inputString: String, key: PrivateKey = privateKey): String = {

    cipher.init(Cipher.DECRYPT_MODE, key)

    val decodedInputString: Array[Byte] = Base64.decodeBase64(inputString)

    val decrypted: Array[Byte] = cipher.doFinal(decodedInputString)

    new String(decrypted)
  }

【讨论】:

    猜你喜欢
    • 2023-03-21
    • 2015-06-14
    • 2012-04-17
    • 2022-11-22
    • 2010-10-27
    • 2020-06-10
    • 1970-01-01
    • 2014-03-03
    • 2017-04-26
    相关资源
    最近更新 更多