0

I'm writing an implementation for AES with 128 bit key. An exception is thrown at the last line of the else block.

    private static int KEY_SIZE_IN_BYTE = 16;
    private static int EXPANDED_KEY_SIZE_IN_BYTE = 176;
    private static int BYTE_PER_WORD = 4;

private static byte[][] doKeyExpansion(byte[] keyByteArray) {
        int keySizeInWord = KEY_SIZE_IN_BYTE / BYTE_PER_WORD;
        int expandedKeySizeInWord = EXPANDED_KEY_SIZE_IN_BYTE / BYTE_PER_WORD;
        
        byte[][] result = new byte[expandedKeySizeInWord][BYTE_PER_WORD];
        
        for(int i = 0; i < keySizeInWord; i++) {
            for(int j = 0; j < BYTE_PER_WORD; j++) {
                result[i][j] = keyByteArray[i * BYTE_PER_WORD + j];
            }
        }
        
        for(int i = keySizeInWord; i < expandedKeySizeInWord; i++) {
            byte[] temp = new byte[BYTE_PER_WORD];
            
            // Rotate word if 4 divides i
            if(i % 4 == 0) {
                for(int j = 0; j < BYTE_PER_WORD; j++) {
                    temp[j] = result[i - 1][(j + 1) % BYTE_PER_WORD];
                }
            } else {
                for(int j = 0; j < BYTE_PER_WORD; j++) {
                    byte a = result[i - 1][j];
                    temp[j] = 1;
                    byte b = 5;
                    temp[j] = b;

                    // Exception is thrown if this is not commented
                    //temp[j] = a;
                }
            }
            
            // Substitute using Sbox
            for(int j = 0; j < BYTE_PER_WORD; j++) {
                temp[j] = substitueWithSbox(temp[j]);
            }
            
            // xor round constant
            byte[] roundConstant = { (byte) ROUND_CONSTANT_FIRST_BYTE[(i / BYTE_PER_WORD) - 1], 0, 0, 0}; 
            temp = xorWord(temp, roundConstant);
            
            result[i] = xorWord(temp, result[i - 4]);
        }
        
        return result;
    }
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3

When I comment it out like this, the code runs fine without problem. I attempted to separate them out like a few lines above, and both sides of the assignments don't trigger any exception. I don't know why this happen.

Could somebody help please?

I add this so it could help provide detail of the situation. Line 83 throws an excpetion if line 87 is not commented (Thanks to @tgdavies that he corrected me on this). Comment it out and it will work. This is the most confusing thing that I've seen so far.

import java.util.BitSet;

public class Duplicate {
    
    private static byte HEX_BASE = 16;

    private static int KEY_SIZE_IN_BYTE = 16;

    private static int EXPANDED_KEY_SIZE_IN_BYTE = 176;
    private static int BYTE_PER_WORD = 4;

    
    private static int[] SBOX = {
            0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
            0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
            0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
            0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
            0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
            0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
            0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
            0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
            0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
            0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
            0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
            0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
            0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
            0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
            0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
            0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16
            };
    
