尝试解密字符串的IllegalBlockSizeException

时间:2014-11-19 19:44:57

标签: java encryption cryptography jce

我在JRE 1.6上使用AES 128位加密。

我一直试图解密由encrypt()生成的字符串:

2014-11-19 14:40:10.831     28 javax.crypto.IllegalBlockSizeException: Input length (with padding) not multiple of 16 bytes
2014-11-19 14:40:10.834     28  at com.ibm.crypto.provider.AESCipher.a(Unknown Source)
2014-11-19 14:40:10.836     28  at com.ibm.crypto.provider.AESCipher.engineDoFinal(Unknown Source)
2014-11-19 14:40:10.837     28  at com.ibm.crypto.provider.AESCipher.engineDoFinal(Unknown Source)
2014-11-19 14:40:10.839     28  at javax.crypto.Cipher.doFinal(Unknown Source)
2014-11-19 14:40:10.841     28  at com.axa.oe.mongo.Security.decrypt(Security.java:72)
2014-11-19 14:40:10.843     28  at com.axa.oe.mongo.MongoSearch.evaluate(MongoSearch.java:62)
2014-11-19 14:40:10.844     28  at com.ibm.broker.javacompute.MbRuntimeJavaComputeNode.evaluate(MbRuntimeJavaComputeNode.java:265)
2014-11-19 14:40:10.846     28  at com.ibm.broker.plugin.MbNode.evaluate(MbNode.java:1480)

我注意到加密的字符串长度为24个字节,wtf?例如。 “fb / 8asoHS / ShyCDV46t / Aw ==”

它们不应该是16个字节吗?无论如何不确定这是不是问题。

以下是来源:

package com.axa.oe.mongo;

import java.security.spec.InvalidKeySpecException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;

import com.ibm.broker.javacompute.Base64;

public class Security {
    private static final String AES_KEY = "blah";
    private SecretKeySpec keyObj;
    private Cipher cipher;
    private IvParameterSpec ivObj;

    public Security() throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException {
        // A constant IV
        byte[] iv = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
        this.ivObj = new IvParameterSpec(iv);

        byte[] key = AES_KEY.getBytes();
        MessageDigest sha = MessageDigest.getInstance("SHA-1");
        key = sha.digest(key);
        key = Arrays.copyOf(key, 16); // use only first 128 bit
        this.keyObj = new SecretKeySpec(key, "AES");

        // Create a Cipher by specifying the following parameters
        //  a. Algorithm name - here it is AES 
        //  b. Mode - here it is CBC mode 
        //  c. Padding - e.g. PKCS7 or PKCS5
        this.cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
    }

    public String encrypt(String strDataToEncrypt) throws InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, NoSuchPaddingException {
        String strCipherText = new String();

        this.cipher.init(Cipher.ENCRYPT_MODE, this.keyObj, this.ivObj);

        // Encrypt the Data 
        //  a. Declare / Initialize the Data. Here the data is of type String 
        //  b. Convert the Input Text to Bytes 
        //  c. Encrypt the bytes using doFinal method
        byte[] byteDataToEncrypt = strDataToEncrypt.getBytes();

        byte[] byteCipherText = this.cipher.doFinal(byteDataToEncrypt);

        // b64 is done differently on Android
        strCipherText = Base64.encode(byteCipherText);

        return strCipherText;
    }

    public String decrypt(String strCipherText) throws InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, NoSuchPaddingException {
        String strDecryptedText = new String();

        // Initialize the Cipher for Encryption
        this.cipher.init(Cipher.DECRYPT_MODE, this.keyObj, this.ivObj);

        // Decrypt the Data
        //  a. Initialize a new instance of Cipher for Decryption (normally don't reuse the same object)
        //     Be sure to obtain the same IV bytes for CBC mode.
        //  b. Decrypt the cipher bytes using doFinal method
        byte[] byteDecryptedText = this.cipher.doFinal(strCipherText.getBytes());
        strDecryptedText = new String(byteDecryptedText);

        return strDecryptedText;
    }
}

我正在使用全局密钥,因为应用程序不使用会话或登录。另请注意,IV是一个常量字节数组。我的JCE版本有点过时,我试图升级它,但目前陷入官僚主义,所以我必须做出应有的...

非常感谢!

1 个答案:

答案 0 :(得分:1)

看起来像fb/8asoHS/ShyCDV46t/Aw==的字符串是密文文本字节数组的Base64编码表示。

密钥开始时长16个字节。 Base64编码将长度增加到4/3,因为它使用较少的字符来表示字节。 16 * 4/3 = 22.但Base64需要一次转换3个字节,因此它将字节填充为3的倍数,因此16 - > 18 * 4/3 = 24.最终的等号是Base64中这种填充的典型工件。

加密后,您将对密码文本进行Base64编码。在解密之前,您需要对密码文本进行Base64解码。

可能类似于:

public String decrypt(String strCipherText) throws InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, NoSuchPaddingException {
    String strDecryptedText = new String();

    // Initialize the Cipher for Encryption
    this.cipher.init(Cipher.DECRYPT_MODE, this.keyObj, this.ivObj);

    // Decode the Base64 text
    byte[] cipherBytes = Base64.decode(strCipherText);

    // Decrypt the Data
    //  a. Initialize a new instance of Cipher for Decryption (normally don't reuse the same object)
    //     Be sure to obtain the same IV bytes for CBC mode.
    //  b. Decrypt the cipher bytes using doFinal method
    byte[] byteDecryptedText = this.cipher.doFinal(cipherBytes);
    strDecryptedText = new String(byteDecryptedText);

    return strDecryptedText;
}