简体   繁体   中英

IllegalBlockSize Exception When Doing RSA on bytes of Strings

I am trying to write RSA encryption and decryption classes in Java for a server where the client will be passing strings back and forth. I have the following code for the classes:

public class RSAEncryption {
public static final String KEYGENALGORITHM = "RSA";
public static final String ALGORITHM = "RSA/ECB/PKCS1Padding";

public static KeyPairContainer generateKey() {
      KeyPairGenerator keyGen;
      KeyPair key;
    try {
        keyGen = KeyPairGenerator.getInstance(KEYGENALGORITHM);
        keyGen.initialize(1024);
        key = keyGen.generateKeyPair();
        return new KeyPairContainer(key.getPublic(), key.getPrivate());
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
        System.out.println("Error: No such algorithm");
    }
    return null;
 }

public static String pubkeyToString(PublicKey key){
    byte[] array = key.getEncoded();
    BASE64Encoder encoder = new BASE64Encoder();
    String tempstring = encoder.encode(array);
    return tempstring;
}

public static PublicKey stringToPubKey(String string){
    BASE64Decoder decoder = new BASE64Decoder();
    try {
        byte[] array = decoder.decodeBuffer(string);
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(array);
        KeyFactory keyFact = KeyFactory.getInstance(KEYGENALGORITHM);
        PublicKey pubKey = keyFact.generatePublic(x509KeySpec);
        return pubKey;
    } catch (IOException | NoSuchAlgorithmException | InvalidKeySpecException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } return null;
}

public static byte[] rSAencrypt(byte[] plaintext, String keystring) {
    Cipher cipher;
    try {
        PublicKey key = stringToPubKey(keystring);
        cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, key);
        byte[] cipherText = cipher.doFinal(plaintext);
        //String cipherText = new String(cipherTextbytes);
        return cipherText;
    } catch (NoSuchAlgorithmException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (NoSuchPaddingException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (InvalidKeyException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (IllegalBlockSizeException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (BadPaddingException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    return null;

}

public static byte[] rSAdecrypt(byte[] ciphertext, PrivateKey key){
    Cipher cipher;
    try {
        //byte[] ciphertext = ciphertextstring.getBytes();
        cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, key);
        byte[] decryptedText = cipher.doFinal(ciphertext);
        return decryptedText;
    } catch (NoSuchAlgorithmException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (NoSuchPaddingException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (InvalidKeyException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (IllegalBlockSizeException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (BadPaddingException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    return null;
}
}

I have the following code for a test class:

public class RSAEncryptionKeyDemo {
public static void main(String[] args){
    KeyPairContainer keyPair = RSAEncryption.generateKey();
    PublicKey pubKey = keyPair.getPublicKey();
    String pubKeytext = RSAEncryption.pubkeyToString(pubKey);
    System.out.println(pubKeytext);

    String plaintext = "Hello world!";
    byte[] ciphertext = RSAEncryption.rSAencrypt(plaintext.getBytes(), pubKeytext);
    String ciphertextString = new String(ciphertext);
    System.out.println(ciphertextString);

    PrivateKey privkey = keyPair.getPrivateKey();
    byte[] decryptedText = RSAEncryption.rSAdecrypt(ciphertextString.getBytes(), privkey);

    String decryptedTextstring = new String(decryptedText);

    System.out.println(decryptedTextstring);


}
}

However, when I try to run the test class, key generation and encryption work fine, but I am thrown an error when I try to decrypt. The error is javax.crypto.IllegalBlockSizeException: Data must not be longer than 128 bytes, however, my data is definitely less than 128 bytes.

I can confirm that transforming the Public key to a string and back returns the same Public Key. I have also tried testing the code just using bytes, and this works fine. The error is apparently in trying to decrypt the bytes taken from a string.

Is there some way to decrypt bytes taken from a string without throwing this error? Thanks in advance, it is very much appreciated.

EDIT: i think I might have isolated the issue. I am trying to turn an encrypted bytearray into a string, and then extract the bytes from it, but the encrypted bytearray doesn't translate properly into a string anyway so when I get the bytes it doesn't extract what the original encrypted bytearray was. Is that correct, and if so, how do I turn the bytearray into a string properly so we can exchange it?

If you do this

byte[] ciphertext = RSAEncryption.rSAencrypt(plaintext.getBytes(), pubKeytext);
//String ciphertextString = new String(ciphertext);
//System.out.println(ciphertextString);

PrivateKey privkey = keyPair.getPrivateKey();
byte[] decryptedText = RSAEncryption.rSAdecrypt(ciphertext, privkey);

the code runs perfectly fine. You cannot convert a byte array to a String since the bytes are converted to characters and back to bytes (using getBytes()) - depending on your default charset. new String(ciphertext) strips away unprintable characters which changes the ciphertext and hence makes the plaintext unrecoverable. (Thanks to Artjom B. for pointing that out.)

Simply use Base64 or binary to transport your ciphertext, eg:

byte[] ciphertext = RSAEncryption.rSAencrypt(plaintext.getBytes(), pubKeytext);
String ciphertextString = Base64.toBase64String(ciphertext);
System.out.println(ciphertextString);

PrivateKey privkey = keyPair.getPrivateKey();
byte[] decryptedText = RSAEncryption.rSAdecrypt(Base64.decode(ciphertextString), privkey);

(I am using the BouncyCastle Base64 encoder here.)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM