0

I have this method for encryption:

private byte[] encrypt(byte[] data) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException,
        BadPaddingException {
    Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
    cipher.init(Cipher.ENCRYPT_MODE, myPublicKey);
    ByteArrayInputStream input = new ByteArrayInputStream(data);
    ByteArrayOutputStream output = new ByteArrayOutputStream();
    byte[] buffer = new byte[64];
    int bytes;
    ByteArrayOutputStream aux;
    try {
        while ((bytes = input.read(buffer)) != -1) {
            aux = new ByteArrayOutputStream();
            aux.write(buffer, 0, bytes);
            byte[] fragment = aux.toByteArray();
            byte[] encryptedFragment = cipher.doFinal(fragment);
            output.write(encryptedFragment);
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
    byte[] result = output.toByteArray();
    return result;
}

And this one for decryption:

public static String decrypt(byte[] data) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, IOException {
    Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
    cipher.init(Cipher.DECRYPT_MODE, myPrivateKey);
    int bitLenght = ((java.security.interfaces.RSAPrivateKey) privateKey).getModulus().bitLength();
    int blockSize = bitLenght / 8;
    byte[] buffer = new byte[blockSize];
    int bytes;
    byte[] decrypted;
    ByteArrayOutputStream aux;
    ByteArrayInputStream input = new ByteArrayInputStream(data);
    ByteArrayOutputStream output = new ByteArrayOutputStream();
    while ((bytes = input.read(buffer)) != -1) {
        aux = new ByteArrayOutputStream();
        aux.write(buffer, 0, bytes);
        byte[] fragment = aux.toByteArray();

        byte[] decryptedFragment = cipher.doFinal(fragment);
        output.write(decryptedFragment);
    }
    decrypted = output.toByteArray();

    return new String(decrypted);
}

But I'm getting this exception:

javax.crypto.BadPaddingException: Decryption error

As I can see I've configured the Cipher to have the same PKCS1Padding so I can't guess why I'm getting that error.

I've created my private key as follows:

openssl genrsa -out myPrivateKey.key 2048

And the public one:

openssl rsa -in myPrivateKey.pem -pubout -out myPublicKey.key

As far as I can see with that command they are both PKCS1, in fact my private key starts with -----BEGIN RSA PRIVATE KEY-----.

What am I missing?

NOTE: I've also tried with blockSize = 64, same result.

popirey
  • 31
  • 5
  • Well that was an error, `data`and `message`, where the same variables, I changed it to read clearer here but I missed one. Fixed! – popirey Dec 20 '19 at 07:55
  • This might be interesting to you [Handling crypto exceptions](https://stackoverflow.com/questions/15709421/handling-crypto-exceptions/15712409#15712409) – kelalaka Dec 20 '19 at 08:31
  • There is about everything wrong in the above code, but I cannot see the particular bug to be honest. – Maarten Bodewes Dec 21 '19 at 00:30
  • 1
    Tried to replicate, runs. Thanks for that loss of time. – Maarten Bodewes Dec 21 '19 at 00:37
  • 1
    Your code is grossly overcomplicated, but (with the one identifier fixed) works _with correct data and keys_, which you don't show the management or communication of. 'bad padding' in any modern crypto is 99.9999% of the time wrong data (often just damaged) or key (for symmetric mistaken or damaged, for asymmetric usually mistaken because damage is usually detected). I'd lean toward key, since you say you used `openssl genrsa` which produces a format that Java can't directly handle. (It can be done, but generally requires understanding not evident in your Q.) – dave_thompson_085 Dec 21 '19 at 08:48
  • indeed BadPaddingException indicates incomplete data or wrong key used, make sure (debug) your keys are really keys you thing they are and if all data are read before decryption – gusto2 Dec 21 '19 at 17:25
  • @dave_thompson_085 Thanks for the comments. As you would have guessed by this point, I'm new with this theme, this is some code I have to maintain, not that I have created it myself, so I would appreciate some understanding, not everybody is born knowing. However you were right, I didn't figure it out but it was the key reading what I was doing wrong. I've fixed it (using spongycastle dependencies) and now it's working. Thanks, if you post it as an answer I'll choose it. – popirey Dec 23 '19 at 08:54

1 Answers1

1

Encrypting a stream - correctly you should have cipher.update(..) in the loop and .doFinal(..) called only once after processing all data.

When decrypting if you call doFinal on a partial message you may get the exception. Regardless that it is not apparent from your code if that is the issue you face. (assuming you have the keypair correcly imported)

And indeed RSA is intended only for short (117 bytes) messages. Otherwise you may search for "hybrid encryption"

P. S.: the way your process the streams and arrays is screaming for optimalization, so have a look at it too, but that is for different question

gusto2
  • 11,210
  • 2
  • 17
  • 36
  • OP's code is actually doing separate RSA encryption and decryption on each chunk of data, so `.doFinal` is correct. The maximum size for (each) RSA encryption depends on the key size and padding used; for 2048-bit as stated in the Q with PKCS1-v1_5 it is 243 bytes. But concur hybrid is the better approach for data (possibly) larger than one RSA block. – dave_thompson_085 Dec 21 '19 at 08:43