Browse Source

added cs465 aes lab with added CLI interface

Just added a simple CLI to allow users to leverage the aes library.
Obviously, this was just a project to learn more about AES, not
something to be used in production systems
master
Derek McQuay 3 years ago
parent
commit
f5ffe7eb31
3 changed files with 1009 additions and 0 deletions
  1. +555
    -0
      cs465/aes/aes.go
  2. +356
    -0
      cs465/aes/aes_test.go
  3. +98
    -0
      cs465/main.go

+ 555
- 0
cs465/aes/aes.go View File

@@ -0,0 +1,555 @@
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
}

+ 356
- 0
cs465/aes/aes_test.go View File

@@ -0,0 +1,356 @@
package aes

import (
"bytes"
"testing"
)

func TestShiftRows(t *testing.T) {
input := Block{
0, 1, 2, 3,
4, 5, 6, 7,
8, 9, 10, 11,
12, 13, 14, 15,
}
expected := Block{
0, 1, 2, 3,
5, 6, 7, 4,
10, 11, 8, 9,
15, 12, 13, 14,
}
actual := shiftRows(input)
if !bytes.Equal(expected, actual) {
t.Errorf(
"failed to get right ShiftRows:\n\texpected: % x\n\t actual: % x",
expected,
actual,
)

}
}

func TestSubBytes(t *testing.T) {
input := Block{
0x19, 0xa0, 0x9a, 0xe9,
0x3d, 0xf4, 0xc6, 0xf8,
0xe3, 0xe2, 0x8d, 0x48,
0xbe, 0x2b, 0x2a, 0x08,
}
expected := Block{
0xd4, 0xe0, 0xb8, 0x1e,
0x27, 0xbf, 0xb4, 0x41,
0x11, 0x98, 0x5d, 0x52,
0xae, 0xf1, 0xe5, 0x30,
}
actual := subBytes(input)
if !bytes.Equal(expected, actual) {
t.Errorf(
"failed to get right ShiftRows:\n\texpected: % x\n\t actual: % x",
expected,
actual,
)
}
}

func TestSplitBytes(t *testing.T) {
input := byte(0xab)
expected1 := byte(0xa)
expected2 := byte(0xb)
actual1, actual2 := splitBytes(input)
if expected1 != actual1 || expected2 != actual2 {
t.Errorf(
"failed to get SplitBytes:\n\texpected: 0x%x 0x%x\n\t actual: 0x%x 0x%x",
expected1,
expected2,
actual1,
actual2,
)
}
}

func TestXtime(t *testing.T) {
input := byte(0x14)
expected := []byte{
0x14, 0x28, 0x50, 0xa0,
0x5b, 0xb6, 0x77, 0xee,
}
actual := xtime(input)
if !bytes.Equal(expected, actual) {
t.Errorf(
"failed to get Xtime:\n\texpected: % x\n\tactual: % x",
expected,
actual,
)
}
}

func TestFFmult(t *testing.T) {
input := xtime(0x14)
expected1 := byte(0x14)
expected2 := byte(0x28)
expected3 := byte(0x3c)
actual1 := ffmult(input, 1)
actual2 := ffmult(input, 2)
actual3 := ffmult(input, 3)
if expected1 != actual1 || expected2 != actual2 || expected3 != actual3 {
t.Errorf(
"failed to get FFmult:\n\texpected: 0x% x 0x% x 0x% x\n\t actual:0x% x 0x% x 0x% x",
expected1,
expected2,
expected3,
actual1,
actual2,
actual3,
)
}
}

func TestMixColumns(t *testing.T) {
input := Block{
0xdb, 0xf2, 0x2d, 0x01,
0x13, 0x0a, 0x26, 0x01,
0x53, 0x22, 0x31, 0x01,
0x45, 0x5c, 0x4c, 0x01,
}
expected := Block{
0x8e, 0x9f, 0x4d, 0x01,
0x4d, 0xdc, 0x7e, 0x01,
0xa1, 0x58, 0xbd, 0x01,
0xbc, 0x9d, 0xf8, 0x01,
}
actual := mixColumns(input)
for i := 0; i < 16; i++ {
if actual[i] != expected[i] {
t.Errorf(
"failed to get MixColumn:\n\texpected: %v \n\tactual: %v", expected, actual,
)
}
}
}

func TestCipher(t *testing.T) {
key := Block{
0x2b, 0x28, 0xab, 0x09,
0x7e, 0xae, 0xf7, 0xcf,
0x15, 0xd2, 0x15, 0x4f,
0x16, 0xa6, 0x88, 0x3c,
}
input := Block{
0x32, 0x88, 0x31, 0xe0,
0x43, 0x5a, 0x31, 0x37,
0xf6, 0x30, 0x98, 0x07,
0xa8, 0x8d, 0xa2, 0x34,
}
expected := Block{
0x39, 0x02, 0xdc, 0x19,
0x25, 0xdc, 0x11, 0x6a,
0x84, 0x09, 0x85, 0x0b,
0x1d, 0xfb, 0x97, 0x32,
}
actual := Cipher(input, 128, key)
for i := 0; i < 16; i++ {
if actual[i] != expected[i] {
t.Errorf(
"failed to get Cipher:\n\texpected: %v\n\tactual: %v", expected, actual,
)
}
}

//Test case for 128 from FIPS

key = Block{
0x00, 0x04, 0x08, 0x0c,
0x01, 0x05, 0x09, 0x0d,
0x02, 0x06, 0x0a, 0x0e,
0x03, 0x07, 0x0b, 0x0f,
}
input = Block{
0x00, 0x44, 0x88, 0xcc,
0x11, 0x55, 0x99, 0xdd,
0x22, 0x66, 0xaa, 0xee,
0x33, 0x77, 0xbb, 0xff,
}
expected = Block{
0x69, 0x6a, 0xd8, 0x70,
0xc4, 0x7b, 0xcd, 0xb4,
0xe0, 0x04, 0xb7, 0xc5,
0xd8, 0x30, 0x80, 0x5a,
}
actual = Cipher(input, 128, key)
for i := 0; i < 16; i++ {
if actual[i] != expected[i] {
t.Errorf(
"failed to get Cipher:\n\texpected: %v\n\tactual: %v", expected, actual,
)
}
}

//Test case for 192 from FIPS
key = Block{
0x00, 0x04, 0x08, 0x0c, 0x10, 0x14,
0x01, 0x05, 0x09, 0x0d, 0x11, 0x15,
0x02, 0x06, 0x0a, 0x0e, 0x12, 0x16,
0x03, 0x07, 0x0b, 0x0f, 0x13, 0x17,
}
input = Block{
0x00, 0x44, 0x88, 0xcc,
0x11, 0x55, 0x99, 0xdd,
0x22, 0x66, 0xaa, 0xee,
0x33, 0x77, 0xbb, 0xff,
}
expected = Block{
0xdd, 0x86, 0x6e, 0xec,
0xa9, 0x4c, 0xaf, 0x0d,
0x7c, 0xdf, 0x70, 0x71,
0xa4, 0xe0, 0xa0, 0x91,
}
actual = Cipher(input, 192, key)
for i := 0; i < 16; i++ {
if actual[i] != expected[i] {
t.Errorf(
"failed to get Cipher:\n\texpected: %v\n\tactual: %v", expected, actual,
)
}
}

//Test case for 256 from FIPS
key = Block{
0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
0x01, 0x05, 0x09, 0x0d, 0x11, 0x15, 0x19, 0x1d,
0x02, 0x06, 0x0a, 0x0e, 0x12, 0x16, 0x1a, 0x1e,
0x03, 0x07, 0x0b, 0x0f, 0x13, 0x17, 0x1b, 0x1f,
}
input = Block{
0x00, 0x44, 0x88, 0xcc,
0x11, 0x55, 0x99, 0xdd,
0x22, 0x66, 0xaa, 0xee,
0x33, 0x77, 0xbb, 0xff,
}
expected = Block{
0x8e, 0x51, 0xea, 0x4b,
0xa2, 0x67, 0xfc, 0x49,
0xb7, 0x45, 0x49, 0x60,
0xca, 0xbf, 0x90, 0x89,
}
actual = Cipher(input, 256, key)
for i := 0; i < 16; i++ {
if actual[i] != expected[i] {
t.Errorf(
"failed to get Cipher:\n\texpected: %v\n\tactual: %v", expected, actual,
)
}
}
}

func TestInvCipher(t *testing.T) {
key := Block{
0x2b, 0x28, 0xab, 0x09,
0x7e, 0xae, 0xf7, 0xcf,
0x15, 0xd2, 0x15, 0x4f,
0x16, 0xa6, 0x88, 0x3c,
}
input := Block{
0x39, 0x02, 0xdc, 0x19,
0x25, 0xdc, 0x11, 0x6a,
0x84, 0x09, 0x85, 0x0b,
0x1d, 0xfb, 0x97, 0x32,
}
expected := Block{
0x32, 0x88, 0x31, 0xe0,
0x43, 0x5a, 0x31, 0x37,
0xf6, 0x30, 0x98, 0x07,
0xa8, 0x8d, 0xa2, 0x34,
}
actual := InvCipher(input, 128, key)
for i := 0; i < 16; i++ {
if actual[i] != expected[i] {
t.Errorf(
"failed to get Cipher:\n\texpected: %v\n\tactual: %v", expected, actual,
)
}
}

//Test case for 128 from FIPS
key = Block{
0x00, 0x04, 0x08, 0x0c,
0x01, 0x05, 0x09, 0x0d,
0x02, 0x06, 0x0a, 0x0e,
0x03, 0x07, 0x0b, 0x0f,
}
input = Block{
0x69, 0x6a, 0xd8, 0x70,
0xc4, 0x7b, 0xcd, 0xb4,
0xe0, 0x04, 0xb7, 0xc5,
0xd8, 0x30, 0x80, 0x5a,
}
expected = Block{
0x00, 0x44, 0x88, 0xcc,
0x11, 0x55, 0x99, 0xdd,
0x22, 0x66, 0xaa, 0xee,
0x33, 0x77, 0xbb, 0xff,
}
actual = InvCipher(input, 128, key)
for i := 0; i < 16; i++ {
if actual[i] != expected[i] {
t.Errorf(
"failed to get Cipher:\n\texpected: %v\n\tactual: %v", expected, actual,
)
}
}

//Test case for 192 from FIPS
key = Block{
0x00, 0x04, 0x08, 0x0c, 0x10, 0x14,
0x01, 0x05, 0x09, 0x0d, 0x11, 0x15,
0x02, 0x06, 0x0a, 0x0e, 0x12, 0x16,
0x03, 0x07, 0x0b, 0x0f, 0x13, 0x17,
}
input = Block{
0xdd, 0x86, 0x6e, 0xec,
0xa9, 0x4c, 0xaf, 0x0d,
0x7c, 0xdf, 0x70, 0x71,
0xa4, 0xe0, 0xa0, 0x91,
}
expected = Block{
0x00, 0x44, 0x88, 0xcc,
0x11, 0x55, 0x99, 0xdd,
0x22, 0x66, 0xaa, 0xee,
0x33, 0x77, 0xbb, 0xff,
}
actual = InvCipher(input, 192, key)
for i := 0; i < 16; i++ {
if actual[i] != expected[i] {
t.Errorf(
"failed to get Cipher:\n\texpected: %v \n\tactual:%v", expected, actual,
)
}
}

//Test case for 256 from FIPS
key = Block{
0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
0x01, 0x05, 0x09, 0x0d, 0x11, 0x15, 0x19, 0x1d,
0x02, 0x06, 0x0a, 0x0e, 0x12, 0x16, 0x1a, 0x1e,
0x03, 0x07, 0x0b, 0x0f, 0x13, 0x17, 0x1b, 0x1f,
}
input = Block{
0x8e, 0x51, 0xea, 0x4b,
0xa2, 0x67, 0xfc, 0x49,
0xb7, 0x45, 0x49, 0x60,
0xca, 0xbf, 0x90, 0x89,
}
expected = Block{
0x00, 0x44, 0x88, 0xcc,
0x11, 0x55, 0x99, 0xdd,
0x22, 0x66, 0xaa, 0xee,
0x33, 0x77, 0xbb, 0xff,
}
actual = InvCipher(input, 256, key)
for i := 0; i < 16; i++ {
if actual[i] != expected[i] {
t.Errorf(
"failed to get Cipher:\n\texpected: %v\n\tactual: %v", expected, actual,
)
}
}
}

