I have an Class/Object Access which is Serializable.
public class Access implements Serializable {
private static final long serialVersionUID = 1L;
private URL website;
private String username;
private String password;
// + some methods
}
Now when writing them to a File I encrypt them using a Cipher. Looks like this:
WRITING:
ObservableList<Access> userData;
userData = FXCollections.observableArrayList();
...
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, key128);
File file = new File("./resources/saves" + username);
file.createNewFile();
CipherOutputStream cipherOut = new CipherOutputStream(
new BufferedOutputStream(new FileOutputStream(file, true)), cipher);
ObjectOutputStream out = new ObjectOutputStream(cipherOut);
userData.forEach((item) -> {
try {
out.writeObject(new SealedObject(item, cipher));
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
});
out.flush();
out.close();
READING:
ObservableList<Access> access = FXCollections.observableArrayList();
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, key128);
CipherInputStream cipherIn = new CipherInputStream(
new BufferedInputStream(new FileInputStream("./resources/saves" + username)), cipher);
ObjectInputStream in = new ObjectInputStream(cipherIn);
SealedObject sealed;
while ((sealed = (SealedObject) in.readObject()) != null) {
access.add((Access) sealed.getObject(cipher));
}
If I now Load the File it seems corrupted. I find it hard to find the mistake. I think the problem is in the load function. Am I missing something obvious here?
Error:
java.io.StreamCorruptedException: invalid stream header: 3D23898C
Thank you for your time & help!
Okay, The problem is the interaction between the cipher stream and the object stream.
When you read the file, the ObjectInputStream
asks to the underlying stream (the cipher stream) to read a very specific header. But the cipher stream has zero knowledge of that - he reads the normal amount of bytes he is supposed to, according his own protocol, in order to make sense of the encrypted data. The result is that the ObjectInputStream gets a truncated/altered header and can't process the stream correctly.
Good news is, you don't actually need it ! The SealedObject
will take care of encryption/decryption for you. Simply remove the cipher stream and it should work.
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(file, true));
and to read:
FileInputStream inputStream = new FileInputStream(fileName);
ObjectInputStream ois = new ObjectInputStream(inputStream);
Now, if you really want to use the cipher stream (and thus effectively encrypt/decrypt the data twice with the same key), you need first to make a "first pass" on the file to decrypt it, and then open an object stream on the new decrypted file.