bitflip-at
bitflip-at

Reputation: 149

java read encrypted Objects

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!

Upvotes: 2

Views: 476

Answers (2)

Fabien Benoit-Koch
Fabien Benoit-Koch

Reputation: 2841

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.

Upvotes: 3

Fabien Benoit-Koch
Fabien Benoit-Koch

Reputation: 2841

Did you forget to call out.flush() and out.close() ?

If you did, some data may not be actually be written to the disk and it'll be impossible to read it again.

Upvotes: 1

Related Questions