【问题标题】:Input length must be multiple of 16 when decrypting with padded cipher使用填充密码解密时,输入长度必须是 16 的倍数
【发布时间】:2012-05-16 17:01:44
【问题描述】:

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

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)

有什么问题?

【问题讨论】:

  • result_len 是 16 的倍数吗?如果不是,请确保它是,然后 result_Bytes 应该是正确的长度。

标签: java


【解决方案1】:

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

  • 在加密方法中,不要忘记将字符串编码为 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()));
    }

}

【讨论】:

  • 注意:对于固定的key,使用任何16个字符的字符串
  • 我的设备 sdk 是 23。解码工作在 26 sdk。还有其他方法吗?
【解决方案2】:

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

场景 1
您正在尝试解密一个最初未正确编码的值。

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

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

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

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

【讨论】:

  • Base64.getDecoder().decode(encryptedText); 为我工作
【解决方案3】:

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

我遇到的问题与加密文本在尝试解密时被转换为字符串和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;
}

【讨论】:

  • 您能否更清楚地说明:上面的代码是给出问题的代码还是解决问题的代码?
【解决方案4】:

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-18
    • 2012-06-05
    • 1970-01-01
    • 1970-01-01
    • 2019-04-14
    • 1970-01-01
    相关资源
    最近更新 更多