Reputation: 11329
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. I have to use NoPadding because the input should have the same length as the output even if the decryption fails. 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. 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)? 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);
}
}
Upvotes: 2
Views: 8406
Reputation: 11329
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();
//...
}
Upvotes: 1