Search code examples
javaencryptionblock

Implementing solution to IllegalBlockSizeException in Java?


I'm trying to fix my code. In my code, I'm trying to generate a 16bit key which I've already done. Secondly, generate a random message which is also done. Encrypt and decrypt the data which I'm getting errors on. Lastly have a brute force algorithm to decrypt the message which i'll try doing later. So for my encryption the code encrypts it but doesn't encrypt the random generated string. I'm getting bunch of errors.

My Code:

import java.util.Random;
import java.security.Security;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;

public class Assignment1Demo {

private static String msg;

private static String msgE;

private static String msgD;

private static int key;


public static void main(String[] args){

//TODO: You can only call methods in main method

key = generateKey();

msg = generateMsg();

msgE = encryption(key,msg);

bruteForce(msgE);

}

private static int generateKey() {

//TODO: implement step a (randomly generate 16-bit key)

//16 bit digit means 2^16 -1 in decimal

Random rand = new Random();

return rand.nextInt((int) (Math.pow(2, 16)-1));

}

private static String generateMsg() {

//TODO: implement step b (randonly generate a string with an even number of characters)
    String chractersU="ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    String chractersL=chractersU.toLowerCase();
    String space=" ";
    String alphanum=chractersU+space+chractersL;
    String random="";
    int length=alphanum.length();
    Random rand=new Random();
    char[] text=new char[length];

    for(int i=0;i<length;i++) {
        text[i]=alphanum.charAt(rand.nextInt(alphanum.length()));
    }


for(int i=0;i<text.length/2;i++) {
    if(text.length%2!=0) {
        random += text[i];
    }}


return random;

}

private static String encryption (int key, String msg) {

//TODO: implement step c (encrypt the message)

String strData="";
String strKey=Integer.toString(key);

    try {
        SecretKeySpec skeyspec=new SecretKeySpec(strKey.getBytes(),"Blowfish");
        Cipher cipher=Cipher.getInstance("Blowfish");
        cipher.init(Cipher.ENCRYPT_MODE, skeyspec);
        byte[] encrypted=cipher.doFinal(msg.getBytes());
        strData=new String(encrypted);

    } catch (Exception e) {
        e.printStackTrace();

    }
    return strData;
}






private static void decryption(int key, String msgE) {

//TODO: implement step d (decryption)

String strKey = Integer.toString(key);
String strData="";

try {
    SecretKeySpec skeyspec=new SecretKeySpec(strKey.getBytes(),"Blowfish");
    Cipher cipher=Cipher.getInstance("Blowfish");
    cipher.init(Cipher.DECRYPT_MODE, skeyspec);
    byte[] decrypted=cipher.doFinal(msgE.getBytes());
    strData=new String(decrypted);

} catch (Exception e) {
    e.printStackTrace();

}
System.out.println(strData);
}

private static void bruteForce(String msgE) {

//TODO: implement bruteForce algorithm, you may need the above decryption(key,msgE) method

boolean isEnglisString = msgE.matches("[a-zA-Z]+");

if(isEnglisString)

System.out.println("Yes encrypted message is Randomly English generated message " + msgE);

else
System.out.println("encrypted message is Not Randomly english generated message "+msgE);
decryption(key, msgE);
isEnglisString = msgD.matches("[a-zA-Z]+");
if(isEnglisString)
System.out.println("Yes decrypted message is Randomly english generated message "+ msgD);
else
System.out.println("decrypted message is not Randomly english generated message "+ msgD);
}}

Errors:

javax.crypto.IllegalBlockSizeException: Input length must be multiple of 8 when decrypting with padded cipher
    at java.base/com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:936)
    at java.base/com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:847)
    at java.base/com.sun.crypto.provider.BlowfishCipher.engineDoFinal(BlowfishCipher.java:319)
    at java.base/javax.crypto.Cipher.doFinal(Cipher.java:2189)
    at Assignment1Demo.decryption(Assignment1Demo.java:110)
    at Assignment1Demo.bruteForce(Assignment1Demo.java:132)
    at Assignment1Demo.main(Assignment1Demo.java:30)

Exception in thread "main" java.lang.NullPointerException
    at Assignment1Demo.bruteForce(Assignment1Demo.java:133)
    at Assignment1Demo.main(Assignment1Demo.java:30)

