user13356
user13356

Reputation: 21

Java decryption provides a different result from the original

While encrypting and decrypting a file using CipherInputStream and CipherOutputStream, the decrypted file is different from the original. There are no errors thrown when during execution, but the original and the result have different hashes. The original and the result are also the exact same size. There is not any file collisions/overwriting going on. My best guess so far is character encoding.

public void fileTest(File source, File output, String key) throws Exception {
    Log.write("Starting file encryption/decryption test!");
    Util.charset = CharsetToolkit.guessEncoding(source, 4096, StandardCharsets.UTF_8);
    Log.write("Using charset " + Util.charset.name());
    Log.write("Using key: " + key);
    String oHash = Util.checksum(source);
    Log.write("Original hash: " + oHash);

    //Cipher setup

    SecretKeySpec sks = Util.padKey(key);
    Cipher eCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    Cipher dCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    eCipher.init(Cipher.ENCRYPT_MODE, sks, new IvParameterSpec(new byte[16]));
    dCipher.init(Cipher.DECRYPT_MODE, sks, new IvParameterSpec(new byte[16]));

    //IO setup
    File tmpEncrypt = new File(source.getParent() + "/" + source.getName() + "-tmp");
    tmpEncrypt.createNewFile();
    output.createNewFile();
    Log.write("Encrypting to: " + tmpEncrypt.getAbsolutePath());
    InputStream fis = new FileInputStream(source);
    InputStream enIn = new FileInputStream(tmpEncrypt);
    OutputStream fos = new FileOutputStream(tmpEncrypt);
    OutputStream clearOut = new FileOutputStream(output);
    CipherInputStream cis = new CipherInputStream(enIn, dCipher);
    CipherOutputStream cos = new CipherOutputStream(fos, eCipher);

    //Encrypt
    Log.write("Starting encryption process");
    int numRead = 0;
    byte[] buffer = new byte[1024];
    while ((numRead = fis.read(buffer)) >= 0) {
        cos.write(buffer, 0, numRead);
    }

    cos.close();
    fos.close();
    Log.write("Done!");

    Log.write("Encrypted hash: " + Util.checksum(output));

    //Decrypt
    Log.write("Starting decryption process");
    int nr = 0;
    byte[] b = new byte[1024];
    while ((nr = cis.read(b)) >= 0) {
        clearOut.write(buffer, 0, nr);
    }
    clearOut.close();
    cis.close();
    fis.close();
    Log.write("Done!");

    String fHash = Util.checksum(output);
    Log.write("Final hash: " + fHash);

    if(fHash.equals(oHash)) {
        Log.write("Success! The hashes are equal!");
    } else {
        Log.write("Failure! Hashes are different!");
    }
}

EDIT: I took your advice @zaph, and now it seems to be a problem with writing/read the file. The file is exactly 40 bytes long. Here's the hex dumps:

Key hex: 000074657374696e676b65797364617767313233
IV hex: 0000000000000000000000000000000000000000
Data IN: Lorem ipsum dolor sit amet orci aliquam.
Data OUT: Lorem ipsum dolor sit amet orci Lorem ip.

Odd, it seems to be overwriting the last 8 bytes with a repetition of the first 8 bytes. I tried adjusting my buffer size from 1024 bytes down to 8 bytes, and it got even stranger. Hex dump from 8 byte test:

Key hex: 000074657374696e676b65797364617767313233
IV hex: 0000000000000000000000000000000000000000
Data IN: Lorem ipsum dolor sit amet orci aliquam.
Data OUT: aliquam.aliquam.aliquam.aliquam.aliquam.

Something is definitely wrong with the way the first is being read/wrote, but I don't have a clue what is going on. Thank you in advance!

Upvotes: 0

Views: 274

Answers (1)

user13356
user13356

Reputation: 21

Solved it! There was a problem with my while loops. Like this one:

while ((nr = cis.read(b)) >= 0) {
    clearOut.write(buffer, 0, nr);
}

So I replaced it with a for loop instead and everything is working.

int segs = (int) (source.length() / 4);
for (int i = 0; i < segs; i++) {
    fis.read(buffer);
    cos.write(buffer, 0, buffer.length);
}

Upvotes: 2

Related Questions