解密时出现随机IllegalBlockSizeException

时间:2018-11-05 15:40:13

标签: java encryption raspberry-pi

我在解密文本时遇到一些问题:

我的后端经常在解密过程中引发IllegalBlockSizeException:

javax.crypto.IllegalBlockSizeException: Input length must be multiple of 16 when decrypting with padded cipher

当我再次尝试(1-3次)后,它可以成功解密SAME文本并将响应发送给FE。

正如我注意到的那样,通常是在短时间内尝试解密许多(大约100个)字符串时发生的(2条来自FE的请求,15条来自db /请求的记录,2条加密的字段/记录)

我的服务器在具有Raspbian的Raspberry Pi B +上运行。 “普通” PC上不存在该问题。

加密类:

package bookmarks.common.encryption.base;

import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;

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

import org.apache.commons.net.util.Base64;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class DefaultEncryptor {
    private static final int SIZE = 16;
    private static final String ALGORITHM = "AES";

    private static final Base64 BASE_64 = new Base64();

    private final Key key;
    private final Cipher cipher;

    public DefaultEncryptor(String password) {
        byte[] key = createKey(password);
        this.key = new SecretKeySpec(key, ALGORITHM);
        try {
            cipher = Cipher.getInstance(ALGORITHM);
        } catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
            log.error("Error creating encryptor.", e);
            throw new RuntimeException(e);
        }
    }

    private byte[] createKey(String password) {
        if (password.length() < SIZE) {
            int missingLength = SIZE - password.length();
            StringBuilder passwordBuilder = new StringBuilder(password);
            for (int i = 0; i < missingLength; i++) {
                passwordBuilder.append(" ");
            }
            password = passwordBuilder.toString();
        }
        return password.substring(0, SIZE).getBytes(StandardCharsets.UTF_8);
    }

    public String encrypt(String text) {
        try {
            cipher.init(Cipher.ENCRYPT_MODE, key);
            byte[] encrypted = cipher.doFinal(text.getBytes(StandardCharsets.UTF_8));
            byte[] base64 = BASE_64.encode(encrypted);
            return new String(base64, StandardCharsets.UTF_8);
        } catch (InvalidKeyException | BadPaddingException | IllegalBlockSizeException e) {
            log.error("Error encryping value.", e);
            throw new RuntimeException(e);
        }

    }

    public String decrypt(String text) {
        try {
            cipher.init(Cipher.DECRYPT_MODE, key);
            byte[] base64 = BASE_64.decode(text.getBytes(StandardCharsets.UTF_8));
            byte[] decrypted = cipher.doFinal(base64);
            return new String(decrypted, StandardCharsets.UTF_8);
        } catch (InvalidKeyException | BadPaddingException | IllegalBlockSizeException e) {
            log.error("Error decrypting value.", e);
            throw new RuntimeException(e);
        }
    }
}

有什么想法可以引起问题吗?

2 个答案:

答案 0 :(得分:0)

仅使用不带IV的AES密码意味着使用AES/ECB/PKCS5Padding。这种密码和模式要求输入解密的内容是块大小(128位)的倍数

  Input length must be multiple of 16 when decrypting with padded cipher

密码抱怨输入不是16的倍数

  

正如我注意到的那样,通常是在短时间内尝试解密许多(约100个)字符串时发生的

我想到的是什么(正如James所说,这是我的有根据的猜测),密码对象不是线程安全的。我会很自信地说

  • 传递的输入不完整(您可能希望记录输入字节数组的长度)
  • 有多个线程重用同一密码对象

答案 1 :(得分:0)

问题是静态常量BASE_64,不是线程安全的。当多个请求同时到达时,spring-boot对它们进行并行处理,并且base64解码返回损坏的结果,并且当然不能解密无效数据。