AES/CBC/NoPadding 和 IllegalBlockSizeException - 自定义填充处理
AES/CBC/NoPadding and IllegalBlockSizeException - Custom padding handling
更新:我删除了代码中的另一个问题以使问题更准确。
我需要使用 AES/CBC/NoPadding 加密可变长度的字符串,但我收到 IllegalBlockSizeException。
我必须使用 NoPadding 因为即使解密失败,输入的长度也应与输出的长度相同。
应该不可能确定它失败了。
之前我使用 AES/CBC/PKCS5Padding 没有任何问题,但这不是一个选项。所以我的问题是:
如何添加自定义填充以获得 16 字节的倍数或可能导致 IllegalBlockSizeException (DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH) 的原因?我还读到密文窃取是一种方法。我将不胜感激。
这是我当前的代码:
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);
}
}
我用下面的代码解决了我的问题。我必须添加带空格的自定义填充:
@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();
//...
}
更新:我删除了代码中的另一个问题以使问题更准确。
我需要使用 AES/CBC/NoPadding 加密可变长度的字符串,但我收到 IllegalBlockSizeException。 我必须使用 NoPadding 因为即使解密失败,输入的长度也应与输出的长度相同。 应该不可能确定它失败了。
之前我使用 AES/CBC/PKCS5Padding 没有任何问题,但这不是一个选项。所以我的问题是:
如何添加自定义填充以获得 16 字节的倍数或可能导致 IllegalBlockSizeException (DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH) 的原因?我还读到密文窃取是一种方法。我将不胜感激。
这是我当前的代码:
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);
}
}
我用下面的代码解决了我的问题。我必须添加带空格的自定义填充:
@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();
//...
}