5

I'm trying to set up RSA encryption so I can make a simple library for myself to use in the future and I can't get this simple code to work. Here is the source code:

package rsa.testing;

import java.security.KeyPair;
import java.security.KeyPairGenerator;

import javax.crypto.Cipher;

public class AloneTest
{
    public static void doTest()
    {
        try
        {
            KeyPairGenerator gen = KeyPairGenerator.getInstance("RSA");
            gen.initialize(2048);
            KeyPair pair = gen.genKeyPair();
            System.out.println("Public key: " + byteArrayToString(pair.getPublic().getEncoded()));
            System.out.println("Private key: " + byteArrayToString(pair.getPrivate().getEncoded()));

            Cipher encryptPublic = Cipher.getInstance("RSA");
            encryptPublic.init(Cipher.ENCRYPT_MODE, pair.getPublic());

            Cipher decryptPublic = Cipher.getInstance("RSA");
            decryptPublic.init(Cipher.DECRYPT_MODE, pair.getPublic());

            Cipher encryptPrivate = Cipher.getInstance("RSA");
            encryptPrivate.init(Cipher.ENCRYPT_MODE, pair.getPrivate());

            Cipher decryptPrivate = Cipher.getInstance("RSA");
            decryptPrivate.init(Cipher.DECRYPT_MODE, pair.getPrivate());

            System.out.println("All ciphers created.");
            System.out.println();

            String plainText = "Hello World!";
            System.out.println("Plain text: " + plainText);
            String encrypted = new String(encryptPrivate.doFinal(plainText.getBytes()));
            System.out.println("Encrypted: " + encrypted);
            String decrypted = new String(decryptPublic.doFinal(encrypted.getBytes()));
            System.out.println("Decrypted: " + decrypted);
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }

    private static String byteArrayToString(byte[] bytes)
    {
        String str = "";

        for (byte b : bytes)
        {
            str += b + " ";
        }

        return str.trim();
    }
}

And this the output (image because it doesn't let me copy the encrypted text).

Any ideas?

EDIT: Changed the following:

String plainText = "Hello World!";
System.out.println("Plain text: " + plainText);
String encrypted = byteToBase64String(encryptPublic.doFinal(plainText.getBytes()));
System.out.println("Encrypted: " + encrypted);
String decrypted = byteToBase64String(decryptPublic.doFinal(encrypted.getBytes()));
System.out.println("Decrypted: " + decrypted);

Method used to convert bytes to Base64:

private static String byteToBase64String(byte[] bytes)
{
    return Base64.getEncoder().encodeToString(bytes);
}

But now I get this error:

Plain text: Hello World!
Encrypted: dCTsYrQTDfNkRr6+nupWW4ntsmD69wrWS1TDvS3Uk1B6lCKkycegAb7wJgnXNolZ58dRXgbzEyCkeM/IbH0ruIEMfuhS5vrggo1s9+6MQN2hW1I4iElJfAdGKYQ8H9pFhAws+VQGetjwvJwUI9iWIi15721vc508/ks7rn4oQOk=
javax.crypto.IllegalBlockSizeException: Data must not be longer than 128 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 rsa.testing.AloneTest.doTest(AloneTest.java:40)
    at rsa.testing.Main.main(Main.java:21)

Do I have to do some sort of splitting? Or am I doing something else wrong?

liaquore
  • 403
  • 8
  • 22
  • 1
    You are converting `byte[]` to `String` without properly encoding it - THIS WILL NOT WORK. Instead use base64 for converting `byte[]` to `String`! – Robert Dec 29 '18 at 12:50
  • I added conversion to Base64, but now I get a new error that can be seen in my post. – liaquore Dec 29 '18 at 13:00
  • Of course you have to base64 decode the data before decrypting. Note that my first comment only applies to byte[] values that contain binary data for byte[] that contains textual data you can convert it directly to String. – Robert Dec 29 '18 at 13:05
  • Sorry, what do you mean by that? – liaquore Dec 29 '18 at 13:12
  • I agree with @Robert: You should **work always only with `byte[]`**, and only convert to String (through base64, or direct converting, or whatever) just when you want to transfer the crypted data through some text means (lik `System.out`). – Little Santi Dec 30 '18 at 16:59
  • 1
    plaintext string -> char encode to byte[] -> encrypt -> base 64 encode -> ciphertext string -> base 64 decode -> decrypt -> character decode to string -> plaintext string – Maarten Bodewes Dec 30 '18 at 18:25
  • Note that often there is not need in crypto to convert anything from / to strings. Doing so is the crypto equivalent of stringly typed code (look it up). Modern cryptography operates on bits / bytes, so if you can store binary data then there is no need to convert to strings. – Maarten Bodewes Jan 04 '19 at 15:03

1 Answers1

3

You are missing this:

when encrypting with public key one should use private key to decrypt
and also
when encrypting with private key one should use public key to decrypt

UPDATE

When encrypting with e.g. private key then trying to decrypt with same private key you'll have that java.crypto.BadPaddingException

I can't share the code proving this but I tested using:

KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
keyPairGen.initialize(2048);
keyPair = keyPairGen.generateKeyPair();

while for Cipher I used:

Cipher.getInstance("RSA/ECB/PKCS1Padding")
Adrian
  • 3,321
  • 2
  • 29
  • 46
  • 1
    My question is pretty old so I already figured that out a while ago. Thanks for answering though :) – liaquore Jun 11 '19 at 12:09
  • I had few moments ago the same annoying problem and seeing yous not answered I thought it's a java bug :D. – Adrian Jun 11 '19 at 12:35