// Denne implementation kører med 128 bit state (dvs. input og output) og 128 bit nøgle. // Al kode er lavet af Henrik Sørensen, haas@itu.dk. public class AES { // Antal runder final int rounds = 10; // Pointer ind i ExpandedKey. public int ExpandedKeyP = 0; public byte[] state = new byte[16]; public byte[] key = new byte[16]; byte[] Sbox = new byte[256]; byte[] invSbox = new byte[256]; byte[] ExpandedKey = new byte[16 * (10 + 1)]; private void SubBytes() { for (int i = 0 ; i < 16 ; i++) { state[i] = Sbox[ ToInt(state[i])]; } } private void InvSubBytes() { for (int i = 0 ; i < 16 ; i++) { state[i] = invSbox[ ToInt(state[i])]; } } private byte SubByte(byte a) { return Sbox[ToInt(a)]; } // Da det i denne implementation altid gælder at nøglen er mindre end 192 bit, har jeg // kun implementeret den ene af KeyExpansion-funktionerne. private void ExpandKey() { byte[] tmp = new byte[5]; // Den 5. byte bruges som en imidlertid variabel. byte[] Rcon = new byte[12]; Rcon[1] = 0x01; for (int i = 2 ; i < 12 ; i++) { Rcon[i] = XTime(Rcon[i-1]); } // Kopier cipher-key ind i de første 4 words af expandedkey. for (int i = 0 ; i < 16 ; i++) ExpandedKey[i] = key[i]; for (int i = 4 ; i < 4 * (10 + 1) ; i++) { // Itererer words, ikke bytes. for (int j = 0 ; j < 4 ; j++) tmp[j] = ExpandedKey[4*(i-1) + j]; if ( (i % 4) == 0) { // RotWord tmp[4] = tmp[0]; for (int j = 0 ; j < 4; j++) tmp[j] = tmp[j+1]; // SubWord for (int j = 0 ; j < 4; j++) tmp[j] = SubByte(tmp[j]); tmp[0] = (byte)(tmp[0] ^ Rcon[i / 4]); } for (int j = 0 ; j < 4; j++) ExpandedKey[4*i + j] = (byte)(ExpandedKey[4*(i - 4) + j] ^ tmp[j]); } } // Debug-metode; Bruges til let at udskrive et array på 4 bytes. public static void WriteWord(String desc, byte[] w) { MSG(desc + ": "); for (int i = 0 ; i < 4 ; i++) { MSG(Byte2Hex(w[i]) + " "); } MSG("\n"); } private void InvShiftRows() { byte tmp; // Række 1 tmp = state[13]; state[13] = state[9]; state[9] = state[5]; state[5] = state[1]; state[1] = tmp; // Række 2 tmp = state[14]; state[14] = state[6]; state[6] = tmp; tmp = state[10]; state[10] = state[2]; state[2] = tmp; // Række 3 tmp = state[3]; state[3] = state[7]; state[7] = state[11]; state[11] = state[15]; state[15] = tmp; } private void ShiftRows() { byte tmp; // Række 1 tmp = state[1]; state[1] = state[5]; state[5] = state[9]; state[9] = state[13]; state[13] = tmp; // Række 2 tmp = state[14]; state[14] = state[6]; state[6] = tmp; tmp = state[10]; state[10] = state[2]; state[2] = tmp; // Række 3 tmp = state[15]; state[15] = state[11]; state[11] = state[7]; state[7] = state[3]; state[3] = tmp; } // Kan udskrive klassens tabeller. public void PrintState() { String[] tmp = {"","","",""}; for (int i = 0 ; i < 16 ; i++) { tmp[i % 4] += Byte2Hex(state[i]) + " "; } for (int i = 0 ; i < 4 ; i++) System.out.println(tmp[i]); } public void PrintKey() { String[] tmp = {"","","",""}; for (int i = 0 ; i < 16 ; i++) { tmp[i % 4] += Byte2Hex(key[i]) + " "; } for (int i = 0 ; i < 4 ; i++) System.out.println(tmp[i]); } public void PrintExpandedKey() { for (int i = 0 ; i < 176 ; i++) { System.out.print("" + Byte2Hex(ExpandedKey[i]) + " "); if ( (i % 16 ) == 15) MSG("\n"); } } private void MixColumns() { byte[] tmp = new byte[4]; // Kan indeholde en søjle. for (int i = 0 ; i < 4 ; i++) { // Itererer igennem søjlerne. // Følgende er implementeret som beskrevet i [1] sektion 5.1.3. tmp[0] = (byte)(PolyMult((byte)0x02, state[i*4]) ^ PolyMult((byte)0x03, state[i*4+1]) ^ state[i*4+2] ^ state[i*4+3]); tmp[1] = (byte)(state[4*i] ^ PolyMult((byte) 0x02, state[4*i+1]) ^ PolyMult((byte) 0x03, state[4*i+2]) ^ state[4*i+3]); tmp[2] = (byte)(state[4*i] ^ state[4*i+1] ^ PolyMult((byte)0x02, state[4*i+2]) ^ PolyMult((byte)0x03,state[4*i+3])); tmp[3] = (byte)(PolyMult((byte)0x03, state[4*i]) ^ state[4*i+1] ^ state[4*i+2] ^ PolyMult((byte)0x02,state[4*i+3])); for (int j = 0 ; j < 4; j++) state[4*i+j] = tmp[j]; } } private void InvMixColumns() { byte[] tmp = new byte[4]; for (int i = 0 ; i < 4 ; i++) { // Følgende er implementeret som beskrevet i [1] sektion 5.3.3 tmp[0] = (byte)(PolyMult((byte)0x0e, state[4*i]) ^ PolyMult((byte) 0x0b, state[4*i+1]) ^ PolyMult((byte)0x0d, state[4*i+2]) ^ PolyMult((byte)0x09, state[4*i+3])); tmp[1] = (byte)(PolyMult((byte)0x09, state[4*i]) ^ PolyMult((byte) 0x0e, state[4*i+1]) ^ PolyMult((byte)0x0b, state[4*i+2]) ^ PolyMult((byte)0x0d, state[4*i+3])); tmp[2] = (byte)(PolyMult((byte)0x0d, state[4*i]) ^ PolyMult((byte) 0x09, state[4*i+1]) ^ PolyMult((byte)0x0e, state[4*i+2]) ^ PolyMult((byte)0x0b, state[4*i+3])); tmp[3] = (byte)(PolyMult((byte)0x0b, state[4*i]) ^ PolyMult((byte) 0x0d, state[4*i+1]) ^ PolyMult((byte)0x09, state[4*i+2]) ^ PolyMult((byte)0x0e, state[4*i+3])); for (int j = 0 ; j < 4; j++) state[4*i+j] = tmp[j]; } } public static byte XTime(byte a, byte times) { for (int i = 0 ; i < times ; i++) a = XTime(a); return a; } public static byte XTime(byte a) { byte b; b = (byte)(a << 1); if ( (a & 128) != 0) b = (byte) (b ^ (0x1b)); return b; } // Udskriver en byte i binær notation. public static void Byte2Bin(byte b) { for (int i = 7 ; i >= 0 ; i--) if ( (b & (1 << i)) != 0) System.out.print("1"); else System.out.print("0"); } // En funktion der udfører multiplikationen af to polynomier, som beskrevet i // [1] sektion 4.2. public static byte PolyMult(byte a, byte b) { byte res = 0; for (byte i = 7 ; i >= 0 ; i--) if ( (a & (1 << i)) != 0 ) res = (byte)(res ^ XTime(b, i)); return res; } private void AddRoundKey() { for (int i = 0 ; i < 16 ; i++) { state[i] = (byte)(state[i] ^ ExpandedKey[ExpandedKeyP]); ExpandedKeyP++; } } private void InvAddRoundKey() { for (int i = 15 ; i >= 0 ; i--) { state[i] = (byte)(state[i] ^ ExpandedKey[ExpandedKeyP]); ExpandedKeyP--; } } // Blot lavet for at lette udskrivningen af debug-information til konsollen. public static void MSG(String msg) { System.out.print(msg); } // Function der viser datatypen byte i hex. public static String Byte2Hex(byte b) { byte tmp = 0; String str=""; for (int i = 7 ; i > 3 ; i--) if ( (b & (1 << i)) != 0) tmp = (byte) (tmp |(1 << (i - 4))); if (tmp < 10) { str = str + tmp; } else { char c = (char)('A' + (tmp - 10)); str = str + c; } tmp = 0; for (int i = 3 ; i > -1 ; i--) if ( (b & (1 << i)) != 0) tmp = (byte) (tmp |(1 << (i))); if (tmp < 10) str = str + tmp; else { char c = (char)('A' + (tmp - 10)); str = str + c; } return str; } // Lavet for at undgå at skulle bekymre sig om javas mangel på "unsigned byte". public static byte ToByte(int a) { byte tmp = 0; for (int i = 7 ; i >= 0 ; i--) if ( (a & (1 <= 0 ; i--) if ( (a & (1 <