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

bab*_*113 25 java encryption

我在java类中遇到解密错误:

javax.crypto.IllegalBlockSizeException : 
    Input length must be multiple of 16 when decrypting with padded cipher.
Run Code Online (Sandbox Code Playgroud)

我该怎么做才能解决这个问题?

更新:

我忘了提到它工作一次,当第二次我试图再次执行它时抛出上述错误.

package com.tb.module.service;
import java.security.Key;
import java.security.spec.InvalidKeySpecException;

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

import sun.misc.*;

/**
 * This class is used for encrypt and decrypt the  password field.
 *
 */
public class PswdEnc {

    private static final String ALGO = "AES";
    private static final byte[] keyValue = new byte[] { 'T', 'h', 'e', 'B', 'e', 's', 't','S', 'e', 'c', 'r','e', 't', 'K', 'e', 'y' };

    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 = new BASE64Encoder().encode(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 = new BASE64Decoder().decodeBuffer(encryptedData);
        byte[] decValue = c.doFinal(decordedValue);
        String decryptedValue = new String(decValue);
        return decryptedValue;
    }


    private static Key generateKey() throws Exception {
        Key key = new SecretKeySpec(keyValue, ALGO);
        return key;
    }

}
Run Code Online (Sandbox Code Playgroud)

Bru*_*eis 77

您使用的算法"AES"是"AES/ECB/NoPadding"的简写.这意味着您使用的是具有128位密钥大小和块大小AES算法,具有ECB 操作模式无填充.

换句话说:您只能以128位或16字节的块加密数据.这就是你得到那个IllegalBlockSizeException例外的原因.

如果要加密大小不是16字节倍数的数据,则要么必须使用某种填充,要么使用密码流.例如,您可以通过指定"AES/CBC/NoPadding"作为算法,或者通过指定"AES/ECB/PKCS5"指定PKCS5填充,使用CBC模式(一种有效地将分组密码转换为流密码的操作模式),它将以非常特定的格式自动在数据末尾添加一些字节,以使密文的大小为16个字节的倍数,并且解密算法将理解它必须忽略某些数据.

无论如何,我强烈建议您立即停止正在做的事情,并研究一些关于密码学的介绍性材料.例如,检查加密我在Coursera.你应该非常清楚选择一种或另一种模式的含义,它们的优点是什么,最重要的是它们的弱点.没有这方面的知识,构建非常容易破解的系统非常容易.


更新:根据您对问题的评论,在将数据存储到数据库时不要加密密码!你永远不应该这样做.您必须HASH密码,正确腌制,这与加密完全不同.真的,拜托,不要做你想做的事情......通过加密密码,可以解密它们.这意味着您作为数据库管理员和谁知道密钥,您将能够读取存储在数据库中的每个密码.要么你知道这一点,要么做得非常非常糟糕,或者你不知道这一点,应该感到震惊并阻止它.

  • +1用于推荐加密哈希 (9认同)
  • 所以,令人敬畏的是,提到哈希更好,虽然更好会更好,但是提供一下关于哈希是什么以及如何实现它的线索怎么样?那就更棒了。 (2认同)
  • 对戏剧性和居高临下投反对票。必须以纯文本形式传输的密码不能存储为哈希值 (2认同)

ros*_*sum 5

几点意见:

import sun.misc.*;不要这样做。它是非标准的,并且不能保证在实现之间是相同的。还有其他可用的 Base64 转换库。

byte[] encVal = c.doFinal(Data.getBytes()); 您在此处依赖默认字符编码。始终指定您使用的字符编码:byte[] encVal = c.doFinal(Data.getBytes("UTF-8")); 不同地方的默认值可能不同。

正如@thegrinner 指出的那样,您需要明确检查字节数组的长度。如果存在差异,则逐字节比较它们以查看差异在哪里。