19

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

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)

问题是什么?

4

4 回答 4

18

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

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

}
于 2019-09-12T08:16:16.170 回答
12

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

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

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

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

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

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

于 2017-04-14T17:45:40.260 回答
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;
}
于 2016-06-20T08:58:01.140 回答
2

看看这个答案:Encrypt and decrypt with AES and Base64 encoding

于 2012-05-08T08:02:29.170 回答