Deviance
Deviance

Reputation: 21

Finding missing byte in a encryption key: Java

So part 2 of my assignment is to find the missing byte of an encryption key. As a background I am not too familiar with this so I have no clue on where to start. I have looked around and cannot seem to find a starting place. The information I have is that the encryption key is in AES/ECB key: {'__' '7e' '15' '16' '28' 'ae' 'd2' 'a6' 'ab' 'f7' '15' '88' '09' 'cf' '4f' '3c'};

What I did try is looping through ACII values (0-255) and then getting the byte of the values and appending them to the byte array of the key. After I would attempt to decrypt the file as normal and output the new file in hopes to see a picture. However I am not seeing anything. Can you please point me to where I am going wrong?

byte[] convertHexString = DatatypeConverter.parseHexBinary(key);
String newKey = new String(convertHexString);
byte[] keyByte = newKey.getBytes();
String[] asciiArray = new String[256];
FileInputStream file = new FileInputStream(path);
Cipher aesCipher = Cipher.getInstance(transformation);
for(int i = 0;i<256; i++){
    arrayInts[i] = Character.toString((char)i);
    byte[] b = asciiArray [i].getBytes();
    byte[] result = new byte[b.length + keyByte.length]; 
    System.arraycopy(b, 0, result, 0, b.length); 
    System.arraycopy(keyByte, 0, result, b.length, keyByte.length); 
    FileOutputStream out = new FileOutputStream("AESencrypt_view" + String.valueOf(i)+".jpg");
    SecretKeySpec key1 = new SecretKeySpec(result,"AES");
    aesCipher.init(Cipher.DECRYPT_MODE, key1);
    CipherOutputStream  outSt = new CipherOutputStream(out,aesCipher);
    byte[] buf = new byte[1024];
    int read;
    while((read=file.read(buf))!=-1){
        outSt.write(buf, 0, read);

    }
    //file.close();
    out.flush();
    outSt.flush();
}

Upvotes: 0

Views: 369

Answers (2)

Artjom B.
Artjom B.

Reputation: 61952

You have many problems with your code.

Don't store binary data in strings

This

byte[] convertHexString = DatatypeConverter.parseHexBinary(key);
String newKey = new String(convertHexString);
byte[] keyByte = newKey.getBytes();

should be reduced to

byte[] keyByte = DatatypeConverter.parseHexBinary(key);

Be aware of NullPointerExceptions

This

String[] asciiArray = new String[256];
...
asciiArray[i].getBytes();

is actually a NullPointerException, because asciiArray[i] was never initialized. When you create an array of non-primitive types, the array is always initialized with all null values.

A FileInputStream produces the file contents only once

You have the code

FileInputStream file = new FileInputStream(path);

outside of the loop, but you're reading the file inside of the loop until it is fully read. The problem is that this works only for the first iteration. In the next iteration (i == 1), there is no data to be read, so nothing to decrypt.

You should either read the file into a byte[] before the for-loop or initialize the stream inside of the for-loop in order to be able to read the file every time.

Listen for the errors

CipherInputStream and CipherOutputStream hide some exceptions. In particular, ECB mode is a non-streaming block cipher mode, so it must have some kind of padding. Usually, this padding is from PKCS#5 (= PKCS#7). You should use the Cipher and it's update method directly. When you're done writing data, then you can call the doFinal method and if the key was wrong, you will get an exception that you can catch with a probability of 255/256th (approx. 1).

Make the key iteration easier

byte[] keyByte = DatatypeConverter.parseHexBinary("007e151628aed2a6abf7158809cf4f3c");

for(int i = 0; i < 256; i++){
    keyByte[0] = (byte)i;
    ...
}

That's it. You don't need more to change the first byte of the key.


Some example code:

byte[] keyByte = DatatypeConverter.parseHexBinary("007e151628aed2a6abf7158809cf4f3c");
Cipher aesCipher = Cipher.getInstance(transformation);
byte[] buf = new byte[1024];

for(int i = 0; i < 256; i++){
    keyByte[0] = (byte)i;

    FileInputStream inFileStream = new FileInputStream(path);
    File outFile = new File("AESencrypt_view" + String.valueOf(i)+".jpg");
    FileOutputStream outFileStream = new FileOutputStream(outFile);

    SecretKeySpec keySpec = new SecretKeySpec(keyByte, "AES");
    aesCipher.init(Cipher.DECRYPT_MODE, keySpec);

    int read;
    while((read = inFileStream.read(buf)) != -1){
        outFileStream.write(aesCipher.update(buf, 0, read));
    }
    inFileStream.close();

    try {
        outFileStream.write(aesCipher.doFinal());
        outFileStream.close();
    }
    catch(BadPaddingException e) {
        // obviously a wrong key or broken ciphertext
        outFileStream.close();
        outFile.delete();
    }
}

If the file is small, you don't have to read it again and again in every iteration, you can read it once before the for-loop.

Upvotes: 2

dcsohl
dcsohl

Reputation: 7406

That's not the way you want to iterate through the possible 256 byte values! Consider, for example, what happens when i = 137: You say Character.toString((char)137) - the output of this is the Unicode character U+0089. Calling s.getBytes() on this gives you the byte array [-62, -118]. Already we know we are in trouble since this should not be two bytes! (This is the UTF-8 interpretation of the character U+0089, FYI.)

Instead, why not just iterate through the possible byte values? There's no reason the for-loop has to iterate over int values; you can iterate directly over byte values. (NB: bytes in Java are signed, for no good reason, so the for-loop looks a little odd, but this is the right way):

for (byte b = -128; b<128; b++) {
    byte[] result = new byte[keyByte.length +1]; 
    result[0] = b;
    System.arraycopy(keyByte, 0, result, 1, keyByte.length); 
    // yadda yadda yadda
}

Upvotes: 1

Related Questions