简体   繁体   English

AES / CBC / NoPadding和IllegalBlockSizeException-自定义填充处理

[英]AES/CBC/NoPadding and IllegalBlockSizeException - Custom padding handling

UPDATE: I removed another issue in my code to make the question more precise. 更新:我删除了代码中的另一个问题,以使问题更加精确。

I need to encrypt a String with variable length with AES/CBC/NoPadding but I'm getting an IllegalBlockSizeException. 我需要使用AES / CBC / NoPadding加密具有可变长度的字符串,但是我遇到了IllegalBlockSizeException。 I have to use NoPadding because the input should have the same length as the output even if the decryption fails. 我必须使用NoPadding,因为即使解密失败,输入的长度也应与输出的长度相同。 It shouldn't be possible to determine that it failed. 不可能确定它失败了。

Before I used AES/CBC/PKCS5Padding without any problem but that is not an option. 在我使用AES / CBC / PKCS5Padding之前,没有任何问题,但这不是一个选择。 So my question is: 所以我的问题是:

How do I add a custom padding to get a multiple of 16 byte or what possibly leads to the IllegalBlockSizeException (DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH)? 如何添加自定义填充以获取16字节的倍数,否则可能导致IllegalBlockSizeException(DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH)? I also read that ciphertext stealing is a way to do so. 我还读到密文窃取是一种方法。 I would be grateful for an example. 我想举个例子。

Here's my current code: 这是我当前的代码:

private static final String KEY_TRANSFORMATION_ALGORITHM_SYM = "AES/CBC/NoPadding";

@NonNull
static String encryptMessage(@NonNull String plainMessage,
                             @NonNull SharedPreferences storage,
                             @Nullable Key aesKey,
                             @NonNull String charset) {
    if (aesKey == null) {
        throw new RuntimeException("AES key is null", null);
    }
    try {
        // Cipher can not be re-used on Android
        Cipher cipher = Cipher.getInstance(KEY_TRANSFORMATION_ALGORITHM_SYM);
        cipher.init(Cipher.ENCRYPT_MODE, aesKey, new IvParameterSpec(getIV(storage, cipher, charset)));
        byte[] charsetEncryptedData = cipher.doFinal(plainMessage.getBytes(charset));
        return Base64.encodeToString(charsetEncryptedData, Base64.NO_WRAP);

    } catch (NoSuchAlgorithmException | InvalidKeyException | NoSuchPaddingException | InvalidAlgorithmParameterException | BadPaddingException | IllegalBlockSizeException | UnsupportedEncodingException e) {
        throw new RuntimeException(e.getMessage(), e);
    }
}

@NonNull
static String decryptMessage(@NonNull String encryptedMessage,
                             @NonNull SharedPreferences storage,
                             @Nullable Key aesKey,
                             @NonNull String charset) {
    if (aesKey == null) {
        throw new RuntimeException("AES key is null", null);
    }
    try {
        //Cipher can not be re-used on Android
        Cipher cipher = Cipher.getInstance(KEY_TRANSFORMATION_ALGORITHM_SYM);
        cipher.init(Cipher.DECRYPT_MODE, aesKey, new IvParameterSpec(getIV(storage, cipher, charset)));

        byte[] decryptedData = Base64.decode(encryptedMessage.getBytes(charset), Base64.NO_WRAP);
        byte[] charsetEncryptedData = cipher.doFinal(decryptedData);
        return new String(charsetEncryptedData, charset);

    } catch (NoSuchAlgorithmException | InvalidKeyException | InvalidAlgorithmParameterException | BadPaddingException | NoSuchPaddingException | IllegalBlockSizeException | UnsupportedEncodingException e) {
        throw new RuntimeException(e.getMessage(), e);
    }
}

I solved my issue with the following code. 我用以下代码解决了我的问题。 I had to add a custom padding with spaces: 我必须添加带有空格的自定义填充:

@NonNull
static String encryptMessage(@NonNull String plainMessage,
                             @NonNull SharedPreferences storage,
                             @Nullable Key aesKey,
                             @NonNull String charset) {
        //...
        // add spaces (custom padding) until the plainMessage.getBytes can be divided by 16 without rest --> this is the solution I was looking for
        while (plainMessage.getBytes().length % 16 != 0) {
            plainMessage += '\u0020';
        }
        //...
}

@NonNull
static String decryptMessage(@NonNull String encryptedMessage,
                             @NonNull SharedPreferences storage,
                             @Nullable Key aesKey,
                             @NonNull String charset) {
        //...
        // trim the String to get rid of the spaces
        return new String(charsetEncryptedData, charset).trim();
        //...
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM