package aes import ( "encoding/hex" "fmt" "log" "strconv" ) var sbox = [][]byte{ {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}, } var invSbox = [][]byte{ {0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb}, {0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb}, {0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e}, {0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25}, {0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92}, {0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84}, {0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06}, {0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b}, {0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73}, {0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e}, {0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b}, {0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4}, {0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f}, {0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef}, {0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61}, {0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d}, } var mm = []byte{ 2, 3, 1, 1, 1, 2, 3, 1, 1, 1, 2, 3, 3, 1, 1, 2, } var iMM = []byte{ 14, 11, 13, 9, 9, 14, 11, 13, 13, 9, 14, 11, 11, 13, 9, 14, } var rcon = []byte{0x00, // rcon[] is 1-based, so the first entry is just a place holder 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36, 0x6C, 0xD8, 0xAB, 0x4D, 0x9A, 0x2F, 0x5E, 0xBC, 0x63, 0xC6, 0x97, 0x35, 0x6A, 0xD4, 0xB3, 0x7D, 0xFA, 0xEF, 0xC5, 0x91, 0x39, 0x72, 0xE4, 0xD3, 0xBD, 0x61, 0xC2, 0x9F, 0x25, 0x4A, 0x94, 0x33, 0x66, 0xCC, 0x83, 0x1D, 0x3A, 0x74, 0xE8, 0xCB, 0x8D, } //Block renamed []byte type for simplicity type Block []byte var keyexpanded []Block var key Block //ToString writes []Block to a string in ascii form func ToString(all []Block, keysize int, k Block, decrypt bool) string { final := "" for _, bl := range all { result := Block{} if decrypt { result = InvCipher(bl, keysize, k) } else { result = Cipher(bl, keysize, k) } final += string(result) } return final } //ToHex writes []Block to a string in hex form func ToHex(all []Block, keysize int, k Block, decrypt bool) string { final := "" for _, bl := range all { result := Block{} if decrypt { result = InvCipher(bl, keysize, k) } else { result = Cipher(bl, keysize, k) } for i := 0; i < 16; i++ { final += fmt.Sprintf("0x%x ", result[i]) } } return final } //BlockGen helps create []Block from incoming string func BlockGen(arg string) []Block { all := []Block{} b := Block{} for i, char := range arg { value, err := strconv.ParseUint( hex.EncodeToString( []byte(string(char))), 16, 32, ) if err != nil { log.Fatal(err) } if i%16 == 0 && i > 0 { all = append(all, b) b = b[:0] } b = append(b, byte(value)) if i == len(arg)-1 { all = append(all, b) } } return all } //Cipher performs AES cipher func Cipher(cur Block, bit int, incomingKey Block) Block { if len(cur) != 16 { missing := 16 - len(cur) for i := 0; i < missing; i++ { cur = append(cur, 0x00) } } key = Block{} keyexpanded = []Block{} assignKey(incomingKey) if bit == 128 { keyExpansionBase(128) cur = addRoundKey(cur, 0) for i := 0; i < 9; i++ { cur = subBytes(cur) cur = shiftRows(cur) cur = mixColumns(cur) cur = addRoundKey(cur, i+1) } cur = subBytes(cur) cur = shiftRows(cur) cur = addRoundKey(cur, 10) return cur } if bit == 192 { keyExpansionBase(192) cur = addRoundKey(cur, 0) for i := 0; i < 11; i++ { cur = subBytes(cur) cur = shiftRows(cur) cur = mixColumns(cur) cur = addRoundKey(cur, i+1) if i == 0 { } } cur = subBytes(cur) cur = shiftRows(cur) cur = addRoundKey(cur, 12) return cur } if bit == 256 { keyExpansionBase(256) cur = addRoundKey(cur, 0) for i := 0; i < 13; i++ { cur = subBytes(cur) cur = shiftRows(cur) cur = mixColumns(cur) cur = addRoundKey(cur, i+1) if i == 0 { } } cur = subBytes(cur) cur = shiftRows(cur) cur = addRoundKey(cur, 14) return cur } return cur } //InvCipher inverse AES cipher func InvCipher(cur Block, bit int, incomingKey Block) Block { if len(cur) != 16 { missing := 16 - len(cur) for i := 0; i < missing; i++ { cur = append(cur, 0x00) } } key = Block{} keyexpanded = []Block{} assignKey(incomingKey) if bit == 128 { keyExpansionBase(128) cur = addRoundKey(cur, 10) for i := 9; i > 0; i-- { cur = invShiftRows(cur) cur = invSubBytes(cur) cur = addRoundKey(cur, i) cur = invMixColumns(cur) } cur = invSubBytes(cur) cur = invShiftRows(cur) cur = addRoundKey(cur, 0) return cur } if bit == 192 { keyExpansionBase(192) cur = addRoundKey(cur, 12) for i := 11; i > 0; i-- { cur = invShiftRows(cur) cur = invSubBytes(cur) cur = addRoundKey(cur, i) cur = invMixColumns(cur) } cur = invSubBytes(cur) cur = invShiftRows(cur) cur = addRoundKey(cur, 0) return cur } if bit == 256 { keyExpansionBase(256) cur = addRoundKey(cur, 14) for i := 13; i > 0; i-- { cur = invShiftRows(cur) cur = invSubBytes(cur) cur = addRoundKey(cur, i) cur = invMixColumns(cur) } cur = invSubBytes(cur) cur = invShiftRows(cur) cur = addRoundKey(cur, 0) return cur } return cur } func addRoundKey(cur Block, iteration int) Block { for i := 0; i < 16; i++ { cur[i] = cur[i] ^ keyexpanded[iteration][i] } return cur } func assignKey(cur Block) { key = cur } func keyExpansionBase(keysize int) { if keysize == 128 { keyexpanded = append(keyexpanded, key) for i := 0; i < 10; i++ { keyExpansion(keyexpanded[i], i+1) } } else if keysize == 192 { keyexpanded = append(keyexpanded, key) for i := 0; i < 8; i++ { keyExpansion192(keyexpanded[i], i+1) } temp := keyexpanded keyexpanded = []Block{} for i := 0; i < 9; i++ { if i == 8 { a := Block{ temp[i][0], temp[i][1], temp[i][2], temp[i][3], temp[i][6], temp[i][7], temp[i][8], temp[i][9], temp[i][12], temp[i][13], temp[i][14], temp[i][15], temp[i][18], temp[i][19], temp[i][20], temp[i][21], } b := Block{ temp[i][4], temp[i][5], 0, 0, temp[i][10], temp[i][11], 0, 0, temp[i][16], temp[i][17], 0, 0, temp[i][22], temp[i][23], 0, 0, } keyexpanded = append(keyexpanded, a) keyexpanded = append(keyexpanded, b) } else { a := Block{ temp[i][0], temp[i][1], temp[i][2], temp[i][3], temp[i][6], temp[i][7], temp[i][8], temp[i][9], temp[i][12], temp[i][13], temp[i][14], temp[i][15], temp[i][18], temp[i][19], temp[i][20], temp[i][21], } b := Block{ temp[i][4], temp[i][5], temp[i+1][0], temp[i+1][1], temp[i][10], temp[i][11], temp[i+1][6], temp[i+1][7], temp[i][16], temp[i][17], temp[i+1][12], temp[i+1][13], temp[i][22], temp[i][23], temp[i+1][18], temp[i+1][19], } c := Block{ temp[i+1][2], temp[i+1][3], temp[i+1][4], temp[i+1][5], temp[i+1][8], temp[i+1][9], temp[i+1][10], temp[i+1][11], temp[i+1][14], temp[i+1][15], temp[i+1][16], temp[i+1][17], temp[i+1][20], temp[i+1][21], temp[i+1][22], temp[i+1][23], } keyexpanded = append(keyexpanded, a) keyexpanded = append(keyexpanded, b) keyexpanded = append(keyexpanded, c) } i++ } } else if keysize == 256 { keyexpanded = append(keyexpanded, key) for i := 0; i < 8; i++ { keyExpansion256(keyexpanded[i], i+1) } temp := keyexpanded keyexpanded = []Block{} for i := 0; i < 9; i++ { a := Block{ temp[i][0], temp[i][1], temp[i][2], temp[i][3], temp[i][8], temp[i][9], temp[i][10], temp[i][11], temp[i][16], temp[i][17], temp[i][18], temp[i][19], temp[i][24], temp[i][25], temp[i][26], temp[i][27], } b := Block{ temp[i][4], temp[i][5], temp[i][6], temp[i][7], temp[i][12], temp[i][13], temp[i][14], temp[i][15], temp[i][20], temp[i][21], temp[i][22], temp[i][23], temp[i][28], temp[i][29], temp[i][30], temp[i][31], } keyexpanded = append(keyexpanded, a) keyexpanded = append(keyexpanded, b) } } } func keyExpansion(cur Block, iteration int) Block { var nb = Block{ //nb = nextBlock 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, } rotword := []byte{cur[7], cur[11], cur[15], cur[3]} for i := 0; i < 4; i++ { upper, lower := splitBytes(rotword[i]) rotword[i] = sbox[upper][lower] } rotword[0] = rotword[0] ^ cur[0] ^ rcon[iteration] rotword[1] = rotword[1] ^ cur[4] rotword[2] = rotword[2] ^ cur[8] rotword[3] = rotword[3] ^ cur[12] nb[0], nb[4], nb[8], nb[12] = rotword[0], rotword[1], rotword[2], rotword[3] nb[1], nb[5], nb[9], nb[13] = nb[0]^cur[1], nb[4]^cur[5], nb[8]^cur[9], nb[12]^cur[13] nb[2], nb[6], nb[10], nb[14] = nb[1]^cur[2], nb[5]^cur[6], nb[9]^cur[10], nb[13]^cur[14] nb[3], nb[7], nb[11], nb[15] = nb[2]^cur[3], nb[6]^cur[7], nb[10]^cur[11], nb[14]^cur[15] keyexpanded = append(keyexpanded, nb) return nb } func keyExpansion192(cur Block, iteration int) Block { var nb = Block{ //nb = nextBlock 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, } rotword := []byte{cur[11], cur[17], cur[23], cur[5]} for i := 0; i < 4; i++ { upper, lower := splitBytes(rotword[i]) rotword[i] = sbox[upper][lower] } rotword[0] = rotword[0] ^ cur[0] ^ rcon[iteration] rotword[1] = rotword[1] ^ cur[6] rotword[2] = rotword[2] ^ cur[12] rotword[3] = rotword[3] ^ cur[18] nb[0], nb[6], nb[12], nb[18] = rotword[0], rotword[1], rotword[2], rotword[3] nb[1], nb[7], nb[13], nb[19] = nb[0]^cur[1], nb[6]^cur[7], nb[12]^cur[13], nb[18]^cur[19] nb[2], nb[8], nb[14], nb[20] = nb[1]^cur[2], nb[7]^cur[8], nb[13]^cur[14], nb[19]^cur[20] nb[3], nb[9], nb[15], nb[21] = nb[2]^cur[3], nb[8]^cur[9], nb[14]^cur[15], nb[20]^cur[21] nb[4], nb[10], nb[16], nb[22] = nb[3]^cur[4], nb[9]^cur[10], nb[15]^cur[16], nb[21]^cur[22] nb[5], nb[11], nb[17], nb[23] = nb[4]^cur[5], nb[10]^cur[11], nb[16]^cur[17], nb[22]^cur[23] keyexpanded = append(keyexpanded, nb) return nb } func keyExpansion256(cur Block, iteration int) Block { var nb = Block{ //nb = nextBlock 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, } rotword := []byte{cur[15], cur[23], cur[31], cur[7]} for i := 0; i < 4; i++ { upper, lower := splitBytes(rotword[i]) rotword[i] = sbox[upper][lower] } rotword[0] = rotword[0] ^ cur[0] ^ rcon[iteration] rotword[1] = rotword[1] ^ cur[8] rotword[2] = rotword[2] ^ cur[16] rotword[3] = rotword[3] ^ cur[24] nb[0], nb[8], nb[16], nb[24] = rotword[0], rotword[1], rotword[2], rotword[3] nb[1], nb[9], nb[17], nb[25] = nb[0]^cur[1], nb[8]^cur[9], nb[16]^cur[17], nb[24]^cur[25] nb[2], nb[10], nb[18], nb[26] = nb[1]^cur[2], nb[9]^cur[10], nb[17]^cur[18], nb[25]^cur[26] nb[3], nb[11], nb[19], nb[27] = nb[2]^cur[3], nb[10]^cur[11], nb[18]^cur[19], nb[26]^cur[27] sw := []byte{nb[3], nb[11], nb[19], nb[27]} //sw = subword for i := 0; i < 4; i++ { upper, lower := splitBytes(sw[i]) sw[i] = sbox[upper][lower] } nb[4], nb[12], nb[20], nb[28] = sw[0]^cur[4], sw[1]^cur[12], sw[2]^cur[20], sw[3]^cur[28] nb[5], nb[13], nb[21], nb[29] = nb[4]^cur[5], nb[12]^cur[13], nb[20]^cur[21], nb[28]^cur[29] nb[6], nb[14], nb[22], nb[30] = nb[5]^cur[6], nb[13]^cur[14], nb[21]^cur[22], nb[29]^cur[30] nb[7], nb[15], nb[23], nb[31] = nb[6]^cur[7], nb[14]^cur[15], nb[22]^cur[23], nb[30]^cur[31] keyexpanded = append(keyexpanded, nb) return nb } func splitBytes(b byte) (byte, byte) { return b >> 4, b & 0x0f } func subBytes(cur Block) Block { for i := 0; i < 16; i++ { upper, lower := splitBytes(cur[i]) cur[i] = sbox[upper][lower] } return cur } func invSubBytes(cur Block) Block { for i := 0; i < 16; i++ { upper, lower := splitBytes(cur[i]) cur[i] = invSbox[upper][lower] } return cur } func xtime(cur byte) []byte { var bytes []byte bytes = append(bytes, cur) for i := 1; i < 8; i++ { // first iteration done outside of for-loop if (cur >> 7) == 1 { cur = cur << 1 cur = cur ^ 0x1b } else { cur = cur << 1 } bytes = append(bytes, cur) } return bytes } func ffmult(cur []byte, multiplier byte) byte { if multiplier == 1 { return cur[0] } else if multiplier == 2 { return cur[1] } else if multiplier == 3 { return cur[0] ^ cur[1] } else if multiplier == 9 { return cur[0] ^ cur[3] } else if multiplier == 11 { return cur[0] ^ cur[1] ^ cur[3] } else if multiplier == 13 { return cur[0] ^ cur[2] ^ cur[3] } else if multiplier == 14 { return cur[1] ^ cur[2] ^ cur[3] } return 0 } func mixColumnsAssist(cur []byte) []byte { a1 := ffmult(xtime(cur[0]), mm[0]) ^ ffmult(xtime(cur[1]), mm[1]) ^ ffmult(xtime(cur[2]), mm[2]) ^ ffmult(xtime(cur[3]), mm[3]) a2 := ffmult(xtime(cur[0]), mm[4]) ^ ffmult(xtime(cur[1]), mm[5]) ^ ffmult(xtime(cur[2]), mm[6]) ^ ffmult(xtime(cur[3]), mm[7]) a3 := ffmult(xtime(cur[0]), mm[8]) ^ ffmult(xtime(cur[1]), mm[9]) ^ ffmult(xtime(cur[2]), mm[10]) ^ ffmult(xtime(cur[3]), mm[11]) a4 := ffmult(xtime(cur[0]), mm[12]) ^ ffmult(xtime(cur[1]), mm[13]) ^ ffmult(xtime(cur[2]), mm[14]) ^ ffmult(xtime(cur[3]), mm[15]) return []byte{a1, a2, a3, a4} } func mixColumns(cur Block) Block { col1 := []byte{cur[0], cur[4], cur[8], cur[12]} col2 := []byte{cur[1], cur[5], cur[9], cur[13]} col3 := []byte{cur[2], cur[6], cur[10], cur[14]} col4 := []byte{cur[3], cur[7], cur[11], cur[15]} col1 = mixColumnsAssist(col1) col2 = mixColumnsAssist(col2) col3 = mixColumnsAssist(col3) col4 = mixColumnsAssist(col4) cur = Block{ col1[0], col2[0], col3[0], col4[0], col1[1], col2[1], col3[1], col4[1], col1[2], col2[2], col3[2], col4[2], col1[3], col2[3], col3[3], col4[3], } return cur } func invMixColumns(cur Block) Block { col1 := []byte{cur[0], cur[4], cur[8], cur[12]} col2 := []byte{cur[1], cur[5], cur[9], cur[13]} col3 := []byte{cur[2], cur[6], cur[10], cur[14]} col4 := []byte{cur[3], cur[7], cur[11], cur[15]} col1 = invMixColumnsAssist(col1) col2 = invMixColumnsAssist(col2) col3 = invMixColumnsAssist(col3) col4 = invMixColumnsAssist(col4) cur = Block{ col1[0], col2[0], col3[0], col4[0], col1[1], col2[1], col3[1], col4[1], col1[2], col2[2], col3[2], col4[2], col1[3], col2[3], col3[3], col4[3], } return cur } func invMixColumnsAssist(cur []byte) []byte { a1 := ffmult(xtime(cur[0]), iMM[0]) ^ ffmult(xtime(cur[1]), iMM[1]) ^ ffmult(xtime(cur[2]), iMM[2]) ^ ffmult(xtime(cur[3]), iMM[3]) a2 := ffmult(xtime(cur[0]), iMM[4]) ^ ffmult(xtime(cur[1]), iMM[5]) ^ ffmult(xtime(cur[2]), iMM[6]) ^ ffmult(xtime(cur[3]), iMM[7]) a3 := ffmult(xtime(cur[0]), iMM[8]) ^ ffmult(xtime(cur[1]), iMM[9]) ^ ffmult(xtime(cur[2]), iMM[10]) ^ ffmult(xtime(cur[3]), iMM[11]) a4 := ffmult(xtime(cur[0]), iMM[12]) ^ ffmult(xtime(cur[1]), iMM[13]) ^ ffmult(xtime(cur[2]), iMM[14]) ^ ffmult(xtime(cur[3]), iMM[15]) return []byte{a1, a2, a3, a4} } func shiftRows(cur Block) Block { cur[4], cur[5], cur[6], cur[7] = cur[5], cur[6], cur[7], cur[4] cur[8], cur[9], cur[10], cur[11] = cur[10], cur[11], cur[8], cur[9] cur[12], cur[13], cur[14], cur[15] = cur[15], cur[12], cur[13], cur[14] return cur } func invShiftRows(cur Block) Block { cur[4], cur[5], cur[6], cur[7] = cur[7], cur[4], cur[5], cur[6] cur[8], cur[9], cur[10], cur[11] = cur[10], cur[11], cur[8], cur[9] cur[12], cur[13], cur[14], cur[15] = cur[13], cur[14], cur[15], cur[12] return cur }