+ 98
- 0
cs465/main.go View File

@@ -0,0 +1,98 @@
package main

import (
"fmt"
"log"
"os"

"s.mcquay.me/dm/school/cs465/aes"

"github.com/spf13/cobra"
)

var key128 = aes.Block{
0x2b, 0x28, 0xab, 0x09,
0x7e, 0xae, 0xf7, 0xcf,
0x15, 0xd2, 0x15, 0x4f,
0x16, 0xa6, 0x88, 0x3c,
}
var key192 = aes.Block{
0x00, 0x04, 0x08, 0x0c, 0x10, 0x14,
0x01, 0x05, 0x09, 0x0d, 0x11, 0x15,
0x02, 0x06, 0x0a, 0x0e, 0x12, 0x16,
0x03, 0x07, 0x0b, 0x0f, 0x13, 0x17,
}
var key256 = aes.Block{
0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
0x01, 0x05, 0x09, 0x0d, 0x11, 0x15, 0x19, 0x1d,
0x02, 0x06, 0x0a, 0x0e, 0x12, 0x16, 0x1a, 0x1e,
0x03, 0x07, 0x0b, 0x0f, 0x13, 0x17, 0x1b, 0x1f,
}

func main() {
var keysize int
var decrypt bool
var ascii bool

var aes = &cobra.Command{
Use: "aes",
Short: "aes cipher",
Long: `perform aes cipher`,
Run: func(cmd *cobra.Command, args []string) {
if len(args) < 1 {
fmt.Println("missing input, see -h (--help) for more info")
os.Exit(1)
}
for _, arg := range args {
all := aes.BlockGen(arg)
if ascii {
switch keysize {
case 128:
fmt.Println(aes.ToString(all, 128, key128, decrypt))
case 192:
fmt.Println(aes.ToString(all, 192, key192, decrypt))
case 256:
fmt.Println(aes.ToString(all, 256, key256, decrypt))
default:
log.Fatal("keysize not valid")
}
} else {
switch keysize {
case 128:
fmt.Println(aes.ToHex(all, 128, key128, decrypt))
case 192:
fmt.Println(aes.ToHex(all, 192, key192, decrypt))
case 256:
fmt.Println(aes.ToHex(all, 256, key256, decrypt))
default:
log.Fatal("keysize not valid")
}
}
}
},
}
aes.Flags().IntVarP(
&keysize,
"keysize",
"k",
0,
"keysize",
)
aes.Flags().BoolVarP(
&ascii,
"ascii",
"a",
false,
"display in ascii (may mess up terminal :) )",
)
aes.Flags().BoolVarP(
&decrypt,
"decrypt",
"d",
false,
"decrypt",
)
var rootCmd = &cobra.Command{Use: "app"}
rootCmd.AddCommand(aes)
rootCmd.Execute()
}

Loading…
Cancel
Save