billydh
billydh

Reputation: 1035

RSA decryption error with PKCS#1: javax.crypto.IllegalBlockSizeException: Data must not be longer than 256 bytes

I am running into this problem when trying to decrypt a message.

Error

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

My code is as follows.

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))

  }
}

My key's size is 2048. It was generated via openssl genrsa with .pem output.

I use IntelliJ's environment variable to provide both public and private keys (via the Edit Configurations, copying and pasting them).

The error came from this line new String(cipher.doFinal(inputStringBytes)) from decrypt function.

I have been reading a few stackoverflow's posts (such as this one), however, I still do not understand what is going on.

If possible, I would like a very basic explanation, as encryption/ decryption is a new area for me.

Upvotes: 0

Views: 962

Answers (1)

billydh
billydh

Reputation: 1035

After attempting different things, what works is to apply Base64 encoding to the encrypted message and then use Base64 decoding when decrypting the encrypted message. This is aligned with what @James K Polk comment is saying.

See the updated code (only for the functions encrypt and decrypt as the rest remains the same)

  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)
  }

Upvotes: 1

Related Questions