Dr. Greg Bernstein
February 19th, 2021
From Wikipedia: AES
The Advanced Encryption Standard (AES), also known by its original name Rijndael, is a specification for the encryption of electronic data established by the U.S. National Institute of Standards and Technology (NIST) in 2001.
In the United States, AES was announced by the NIST as U.S. FIPS PUB 197 (FIPS 197) on November 26, 2001. This announcement followed a five-year standardization process in which fifteen competing designs were presented and evaluated, before the Rijndael cipher was selected as the most suitable.
AES is an open standard. The details of its operation has been public for over 20 years.
" is the first (and only) publicly accessible cipher approved by the U.S. National Security Agency (NSA) for top secret information when used in an NSA approved cryptographic module."
AES is very efficient (fast, easy to implement in hardware and software)
Encryption: \(E_K(P) := E(K,P): \{0,1\}^k \times \{0,1\}^n \rightarrow \{0,1\}^n\)
Where \(K\) is the key of length \(k\) bits, \(P\) is the plaintext of length \(n\) bits
Decryption: \(E_K^{-1}(C) := D_K(C) = D(K,C): \{0,1\}^k \times \{0,1\}^n \rightarrow \{0,1\}^n\)
AES is a block cipher it works on blocks of 128 bits (16 bytes) and uses key sizes of 128 bits (16 bytes), 192 bits (24 bytes), or 256 bits (32 bytes)
From Wikipedia: AES: “AES is based on a design principle known as a substitution–permutation network, and is efficient in both software and hardware.”
From Wikipedia
Block Ciphers are used via certain block cipher modes of operation which must be carefully used to get the full protection of the algorithm.
The length of the key is vital to the security of the algorithm, you should never directly use “text” as a key to a block cipher.
AES is well known with published examples
from cryptography.hazmat.primitives.ciphers import (Cipher, algorithms, modes)
plaintext = bytes.fromhex("00112233445566778899aabbccddeeff")
key = bytes.fromhex("000102030405060708090a0b0c0d0e0f")
encryptor = Cipher(algorithms.AES(key), modes.ECB()).encryptor()
ciphertext = encryptor.update(plaintext)
print(ciphertext.hex())
# Expected output: 69c4e0d86a7b0430d8cdb78070b4c55a
decryptor = Cipher(algorithms.AES(key), modes.ECB()).decryptor()
dtext = decryptor.update(ciphertext)
print(dtext.hex())
plaintext = bytes.fromhex("00112233445566778899aabbccddeeff")
key = bytes.fromhex("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f")
encryptor = Cipher(algorithms.AES(key), modes.ECB()).encryptor()
ciphertext = encryptor.update(plaintext)
print(ciphertext.hex())
# Expected output: 8ea2b7ca516745bfeafc49904b496089
Will use matplotlib and numpy to get an image
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import numpy as np
img = mpimg.imread('test.jpg')
plt.figure()
plt.imshow(img)
Screen shot of the Image tutorial page
print(f"The image size in bytes: {img.size}")
print(f"The number of dimensions in the image array: {img.ndim}")
print(f"The size of each image dimension: {img.shape}")
print(f"The type of data in the image arra: {img.dtype}")
Not to be used for security!!!
def jpgEncrypt(npimg, encrypt=True):
shape = npimg.shape
# Chop off rows and columns to be a multiple of 4
nshape = ((shape[0]//4)*4, (shape[1]//4)*4, shape[2])
cimg = np.ndarray(nshape, np.uint8)
# Encrypt by block
for i in range(0, nshape[0]//4):
for j in range(0, nshape[1]//4):
for k in range(0, 3):
mybytes = npimg[4*i:4*(i + 1), 4*j:4*(j+1), k].tobytes()
if encrypt:
cbytes = encryptor.update(mybytes)
else:
cbytes = decryptor.update(mybytes)
deserialized_bytes = np.frombuffer(cbytes, dtype=np.uint8)
cimg[4*i:4*(i + 1), 4*j:4*(j+1), k] = np.reshape(deserialized_bytes, newshape=(4, 4))
return cimg
This is suitable for “top secret” information?
The image (uncompressed) has lots of 128 bit blocks with the same information, i.e., groups of identical 4x4 pixels, the block encryption algorithm processes these into exactly the same new blocks of information!
I guess we can’t use AES?
From Block cipher mode of operation
A block cipher by itself is only suitable for the secure cryptographic transformation (encryption or decryption) of one fixed-length group of bits called a block. A mode of operation describes how to repeatedly apply a cipher’s single-block operation to securely transform amounts of data larger than a block.
Just a sample, there are more…
Mode | Encrypt Parallel | Decrypt Parallel | Random Read | Stream |
---|---|---|---|---|
ECB | Yes | Yes | Yes | No |
CBC | No | Yes | Yes | No |
CFB | No | Yes | Yes | Yes |
OFB | No | No | No | Yes |
CTR | Yes | Yes | Yes | Yes |
From Wikipedia: Block cipher mode of operation
From Wikipedia: Block cipher mode of operation
The disadvantage of this method is a lack of diffusion. Because ECB encrypts identical plaintext blocks into identical ciphertext blocks, it does not hide data patterns well. ECB is not recommended for use in cryptographic protocols
From Wikipedia: Block cipher mode of operation
From Wikipedia: Block cipher mode of operation
An initialization vector (IV) is a block of bits that is used by several modes to randomize the encryption and hence to produce distinct ciphertexts even if the same plaintext is encrypted multiple times.
An initialization vector has different security requirements than a key, so the IV usually does not need to be secret. For most block cipher modes it is important that an initialization vector is never reused under the same key, i.e. it must be a cryptographic nonce. Many block cipher modes have stronger requirements, such as the IV must be random or pseudorandom.
# Set up encryptor and decryptor
key = bytes.fromhex("000102030405060708090a0b0c0d0e0f")
# Need to set the initialization vetor
iv = bytes.fromhex("e0e1e2f3f4a5a6a7b8b90a0b0c0d0e0f")
encryptor = Cipher(algorithms.AES(key), modes.CBC(iv)).encryptor()
decryptor = Cipher(algorithms.AES(key), modes.CBC(iv)).decryptor()
When I use AES with CBC to encrypt my screen shot I get:
From Wikipedia: Block cipher mode of operation
The nonce is like an initialization vector