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
This commit is contained in:
Derek McQuay 2016-04-10 09:53:32 -07:00
parent 110f83b420
commit f5ffe7eb31
3 changed files with 1009 additions and 0 deletions

555
cs465/aes/aes.go Normal file
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
cs465/aes/aes_test.go Normal file
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
cs465/main.go Normal file
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()
}