Skip to content

Commit

Permalink
first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
kitaniman committed Jun 23, 2023
0 parents commit 39a076a
Show file tree
Hide file tree
Showing 8 changed files with 170 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
**/.vscode
**/__pycache__
**/.DS_Store
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Advanced Encryption Standard (AES)

This repository provides a simple implementation of AES using python and numpy. This implementation is as explained in the textbook [Understanding Cryptography](https://doi.org/10.1007/978-3-642-04101-3) by Christof Paar & Jan Pelzl. It should be noted that this implementation was created for learning purposes. For security usage, well-established packages should be used.

## Examples

```Python
print('hello world')
```
23 changes: 23 additions & 0 deletions aes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import numpy as np
from numpy.typing import NDArray


from key_schedule import key_schedule
from byte_substitution import s
from shift_rows import shift_rows
from mix_column import mix_column


def aes_128(x: NDArray[np.unit8], k: NDArray[np.unit8]):
key_generator = key_schedule(k)
state = x
state ^= next(key_generator)

# TODO: remove mix_column form the last step
for key in key_generator:
state = s(state)
state = shift_rows(state)
state = mix_column(state)
state ^= key

return state
9 changes: 9 additions & 0 deletions byte_substitution.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import numpy as np
from numpy.typing import NDArray


from s_box import s_box


def s(a: NDArray[np.uint8]):
return np.array([s_box[ai] for ai in a])
43 changes: 43 additions & 0 deletions key_schedule.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import numpy as np
from numpy.typing import NDArray

from s_box import s_box


RC = (
0b0000_0001,
0b0000_0010,
0b0000_0100,
0b0000_1000,
0b0001_0000,
0b0010_0000,
0b0100_0000,
0b1000_0000,
0b0001_1011,
0b0011_0110,
)


def g(v: NDArray[np.uint8], i: int):
rotated = np.roll(v, -1)

substituted = np.array([
s_box[xi]
for xi in rotated
])

substituted[0] ^= RC[i]

return substituted


def key_schedule(k: NDArray[np.uint8]):
w = np.split(k, 4)
yield np.concatenate(w)

for i in range(10):
w[0] ^= g(w[-1], i)
w[1] ^= w[0]
w[2] ^= w[1]
w[3] ^= w[2]
yield np.concatenate(w)
51 changes: 51 additions & 0 deletions mix_column.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import numpy as np
from numpy.typing import NDArray


constant_matrix = np.array([
[0x02, 0x03, 0x01, 0x01],
[0x01, 0x02, 0x03, 0x01],
[0x01, 0x01, 0x02, 0x03],
[0x03, 0x01, 0x01, 0x02],
])


def gf_multiply(x, y):
r = 0

for _ in range(8):
if y & 1:
r ^= x

hi_bit_set = x & 0x80
x <<= 1

if hi_bit_set:
x ^= 0x11b

y >>= 1

return r & 0xFF


def finite_field_256_dot(v: NDArray[np.uint8], u: NDArray[np.uint8]):
result = 0

for vi, ui in zip(v, u):
if ui == 0x01:
result ^= vi
else:
result ^= gf_multiply(vi, ui)

return result


def mix_column(b: NDArray[np.uint8]):
reshaped = b.reshape((4, 4))

result = np.array([
finite_field_256_dot(reshaped[:, i], constant_matrix[i])
for i in range(4)
])

return result.reshape((16,))
21 changes: 21 additions & 0 deletions s_box.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import numpy as np


s_box = np.array([
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
], np.uint8)
11 changes: 11 additions & 0 deletions shift_rows.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import numpy as np
from numpy.typing import NDArray


def shift_rows(b: NDArray[np.uint8]):
shifted = b.reshape((4, 4))

for i in range(4):
shifted[i] = np.roll(shifted, -i)

return shifted.reshape((16,))

0 comments on commit 39a076a

Please sign in to comment.