    private static int[] ROUND_CONSTANT_FIRST_BYTE = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36 };

    public static void main(String[] args) {
        String plaintextExample = "0123456789abcdeffedcba9876543210".toUpperCase();
        String keyExample = "0f1571c947d9e8590cb7add6af7f6798".toUpperCase();
        String ciphertextExample = "ff0b844a0853bf7c6934ab4364148fb9".toUpperCase();
        
        String plaintextExample2 = "0023456789abcdeffedcba9876543210".toUpperCase();
        String ciphertextExample2 = "612b89398d0600cde116227ce72433f0".toUpperCase();
        
        byte[] keyByteArray = convertKeyToByteArray(keyExample);
        byte[][] expandedKey = doKeyExpansion(keyByteArray);
        
//      for(int i = 0; i < 44; i++) {
//          for(int j = 0; j < 4; j++) {
//              System.out.print(Integer.toHexString(Byte.toUnsignedInt(expandedKey[i][j])));
//          }
//      }
        
        System.out.println("Done");
    }
    
    private static void testByteArray(byte[] toTest) {
        for(int i = 0; i < toTest.length; i++) {
            System.out.print(toTest[i]);
        }
        System.out.println();
    }

    private static byte[][] doKeyExpansion(byte[] keyByteArray) {
        int keySizeInWord = KEY_SIZE_IN_BYTE / BYTE_PER_WORD;
        int expandedKeySizeInWord = EXPANDED_KEY_SIZE_IN_BYTE / BYTE_PER_WORD;
        
        byte[][] result = new byte[expandedKeySizeInWord][BYTE_PER_WORD];
        
        for(int i = 0; i < keySizeInWord; i++) {
            for(int j = 0; j < BYTE_PER_WORD; j++) {
                result[i][j] = keyByteArray[i * BYTE_PER_WORD + j];
            }
        }
        
        for(int i = keySizeInWord; i < expandedKeySizeInWord; i++) {
            byte[] temp = new byte[BYTE_PER_WORD];
            
            // Rotate word if 4 divides i
            if(i % 4 == 0) {
                for(int j = 0; j < BYTE_PER_WORD; j++) {
                    temp[j] = result[i - 1][(j + 1) % BYTE_PER_WORD];
                }
            } else {
                for(int j = 0; j < BYTE_PER_WORD; j++) {
                    byte a = result[i - 1][j];    // line 83
                    temp[j] = 1;
                    byte b = 5;
                    temp[j] = b;
                    temp[j] = a;    // line 87
                }
            }
            
            // Substitute using Sbox
            for(int j = 0; j < BYTE_PER_WORD; j++) {
                temp[j] = substitueWithSbox(temp[j]);
            }
            
            // xor round constant
            byte[] roundConstant = { (byte) ROUND_CONSTANT_FIRST_BYTE[(i / BYTE_PER_WORD) - 1], 0, 0, 0}; 
            temp = xorWord(temp, roundConstant);
            
            result[i] = xorWord(temp, result[i - 4]);
        }
        
        return result;
    }

    private static byte[] xorWord(byte[] byteArray1, byte[] byteArray2) {
        byte[] result;
        BitSet bitSet = new BitSet(byteArray1.length * 8);
        
        for(int i = 0; i < byteArray1.length; i++) {
            int unsignedByte1 = Byte.toUnsignedInt(byteArray1[i]);
            int unsignedByte2 = Byte.toUnsignedInt(byteArray2[i]);
            for(int j = 0; j < 8; j++) {
                bitSet.set(i * 8 + j, unsignedByte1 % 2 != unsignedByte2 % 2);
                unsignedByte1 /= 2;
                unsignedByte2 /= 2;
            }
        }
        
        result = bitSet.toByteArray();
        return result;
    }

    private static byte substitueWithSbox(byte b) {
        int temp = Byte.toUnsignedInt(b);
        return (byte) SBOX[temp];
    }

    private static byte[] convertKeyToByteArray(String keyExample) {
        byte[] result = new byte[KEY_SIZE_IN_BYTE];
        
        for(int i = 0; i < keyExample.length(); i += 2) {
            result[i/2] = convertHexBlockToByte(keyExample.substring(i, i+2));
        }
        
        return result;
    }

    private static byte convertHexBlockToByte(String hexBlock) {
        return (byte) (convertHexDitgitToDecimal(hexBlock.charAt(0)) * HEX_BASE +
                            convertHexDitgitToDecimal(hexBlock.charAt(1)));
    }

    private static byte convertHexDitgitToDecimal(char hexDigit) {
        byte result = 0;
        
        switch(hexDigit) {
        case '0':
            result = 0;
            break;
        case '1':
            result = 1;
            break;
        case '2':
            result = 2;
            break;
        case '3':
            result = 3;
            break;
        case '4':
            result = 4;
            break;
        case '5':
            result = 5;
            break;
        case '6':
            result = 6;
            break;
        case '7':
            result = 7;
            break;
        case '8':
            result = 8;
            break;
        case '9':
            result = 9;
            break;
        case 'A':
            result = 10;
            break;
        case 'B':
            result = 11;
            break;
        case 'C':
            result = 12;
            break;
        case 'D':
            result = 13;
            break;
        case 'E':
            result = 14;
            break;
        case 'F':
            result = 15;
            break;
        }
        
        return result;
    }

}
9
  • Add debug code to display the value of your index before you attempt to use it. Once you see the value is incorrect, then fix the problem. Commented Jul 18, 2021 at 0:16
  • 1
    This seems weird because you access temp[j] before, can you show exactly the code that don't work? Commented Jul 18, 2021 at 0:19
  • Check the line number given in the stack trace. Make sure you are correct about which line is causing the problem. Commented Jul 18, 2021 at 0:31
  • 1
    What you wrote is impossible. If you take that code as is, and it works, and then uncomment that one line you marked down and change nothing else, it cannot possibly then crash: All involved variables are local and you wrote to temp[j] on the immediately preceding line. Check your work: Is this actually your code, is the exception actually happening there? Then update the question. Commented Jul 18, 2021 at 1:18
  • Fire up your debugger and set break points. Step through your code and make sure you what you think is happening is actually what's happening. Hint: you're probably mistaken. Commented Jul 18, 2021 at 1:33

1 Answer 1

1

Run this little program, but first try to predict what it will print. Then think about your xorWord function:

public class BitSetEg {
    public static void main(String... args) {
        BitSet b = new BitSet(32);

        byte[] bytes = b.toByteArray();
        System.out.println(bytes.length);
    }
}
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you very much! This solves my problem. Now I know that I was sloppy with BitSet. Sorry that I cannot vote your answer.

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.