I'm trying to encrypt and decrypt plain text with AES("AES/CBC/PKCS7Padding") with Cipher.
Made secretKey by KeyGenerator and encrypt/decrypt with it.
This works well at first.
However, if plain text is a large string(such as 183244 characters), part of it is decrypted and not all of it.
"part of it" means
If plain text is "abcdefghijklmn", decrypted text comes like "abcdefgh"
(this is an example. actually this happens only with too long characters)
Code
// get key from Android kyestore
SecretKey secretKey = (SecretKey)mKeyStore.getKey(KEY_ALIAS, null);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
IvParameterSpec ivParams = cipher.getParameters().getParameterSpec(IvParameterSpec.class);
//
// Encrypt
//
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
CipherOutputStream cipherOutputStream = new CipherOutputStream(outputStream, cipher);
cipherOutputStream.write(plainString.getBytes("UTF-8"));
cipherOutputStream.close();
String encryptedString = Base64.encodeToString(outputStream.toByteArray(), Base64.DEFAULT);
//
// Decrypt
//
Cipher decryptCipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
decryptCipher.init(Cipher.DECRYPT_MODE, secretKey, ivParams);
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(Base64.decode(encryptedString, Base64.DEFAULT));
CipherInputStream cipherInputStream = new CipherInputStream(byteArrayInputStream, decryptCipher);
outputStream = new ByteArrayOutputStream();
int b;
while ((b = cipherInputStream.read()) != -1) {
outputStream.write(b);
}
outputStream.close();
String decryptedString = outputStream.toString("UTF-8");
//
// results. decrypted string is part of source string and short.
//
int sourceStringLength = plainString.length(); // is 183244;
int decryptedStringLength = decryptedString.length()); // is UNEXPECTED 68553;
Could you please let know the point to fix this?
Edited
I've checked number of bytes on encryption/decryption.
encryption output bytes : "outputStream.toByteArray().length" is 68560
decryption input bytes : "Base64.decode(encryptedString, Base64.DEFAULT).length" is also 68560
I think this means decryption process doesn't lost any part of it and encryption process may truncate part of input plain text. is this because of restriction of AES algorithm?
Solved
As @zaph commented, not all of the bytes is written to steam.
Replacing
cipherOutputStream.write(plainString.getBytes("UTF-8"));
cipherOutputStream.close();
with
// NOTE: workaround. too bit bytes doesn't writted correctly.
byte[] bytes = plainString.getBytes("UTF-8");
int oneBulkSize = 1024;// temp value for proof of concept. might be bigger one.
int numOfBulk = (bytes.length / oneBulkSize);
for (int i = 0; i < numOfBulk; i++) {
cipherOutputStream.write(bytes, oneBulkSize * i, oneBulkSize);
}
if ((bytes.length % oneBulkSize) != 0) {
cipherOutputStream.write(bytes, oneBulkSize * numOfBulk, bytes.length % oneBulkSize);
}
cipherOutputStream.close();
solved the issue.
(Base64.decode(encryptedString, Base64.DEFAULT)
? – Maarten BodewesCipher.getInstance("AES/CBC/PKCS7Padding");
, but on decrypt you haveCipher.getInstance(ALGORITHM);
. So what isALGORITHM
? – President James K. Polk