使用填充密码解密时,输入长度必须是16的倍数

时间:2012-05-08 07:55:03

标签: java

我有服务器和客户端套接字程序,服务器向客户端发送加密消息,即 服务器端代码:

cipher2 = Cipher.getInstance("AES"); 
secretKeySpec = new SecretKeySpec(decryptedText, "AES");
cipher2.init(Cipher.ENCRYPT_MODE, secretKeySpec);
feedback = "Your answer is wrong".getBytes();
cipher2.doFinal(feedback);
dos.writeInt(feedback.length);
dos.write(feedback);

客户端代码:

int result_len = 0;
result_len = din.readInt();            
byte[] result_Bytes = new byte[result_len];
din.readFully(result_Bytes);
cipher2 = Cipher.getInstance("AES");
cipher2.init(Cipher.DECRYPT_MODE, aesKey);             
byte[] encrypt = cipher2.doFinal(result_Bytes);

异常抛出byte[] encrypt = cipher2.doFinal(result_Bytes);

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:2086)

问题是什么?

5 个答案:

答案 0 :(得分:7)

有类似的问题。但重要的是要了解根本原因,并且可能因不同的用例而异。

情景1
您正尝试解密首先未正确编码的值。

byte[] encryptedBytes = Base64.decodeBase64(encryptedBase64String);

如果字符串由于某种原因配置错误或编码不正确,您会看到错误“使用填充密码解密时输入长度必须是16的倍数”

情景2
现在,如果您在url中使用此编码字符串(尝试在url中传入base64Encoded值),它将失败。 你应该做URLEncoding,然后传入令牌,它会工作。

情景3
当与其中一个供应商集成时,我们发现我们必须使用URLEncoder对Base64进行加密,但我们不需要解码它,因为它是由供应商在内部完成的

答案 1 :(得分:2)

答案 2 :(得分:2)

我知道这条消息很久很久以前 - 但我也有问题 完全相同的错误:

我遇到的问题与加密文本在尝试解密时转换为字符串和byte[]的事实有关。

    private Key getAesKey() throws Exception {
    return new SecretKeySpec(Arrays.copyOf(key.getBytes("UTF-8"), 16), "AES");
}

private Cipher getMutual() throws Exception {
    Cipher cipher = Cipher.getInstance("AES");
    return cipher;// cipher.doFinal(pass.getBytes());
}

public byte[] getEncryptedPass(String pass) throws Exception {
    Cipher cipher = getMutual();
    cipher.init(Cipher.ENCRYPT_MODE, getAesKey());
    byte[] encrypted = cipher.doFinal(pass.getBytes("UTF-8"));
    return encrypted;

}

public String getDecryptedPass(byte[] encrypted) throws Exception {
    Cipher cipher = getMutual();
    cipher.init(Cipher.DECRYPT_MODE, getAesKey());
    String realPass = new String(cipher.doFinal(encrypted));
    return realPass;
}

答案 3 :(得分:2)

这是一个非常老的问题,但是我的回答可能会对某人有所帮助。

  • 在crypto方法中,不要忘记将字符串编码为Base64
  • 在解密方法中,不要忘记将字符串解码为Base64

下面是工作代码

    import java.util.Arrays;
    import java.util.Base64;

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

    public class EncryptionDecryptionUtil {

    public static String encrypt(final String secret, final String data) {


        byte[] decodedKey = Base64.getDecoder().decode(secret);

        try {
            Cipher cipher = Cipher.getInstance("AES");
            // rebuild key using SecretKeySpec
            SecretKey originalKey = new SecretKeySpec(Arrays.copyOf(decodedKey, 16), "AES");
            cipher.init(Cipher.ENCRYPT_MODE, originalKey);
            byte[] cipherText = cipher.doFinal(data.getBytes("UTF-8"));
            return Base64.getEncoder().encodeToString(cipherText);
        } catch (Exception e) {
            throw new RuntimeException(
                    "Error occured while encrypting data", e);
        }

    }

    public static String decrypt(final String secret,
            final String encryptedString) {


        byte[] decodedKey = Base64.getDecoder().decode(secret);

        try {
            Cipher cipher = Cipher.getInstance("AES");
            // rebuild key using SecretKeySpec
            SecretKey originalKey = new SecretKeySpec(Arrays.copyOf(decodedKey, 16), "AES");
            cipher.init(Cipher.DECRYPT_MODE, originalKey);
            byte[] cipherText = cipher.doFinal(Base64.getDecoder().decode(encryptedString));
            return new String(cipherText);
        } catch (Exception e) {
            throw new RuntimeException(
                    "Error occured while decrypting data", e);
        }
    }


    public static void main(String[] args) {

        String data = "This is not easy as you think";
        String key = "---------------------------------";
        String encrypted = encrypt(key, data);
        System.out.println(encrypted);
        System.out.println(decrypt(key, encrypted));
      }
  }

对于生成密钥,您可以在下面的类中使用

    import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Base64;

import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;

public class SecretKeyGenerator {

    public static void main(String[] args) throws NoSuchAlgorithmException {

        KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");

        SecureRandom secureRandom = new SecureRandom();
        int keyBitSize = 256;
        keyGenerator.init(keyBitSize, secureRandom);

        SecretKey secretKey = keyGenerator.generateKey();

 System.out.println(Base64.getEncoder().encodeToString(secretKey.getEncoded()));
    }

}

答案 4 :(得分:-3)

我曾经遇到过这个问题。实际上我的代码是正确的,当我在没有服务器的情况下运行它时工作。错误是,当我从网址获取参数时,加号(+)符号的加密网址会自动更改为空格。这可能是你的问题检查一次。     这是我的加密和解密逻辑与密钥生成器,如果你想也可以使用它。

public class Anything
{
    private static final String ALGO = "AES";
    //generate 128bit key
    private static final String keyStr = "Z8LSq0wWwB5v+6YJzurcP463H3F12iZh74fDj4S74oUH4EONkiKb2FmiWUbtFh97GG/c/lbDE47mvw6j94yXxKHOpoqu6zpLKMKPcOoSppcVWb2q34qENBJkudXUh4MWcreondLmLL2UyydtFKuU9Sa5VgY/CzGaVGJABK2ZR94=";

    private static Key generateKey() throws Exception {
        byte[] keyValue = keyStr.getBytes("UTF-8");
        MessageDigest sha = MessageDigest.getInstance("SHA-1");
        keyValue = sha.digest(keyValue);
        keyValue = Arrays.copyOf(keyValue, 16); // use only first 128 bit       
        Key key = new SecretKeySpec(keyValue, ALGO);
        return key;
    }

    public static String encrypt(String Data) throws Exception {
            Key key = generateKey();
            Cipher c = Cipher.getInstance(ALGO);
            c.init(Cipher.ENCRYPT_MODE, key);
            byte[] encVal = c.doFinal(Data.getBytes());
            String encryptedValue = DatatypeConverter.printBase64Binary(encVal);
            return encryptedValue;
    }

    public static String decrypt(String encryptedData) throws Exception {
        Key key = generateKey();
        Cipher c = Cipher.getInstance(ALGO);
        c.init(Cipher.DECRYPT_MODE, key);       
        byte[] decordedValue = DatatypeConverter.parseBase64Binary(encryptedData);
        byte[] decValue = c.doFinal(decordedValue);
        String decryptedValue = new String(decValue);
        return decryptedValue;
    }
}