Solution

  • Your string is randomly generated, but when the block size does not match what the cipher expects, you need to apply an acceptable padding algorithm, so the size of your input is aligned with algorithm. This is applicable to all block ciphers.

    This example is a simple meter for a cipher, not that one could use something like as algorithm "AES/CBC/PKCS5Padding" "RC2/CBC/PKCS5Padding" "DESede/CBC/PKCS5Padding (PKCS#5 padding is defined for 8-byte block sizes)

    @Override
        public SimpleMeter testEncryption(File baseInput, String algorithm, String provider) throws NoSuchProviderException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException {
            Cipher cipherEncryption;
    
            SimpleMeter meter = new SimpleMeter();
    
            SecureRandom randGenerator = new SecureRandom();
            KeyGenerator generator;
    
            generator = KeyGenerator.getInstance(algorithm.split("/")[0], provider);
            generator.init(randGenerator);
            SecretKey key = generator.generateKey();
    
            cipherEncryption = Cipher.getInstance(algorithm, provider);
            cipherEncryption.init(Cipher.ENCRYPT_MODE, key);
    
            try (BufferedInputStream input = new BufferedInputStream(new FileInputStream(baseInput))) {
    
                CipherInputStream encryptionStream = new CipherInputStream(input, cipherEncryption);
    
                meter.start();
    
                while (encryptionStream.read() > -1);
    
                encryptionStream.close();//End all encryption and decryption operation
    
                meter.stop();
            } catch (Exception ex) {
                ex.printStackTrace();
                meter = null;
            }
    
            return meter;
        }
    

    Another example without the streams:

    cipher = Cipher.getInstance("Blowfish/ECB/PKCS5Padding");
    cipher.init(Cipher.DECRYPT_MODE, key);
    byte[] decrypted = cipher.doFinal(encryptedString.getBytes(CHARSET_ISO_8859_1));
     decryptedString = new String(decrypted, CHARSET_ISO_8859_1);
    

    It is really not necessary, but if you wanna go with the base64, you can look for Apache: http://commons.apache.org/proper/commons-codec/


    Examples using your code

    1) ECB mode

    import javax.crypto.Cipher;
    import javax.crypto.spec.SecretKeySpec;
    import java.util.Random;
    
    public class Assignment1Demo {
    
        private static String msg;
    
        private static byte[] msgE;
    
        private static String msgD;
    
        private static int key;
    
        public static void main( String[] args ) {
    
            //TODO: You can only call methods in main method
    
            key = generateKey( );
    
            msg = generateMsg( );
    
            msgE = encryption( key, msg );
    
            bruteForce( msgE );
    
        }
    
        private static int generateKey( ) {
    
            //TODO: implement step a (randomly generate 16-bit key)
    
            //16 bit digit means 2^16 -1 in decimal
    
            Random rand = new Random( );
    
            return rand.nextInt( ( int ) ( Math.pow( 2, 16 ) - 1 ) );
    
        }
    
        private static String generateMsg( ) {
    
            //TODO: implement step b (randonly generate a string with an even number of characters)
            String chractersU = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
            String chractersL = chractersU.toLowerCase( );
            String space = " ";
            String alphanum = chractersU + space + chractersL;
            String random = "";
            int length = alphanum.length( );
            Random rand = new Random( );
            char[] text = new char[ length ];
    
            for ( int i = 0; i < length; i++ ) {
                text[ i ] = alphanum.charAt( rand.nextInt( alphanum.length( ) ) );
            }
    
            for ( int i = 0; i < text.length / 2; i++ ) {
                if ( text.length % 2 != 0 ) {
                    random += text[ i ];
                }
            }
    
            return random;
    
        }
    
        private static byte[] encryption( int key, String msg ) {
    
            //TODO: implement step c (encrypt the message)
    
            byte[] encrypted =new byte[]{};
            String strKey = Integer.toString( key );
    
            try {
                SecretKeySpec skeyspec = new SecretKeySpec( strKey.getBytes( ), "Blowfish" );
                Cipher cipher = Cipher.getInstance("Blowfish/ECB/PKCS5Padding");
                cipher.init( Cipher.ENCRYPT_MODE, skeyspec );
                encrypted = cipher.doFinal( msg.getBytes( ) );
    
            }
            catch ( Exception e ) {
                e.printStackTrace( );
    
            }
            return encrypted;
        }
    
        private static void bruteForce( byte[] msgE ) {
    
            //TODO: implement bruteForce algorithm, you may need the above decryption(key,msgE) method
    
    
            decryption( key, msgE );
        }
    
        private static void decryption( int key, byte[] msgE ) {
    
            //TODO: implement step d (decryption)
    
            String strKey = Integer.toString( key );
            String strData = "";
    
            try {
                SecretKeySpec skeyspec = new SecretKeySpec( strKey.getBytes( ), "Blowfish" );
                Cipher cipher = Cipher.getInstance("Blowfish/ECB/PKCS5Padding");
                cipher.init( Cipher.DECRYPT_MODE, skeyspec );
                byte[] decrypted = cipher.doFinal( msgE);
                strData = new String( decrypted );
    
            }
            catch ( Exception e ) {
                e.printStackTrace( );
    
            }
            System.out.println( strData );
        }
    }
    

    Example 2) your code with CBC mode

    import javax.crypto.Cipher;
    import javax.crypto.spec.SecretKeySpec;
    import java.security.AlgorithmParameters;
    import java.util.Random;
    
    public class Assignment1Demo {
    
        private static String msg;
    
        private static byte[] msgE;
    
        private static String msgD;
    
        private static int key;
        private static byte[] encodedParams;
    
        public static void main( String[] args ) {
    
            //TODO: You can only call methods in main method
    
            key = generateKey( );
    
            msg = generateMsg( );
    
            msgE = encryption( key, msg );
    
            bruteForce( msgE );
    
        }
    
        private static int generateKey( ) {
    
            //TODO: implement step a (randomly generate 16-bit key)
    
            //16 bit digit means 2^16 -1 in decimal
    
            Random rand = new Random( );
    
            return rand.nextInt( ( int ) ( Math.pow( 2, 16 ) - 1 ) );
    
        }
    
        private static String generateMsg( ) {
    
            //TODO: implement step b (randonly generate a string with an even number of characters)
            String chractersU = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
            String chractersL = chractersU.toLowerCase( );
            String space = " ";
            String alphanum = chractersU + space + chractersL;
            String random = "";
            int length = alphanum.length( );
            Random rand = new Random( );
            char[] text = new char[ length ];
    
            for ( int i = 0; i < length; i++ ) {
                text[ i ] = alphanum.charAt( rand.nextInt( alphanum.length( ) ) );
            }
    
            for ( int i = 0; i < text.length / 2; i++ ) {
                if ( text.length % 2 != 0 ) {
                    random += text[ i ];
                }
            }
    
            return random;
    
        }
    
        private static byte[] encryption( int key, String msg ) {
    
            //TODO: implement step c (encrypt the message)
    
            byte[] encrypted =new byte[]{};
            String strKey = Integer.toString( key );
    
            try {
                SecretKeySpec skeyspec = new SecretKeySpec( strKey.getBytes( ), "Blowfish" );
                Cipher cipher = Cipher.getInstance("Blowfish/CBC/PKCS5Padding");
                cipher.init( Cipher.ENCRYPT_MODE, skeyspec );
                encrypted = cipher.doFinal( msg.getBytes( ) );
                encodedParams = cipher.getParameters().getEncoded();
            }
            catch ( Exception e ) {
                e.printStackTrace( );
    
            }
            return encrypted;
        }
    
        private static void bruteForce( byte[] msgE ) {
    
            //TODO: implement bruteForce algorithm, you may need the above decryption(key,msgE) method
    
    
            decryption( key, msgE );
        }
    
        private static void decryption( int key, byte[] msgE ) {
    
            //TODO: implement step d (decryption)
    
            String strKey = Integer.toString( key );
            String strData = "";
    
            try {
                SecretKeySpec skeyspec = new SecretKeySpec( strKey.getBytes( ), "Blowfish" );
                Cipher cipher = Cipher.getInstance("Blowfish/CBC/PKCS5Padding");
                AlgorithmParameters params = AlgorithmParameters.getInstance("Blowfish");
                params.init(encodedParams);
                cipher.init( Cipher.DECRYPT_MODE, skeyspec, params );
                byte[] decrypted = cipher.doFinal( msgE);
                strData = new String( decrypted );
    
            }
            catch ( Exception e ) {
                e.printStackTrace( );
    
            }
            System.out.println( strData );
        }
    }