在Java中实现IllegalBlockSizeException的解决方案?

时间:2018-02-11 21:44:45

标签: java encryption block

我试图修复我的代码。在我的代码中,我试图生成一个我已经完成的16位密钥。其次,生成随机消息,这也是完成的。加密和解密我收到错误的数据。最后有一个强力算法来解密我稍后尝试做的消息。因此,对于我的加密,代码会对其进行加密,但不会对随机生成的字符串进行加密。我收到了很多错误。

我的代码:

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

错误:

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)

2 个答案:

答案 0 :(得分:0)

您的字符串是随机生成的,但是当块大小与密码所期望的不匹配时,您需要应用可接受的填充算法,因此输入的大小与算法一致。这适用于所有分组密码。

这个例子是一个简单的密码计,不是一个人可以使用像算法一样的东西 &#34; AES / CBC / PKCS5Padding&#34; &#34; RC2 / CBC / PKCS5Padding&#34; &#34; DESede / CBC / PKCS5Padding (PKCS#5填充定义为8字节块大小)

@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;
    }

没有流的另一个例子:

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

这真的没有必要,但如果你想使用base64,你可以寻找Apache: http://commons.apache.org/proper/commons-codec/

使用代码的示例

1)ECB模式

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

示例2)您的CBC模式代码

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

答案 1 :(得分:0)

简而言之,您使用的是加密的二进制数据并假设它是有效的文本,一般来说它不会是。

您可以使用UTF-8编码将String编码为byte [],但并非所有可能的byte []编码都是有效的字符串。加密数据时,可以使用任何可能的字节,但不能总是使用标准字符编码将其转换为字符串。这可能导致数据长度发生变化,这就是为什么它不再是数据编码时的8的倍数。

将数据编码为可打印字符串的简单方法是使用Base64编码。

encryption中使用

        strData = DatatypeConverter.printBase64Binary(encrypted);

并在decryption中使用

        byte[] decrypted=cipher.doFinal(DatatypeConverter.parseBase64Binary(msgE));

这样您将始终尝试解密您编写的二进制数据。

另一个选择是不尝试将二进制数据存储在String中,只使用原始byte[]

编辑可以使用byte[]代替String

来尝试此操作
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;

public class A {
    public static void main(String... args) {

        String text = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        for (int i = 0; i < text.length(); i++) {
            byte[] encrypt = encryption(1, text.substring(0, i));
            String hello = decryption(1, encrypt);
            System.out.println(hello);
        }
    }

    private static byte[] encryption(int key, String msg) {
        String strKey = Integer.toString(key);
        try {
            SecretKeySpec skeyspec = new SecretKeySpec(strKey.getBytes(), "Blowfish");
            Cipher cipher = Cipher.getInstance("Blowfish");
            cipher.init(Cipher.ENCRYPT_MODE, skeyspec);
            return cipher.doFinal(msg.getBytes(StandardCharsets.UTF_8));

        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }


    private static String decryption(int key, byte[] msgE) {
        String strKey = Integer.toString(key);
        try {
            SecretKeySpec skeyspec = new SecretKeySpec(strKey.getBytes(), "Blowfish");
            Cipher cipher = Cipher.getInstance("Blowfish");
            cipher.init(Cipher.DECRYPT_MODE, skeyspec);
            byte[] decrypted = cipher.doFinal(msgE);
            return new String(decrypted, StandardCharsets.UTF_8);

        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}