IllegalBlocksizeException - 如何使用Base64解决

时间:2016-03-14 19:09:53

标签: java security cryptography aes

我在使用以下代码时遇到了一些问题 - 我似乎遇到了IllegalBlocksizeException并且不确定我在这里做错了什么?是否有可能获得一些建议/指示?

谢谢

    public class Encryption
    {
        private SecretKeyFactory factory;
        private SecretKey tmp;
        private SecretKey secret;
        private Cipher cipher;

        private byte[] iv;
        private byte[] cipherText;

        private final KeySpec spec = new PBEKeySpec("somepassword".toCharArray(), SALT, 65536, 256);
        private static final byte[] SALT = {(byte)0xc3, (byte)0x23, (byte)0x71, (byte)0x1c, (byte)0x2e, (byte)0xc2, (byte)0xee, (byte)0x77};

        public Encryption()
        {
            try
            {
                factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
                tmp = factory.generateSecret(spec);
                secret = new SecretKeySpec(tmp.getEncoded(), "AES");
                cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
                cipher.init(Cipher.ENCRYPT_MODE, secret);
                iv = cipher.getParameters().getParameterSpec(IvParameterSpec.class).getIV();
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
        }

        public String encrypt(String valueToEncrypt) throws Exception
        {
            cipher.init(Cipher.ENCRYPT_MODE, secret, new IvParameterSpec(iv));
            cipherText = cipher.doFinal(Base64.decodeBase64(valueToEncrypt.getBytes()));
            return Base64.encodeBase64String(cipherText);
        }

        public String decrypt(String encryptedValueToDecrypt) throws Exception
        {
            cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(iv));
            return new String(cipher.doFinal(new Base64().encode(encryptedValueToDecrypt.getBytes())));
        }

        public static void main(String[] args ) throws Exception
        {
            Encryption manager = new Encryption();
            String encrypted = manager.encrypt("this is a string which i would like to encrypt");
            System.out.println(encrypted);
            String decrypted = manager.decrypt(encrypted);
            System.out.println(decrypted);
            System.out.println(encrypted.equals(decrypted));
        }
}

例外情况如下

Exception in thread "main" javax.crypto.IllegalBlockSizeException: Input length must be multiple of 16 when decrypting with padded cipher
    at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:750)
    at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:676)
    at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:313)
    at javax.crypto.Cipher.doFinal(Cipher.java:2087)
    at encrypt.Encryption.decrypt(Encryption.java:52)
    at encrypt.Encryption.main(Encryption.java:60)

3 个答案:

答案 0 :(得分:2)

从功能的角度来看,开始实施加密算法的唯一方法(请记住,工作代码不一定是安全的,并且很多想法都应该朝着这个方向发展),增量:首先尝试使用固定密钥的原始AES,然后添加由PBKDF2生成的密钥,并且仅添加后来的Base64。后者只是一个编码工具,应该是该过程中最简单的部分。

但是让我们来看看代码: 如果您的目标是通过密码生成密钥,则初始化似乎很好。 2.在解密过程中,这条线路突然出现:

 cipherText = cipher.doFinal(Base64.decodeBase64(valueToEncrypt.getBytes()));

valueToEncrypt是一个可读字符串,但您正在尝试解密它。由于它只有小写字母和空格,因此可能不会触发错误,但您尝试对未经base64编码的内容进行64位解码。尝试更有意义:

cipherText = cipher.doFinal(valueToEncrypt.getBytes());

然后 cipherText 可以进行base64编码。

对于解密部分,以相反的顺序撤消加密操作。如果你加密然后base64编码,那么首先解码base64-decode然后解密。

作为最终建议:思考模块化。在一行中编码并在另一行中加密,因此如果要删除或添加图层,只需在一行上切换注释即可。

答案 1 :(得分:2)

您已经颠倒了base-64编码和解码操作。 Base-64接收原始字节并使其成为可打印文本。您可以对加密操作的输出进行编码以使其可打印。但是,在尝试解密之前,您需要对该文本进行base-64解码。

decrypt()方法的这一部分导致了问题:

cipher.doFinal(new Base64().encode(encryptedValueToDecrypt.getBytes()))

应该是:

cipher.doFinal(Base64.decodeBase64(encryptedValueToDecrypt.getBytes()))

要求"指针"非常开放。我能给你的最佳指针:不要自己编写这段代码。选择提供更高级别API的程序包,选择高安全性算法并根据最佳实践应用它们。你不知道自己在做什么,也无法编写安全的代码。但是使用高质量的开源库可能会帮助您开始了解有关加密的更多信息。

答案 2 :(得分:1)

在解密之前,你可能应该对base encryptedValueToDecrypt进行解码。