0

I'm using Cipher/CipherInputStream to encrypt and decrypt a database file(sqlite) in Android to backup it.
When I use the FileInputStream without Cipher, it works very well. But when I use the Cipher, the file encrypt successfuly, but when I decrypt(restore) it, the database doesn't decrypt to the original "source code".
The original caracteres(source code) seems to be an ideogram/hieroglyphs/kanjis(I don't know), and when I encrypt and decrypt, the "source code" is sql(english) restored O.O
That makes the 'database corrupted'

Only to clarify

Backup

File dbFile = new File(PATH_DB);

FileInputStream fileInputStream = new FileInputStream(PATH_DB);

FileOutputStream outputStream = new FileOutputStream(PATH_BKP);

byte[] s = Arrays.copyOf(KEY_DATABASE.getBytes(),16);
SecretKeySpec sks = new SecretKeySpec(s, "AES");

Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.ENCRYPT_MODE, sks);

CipherOutputStream cos = new CipherOutputStream(outputStream, cipher);

//Transferencia dos dados do inputfile para o output
byte[] buffer = new byte[1024];
int length;
while ((length = fileInputStream.read(buffer))!= -1) {
    cos.write(buffer,0,length);
}

//Fecha as streams
cos.flush();
cos.close();
fileInputStream.close();

Restore:

FileInputStream fis = new FileInputStream(PATH_BKP);

FileOutputStream fos = new FileOutputStream(PATH_DB);

byte[] s = Arrays.copyOf(KEY_DATABASE.getBytes(),16);
SecretKeySpec sks = new SecretKeySpec(s, "AES");

Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.DECRYPT_MODE, sks);

CipherInputStream cis = new CipherInputStream (fis, cipher);

byte[] buffer = new byte[1024];
int length;
while ((length = cis.read(buffer)) != -1) {
    fos.write(buffer, 0, length);
}

fos.flush();
fos.close();
cis.close();

1 Answer 1

2

CBC mode needs an initialization vector (IV) to operate. This IV is not a secret value, but it has to be unpredictable (read: randomly chosen). In order for the decryption to work, you must use the same IV. Otherwise, the first block will be corrupted. A common way to solve this is to write the IV in front of the ciphertext.

If you call Cipher#init without an IvParameterSpec as the third argument, the IV will be automatically generated for you. If you don't store it, it will be lost.

During encryption

Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.ENCRYPT_MODE, sks);

outputStream.write(cipher.getIV()); // store the generated IV

CipherOutputStream cos = new CipherOutputStream(outputStream, cipher);

During decryption

byte[] iv = new byte[16]; // 16 is the block size of AES
if (fis.read(iv) != 16) {
    throw new Exception("Incomplete IV"); // TODO: rename to a different exception
}

Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.DECRYPT_MODE, sks, new IvParameterSpec(iv));

CipherInputStream cis = new CipherInputStream (fis, cipher);
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.