A

#### ALEXBEET 22

##### Guest

Block Size: Input/Output Block Size: 128 bits (16 bytes)

Key Generation: Initial Key: A 128-bit key is used to generate 16 round keys. Round Key Generation: The initial key is processed through a key expansion algorithm to produce 16 round keys. Each round key is derived by applying a fixed transformation to the previous round key.

Encryption Process:

Initial State: The plaintext is divided into two halves (L0, R0) of 64 bits each. Rounds: The encryption process consists of 16 rounds. In each round: Round Key Application: The round key is XORed with the right half (R). Feistel Function: A Feistel function is applied to the result, involving substitution and permutation. Swap: The left and right halves are swapped for the next round. Final State: After 16 rounds, the final output is obtained by concatenating the left and right halves.

I’m encountering issues where the decrypted output does not match the original plaintext. Despite following the algorithm and applying the round keys correctly, the decrypted text is incorrect or empty.

What I've Tried: -Verified key generation and round key application. -Checked the implementation of the substitution, permutation, and other operations. -Debugged step-by-step to ensure each operation is applied correctly.

Thank you

Code:

```
def pad(plaintext, block_size):
padding_length = block_size - (len(plaintext) % block_size)
padding = bytes([padding_length] * padding_length)
return plaintext + padding
def unpad(padded_plaintext):
padding_length = padded_plaintext[-1]
return padded_plaintext[:-padding_length]
def key_expansion(key):
# Ensure key is 16 bytes for 128-bit key
if len(key) != 16:
raise ValueError("Key must be 16 bytes long for 128-bit key")
# Convert key into an integer for processing
K = int.from_bytes(key, byteorder='big')
round_keys = []
# Generate round keys
for i in range(17):
# Calculate round key by rotating and applying transformations
round_key = (K ^ (i * 0x1B)) % (1 << 128)
round_keys.append(round_key.to_bytes(16, byteorder='big'))
return round_keys
CP_TABLE = [0, 32, 1, 33, 2, 34, 3, 35, 4, 36, 5, 37, 6, 38, 7, 39, 8, 40, 9, 41, 10, 42, 11, 43, 12, 44, 13, 45, 14, 46, 15, 47, 16, 48, 17, 49, 18, 50, 19, 51, 20, 52, 21, 53, 22, 54, 23, 55, 24, 56, 25, 57, 26, 58, 27, 59, 28, 60, 29, 61, 30, 62, 31, 63]
FP_TABLE = [57, 49, 41, 33, 25, 17, 9, 1, 59, 51, 43, 35, 27, 19, 11, 3, 61, 53, 45, 37, 29, 21, 13, 5, 63, 55, 47, 39, 31, 23, 15, 7, 56, 48, 40, 32, 24, 16, 8, 0, 58, 50, 42, 34, 26, 18, 10, 2, 60, 52, 44, 36, 28, 20, 12, 4, 62, 54, 46, 38, 30, 22, 14, 6]
def permute(block, table):
permuted_block = 0
for index, bit_pos in enumerate(table):
permuted_block |= ((block >> bit_pos) & 1) << index
return permuted_block
SBOX = [
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
]
INV_SBOX = [SBOX.index(x) for x in range(256)]
INV_CP_TABLE = [CP_TABLE.index(i) for i in range(64)]
INV_FP_TABLE = [FP_TABLE.index(i) for i in range(64)]
def sub_bytes_8(state):
return [SBOX[b] for b in state]
def shift_rows_8(state):
return [
state[0], state[1], state[2], state[3],
state[4], state[5], state[6], state[7]
]
def gf_mult(a, b):
p = 0
hi_bit_set = 0
for _ in range(8):
if b & 1:
p ^= a
hi_bit_set = a & 0x80
a <<= 1
if hi_bit_set:
a ^= 0x1b
b >>= 1
return p % 256
def mix_columns_8(state):
result = [0] * 8
for c in range(2):
col = state[c*4:(c+1)*4]
result[c*4] = gf_mult(2, col[0]) ^ gf_mult(3, col[1]) ^ col[2] ^ col[3]
result[c*4+1] = col[0] ^ gf_mult(2, col[1]) ^ gf_mult(3, col[2]) ^ col[3]
result[c*4+2] = col[0] ^ col[1] ^ gf_mult(2, col[2]) ^ gf_mult(3, col[3])
result[c*4+3] = gf_mult(3, col[0]) ^ col[1] ^ col[2] ^ gf_mult(2, col[3])
return result
def add_round_key(state, round_key):
round_key_bytes = list(round_key)
return [b ^ round_key_bytes[i] for i, b in enumerate(state)]
def encrypt_block_8(block, round_keys):
block = int.from_bytes(block, byteorder='big')
block = permute(block, CP_TABLE)
block = block.to_bytes(8, byteorder='big')
state = list(block)
print(f"Initial State: {state}")
state = add_round_key(state, round_keys[0])
print(f"After Add Round Key: {state}")
for i in range(1, 17):
state = sub_bytes_8(state)
state = shift_rows_8(state)
state = mix_columns_8(state)
state = add_round_key(state, round_keys[i])
print(f"After Round {i}: {state}")
block = int.from_bytes(state, byteorder='big')
block = permute(block, FP_TABLE)
return block.to_bytes(8, byteorder='big')
def encrypt_message(message, key):
block_size = 8 # 64-bit block size = 8 bytes
padded_message = pad(message.encode('utf-8'), block_size)
round_keys = key_expansion(key)
ciphertext = b''
for i in range(0, len(padded_message), block_size):
block = padded_message[i:i+block_size]
ciphertext += encrypt_block_8(block, round_keys)
return ciphertext
def inv_mix_columns_8(state):
result = [0] * 8
for c in range(2):
col = state[c*4:(c+1)*4]
result[c*4] = gf_mult(14, col[0]) ^ gf_mult(11, col[1]) ^ gf_mult(13, col[2]) ^ gf_mult(9, col[3])
result[c*4+1] = gf_mult(9, col[0]) ^ gf_mult(14, col[1]) ^ gf_mult(11, col[2]) ^ gf_mult(13, col[3])
result[c*4+2] = gf_mult(13, col[0]) ^ gf_mult(9, col[1]) ^ gf_mult(14, col[2]) ^ gf_mult(11, col[3])
result[c*4+3] = gf_mult(11, col[0]) ^ gf_mult(13, col[1]) ^ gf_mult(9, col[2]) ^ gf_mult(14, col[3])
return result
def inv_sub_bytes_8(state):
return [INV_SBOX[b] for b in state]
def inv_shift_rows_8(state):
return [
state[0], state[1], state[2], state[3],
state[4], state[5], state[6], state[7]
]
def decrypt_block_8(block, round_keys):
block = int.from_bytes(block, byteorder='big')
block = permute(block, INV_FP_TABLE)
block = block.to_bytes(8, byteorder='big')
state = list(block)
state = add_round_key(state, round_keys[16])
for i in range(15, 0, -1):
state = inv_mix_columns_8(state)
state = inv_shift_rows_8(state)
state = inv_sub_bytes_8(state)
state = add_round_key(state, round_keys[i])
state = add_round_key(state, round_keys[0])
block = int.from_bytes(state, byteorder='big')
block = permute(block, INV_CP_TABLE)
return block.to_bytes(8, byteorder='big')
def decrypt_message(ciphertext, key):
block_size = 8 # 64-bit block size = 8 bytes
round_keys = key_expansion(key)
plaintext = b''
for i in range(0, len(ciphertext), block_size):
block = ciphertext[i:i+block_size]
plaintext += decrypt_block_8(block, round_keys)
print("Plain Text: ", plaintext.hex)
return unpad(plaintext).decode('utf-8')
key = b'\x01' * 16 #128-bit key
# plaintext = b'\x06' * 8 #64-bit plaintext
message = "I love cybersecurity"
round_keys = key_expansion(key)
for i, rk in enumerate(round_keys):
print(f"Round Key {i}: {rk.hex()}")
# Encrypt
# ciphertext = encrypt_block_8(plaintext, round_keys)
ciphertext = encrypt_message(message, key)
print("Ciphertext:", ciphertext)
# Decrypt
# decrypted_text = decrypt_block_8(ciphertext, round_keys)
decrypted_text = decrypt_message(ciphertext, key)
print("Decrypted Text:", decrypted_text)
```

<p>Block Size:

Input/Output Block Size: 128 bits (16 bytes)</p>

<p>Key Generation:

Initial Key: A 128-bit key is used to generate 16 round keys.

Round Key Generation: The initial key is processed through a key expansion algorithm to produce 16 round keys. Each round key is derived by applying a fixed transformation to the previous round key.</p>

<p>Encryption Process:</p>

<p>Initial State: The plaintext is divided into two halves (L0, R0) of 64 bits each.

Rounds: The encryption process consists of 16 rounds. In each round:

Round Key Application: The round key is XORed with the right half (R).

Feistel Function: A Feistel function is applied to the result, involving substitution and permutation.

Swap: The left and right halves are swapped for the next round.

Final State: After 16 rounds, the final output is obtained by concatenating the left and right halves.</p>

<p>I’m encountering issues where the decrypted output does not match the original plaintext. Despite following the algorithm and applying the round keys correctly, the decrypted text is incorrect or empty.</p>

<p>What I've Tried:

-Verified key generation and round key application.

-Checked the implementation of the substitution, permutation, and other operations.

-Debugged step-by-step to ensure each operation is applied correctly.</p>

<p>Thank you</p>

<pre><code>def pad(plaintext, block_size):

padding_length = block_size - (len(plaintext) % block_size)

padding = bytes([padding_length] * padding_length)

return plaintext + padding

def unpad(padded_plaintext):

padding_length = padded_plaintext[-1]

return padded_plaintext[adding_length]

def key_expansion(key):

# Ensure key is 16 bytes for 128-bit key

if len(key) != 16:

raise ValueError("Key must be 16 bytes long for 128-bit key")

# Convert key into an integer for processing

K = int.from_bytes(key, byteorder='big')

round_keys = []

# Generate round keys

for i in range(17):

# Calculate round key by rotating and applying transformations

round_key = (K ^ (i * 0x1B)) % (1 << 128)

round_keys.append(round_key.to_bytes(16, byteorder='big'))

return round_keys

CP_TABLE = [0, 32, 1, 33, 2, 34, 3, 35, 4, 36, 5, 37, 6, 38, 7, 39, 8, 40, 9, 41, 10, 42, 11, 43, 12, 44, 13, 45, 14, 46, 15, 47, 16, 48, 17, 49, 18, 50, 19, 51, 20, 52, 21, 53, 22, 54, 23, 55, 24, 56, 25, 57, 26, 58, 27, 59, 28, 60, 29, 61, 30, 62, 31, 63]

FP_TABLE = [57, 49, 41, 33, 25, 17, 9, 1, 59, 51, 43, 35, 27, 19, 11, 3, 61, 53, 45, 37, 29, 21, 13, 5, 63, 55, 47, 39, 31, 23, 15, 7, 56, 48, 40, 32, 24, 16, 8, 0, 58, 50, 42, 34, 26, 18, 10, 2, 60, 52, 44, 36, 28, 20, 12, 4, 62, 54, 46, 38, 30, 22, 14, 6]

def permute(block, table):

permuted_block = 0

for index, bit_pos in enumerate(table):

permuted_block |= ((block >> bit_pos) & 1) << index

return permuted_block

SBOX = [

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

]

INV_SBOX = [SBOX.index(x) for x in range(256)]

INV_CP_TABLE = [CP_TABLE.index(i) for i in range(64)]

INV_FP_TABLE = [FP_TABLE.index(i) for i in range(64)]

def sub_bytes_8(state):

return [SBOX

**for b in state]**

def shift_rows_8(state):

return [

state[0], state[1], state[2], state[3],

state[4], state[5], state[6], state[7]

]

def gf_mult(a, b):

p = 0

hi_bit_set = 0

for _ in range(8):

if b & 1:

p ^= a

hi_bit_set = a & 0x80

a <<= 1

if hi_bit_set:

a ^= 0x1b

b >>= 1

return p % 256

def mix_columns_8(state):

result = [0] * 8

for c in range(2):

col = state[c*4c+1)*4]

result[c*4] = gf_mult(2, col[0]) ^ gf_mult(3, col[1]) ^ col[2] ^ col[3]

result[c*4+1] = col[0] ^ gf_mult(2, col[1]) ^ gf_mult(3, col[2]) ^ col[3]

result[c*4+2] = col[0] ^ col[1] ^ gf_mult(2, col[2]) ^ gf_mult(3, col[3])

result[c*4+3] = gf_mult(3, col[0]) ^ col[1] ^ col[2] ^ gf_mult(2, col[3])

return result

def add_round_key(state, round_key):

round_key_bytes = list(round_key)

return [b ^ round_key_bytes

def shift_rows_8(state):

return [

state[0], state[1], state[2], state[3],

state[4], state[5], state[6], state[7]

]

def gf_mult(a, b):

p = 0

hi_bit_set = 0

for _ in range(8):

if b & 1:

p ^= a

hi_bit_set = a & 0x80

a <<= 1

if hi_bit_set:

a ^= 0x1b

b >>= 1

return p % 256

def mix_columns_8(state):

result = [0] * 8

for c in range(2):

col = state[c*4c+1)*4]

result[c*4] = gf_mult(2, col[0]) ^ gf_mult(3, col[1]) ^ col[2] ^ col[3]

result[c*4+1] = col[0] ^ gf_mult(2, col[1]) ^ gf_mult(3, col[2]) ^ col[3]

result[c*4+2] = col[0] ^ col[1] ^ gf_mult(2, col[2]) ^ gf_mult(3, col[3])

result[c*4+3] = gf_mult(3, col[0]) ^ col[1] ^ col[2] ^ gf_mult(2, col[3])

return result

def add_round_key(state, round_key):

round_key_bytes = list(round_key)

return [b ^ round_key_bytes

*for i, b in enumerate(state)]*

def encrypt_block_8(block, round_keys):

block = int.from_bytes(block, byteorder='big')

block = permute(block, CP_TABLE)

block = block.to_bytes(8, byteorder='big')

state = list(block)

print(f"Initial State: {state}")

state = add_round_key(state, round_keys[0])

print(f"After Add Round Key: {state}")

for i in range(1, 17):

state = sub_bytes_8(state)

state = shift_rows_8(state)

state = mix_columns_8(state)

state = add_round_key(state, round_keysdef encrypt_block_8(block, round_keys):

block = int.from_bytes(block, byteorder='big')

block = permute(block, CP_TABLE)

block = block.to_bytes(8, byteorder='big')

state = list(block)

print(f"Initial State: {state}")

state = add_round_key(state, round_keys[0])

print(f"After Add Round Key: {state}")

for i in range(1, 17):

state = sub_bytes_8(state)

state = shift_rows_8(state)

state = mix_columns_8(state)

state = add_round_key(state, round_keys

*)*

print(f"After Round {i}: {state}")

block = int.from_bytes(state, byteorder='big')

block = permute(block, FP_TABLE)

return block.to_bytes(8, byteorder='big')

def encrypt_message(message, key):

block_size = 8 # 64-bit block size = 8 bytes

padded_message = pad(message.encode('utf-8'), block_size)

round_keys = key_expansion(key)

ciphertext = b''

for i in range(0, len(padded_message), block_size):

block = padded_message[i:i+block_size]

ciphertext += encrypt_block_8(block, round_keys)

return ciphertext

def inv_mix_columns_8(state):

result = [0] * 8

for c in range(2):

col = state[c*4c+1)*4]

result[c*4] = gf_mult(14, col[0]) ^ gf_mult(11, col[1]) ^ gf_mult(13, col[2]) ^ gf_mult(9, col[3])

result[c*4+1] = gf_mult(9, col[0]) ^ gf_mult(14, col[1]) ^ gf_mult(11, col[2]) ^ gf_mult(13, col[3])

result[c*4+2] = gf_mult(13, col[0]) ^ gf_mult(9, col[1]) ^ gf_mult(14, col[2]) ^ gf_mult(11, col[3])

result[c*4+3] = gf_mult(11, col[0]) ^ gf_mult(13, col[1]) ^ gf_mult(9, col[2]) ^ gf_mult(14, col[3])

return result

def inv_sub_bytes_8(state):

return [INV_SBOXprint(f"After Round {i}: {state}")

block = int.from_bytes(state, byteorder='big')

block = permute(block, FP_TABLE)

return block.to_bytes(8, byteorder='big')

def encrypt_message(message, key):

block_size = 8 # 64-bit block size = 8 bytes

padded_message = pad(message.encode('utf-8'), block_size)

round_keys = key_expansion(key)

ciphertext = b''

for i in range(0, len(padded_message), block_size):

block = padded_message[i:i+block_size]

ciphertext += encrypt_block_8(block, round_keys)

return ciphertext

def inv_mix_columns_8(state):

result = [0] * 8

for c in range(2):

col = state[c*4c+1)*4]

result[c*4] = gf_mult(14, col[0]) ^ gf_mult(11, col[1]) ^ gf_mult(13, col[2]) ^ gf_mult(9, col[3])

result[c*4+1] = gf_mult(9, col[0]) ^ gf_mult(14, col[1]) ^ gf_mult(11, col[2]) ^ gf_mult(13, col[3])

result[c*4+2] = gf_mult(13, col[0]) ^ gf_mult(9, col[1]) ^ gf_mult(14, col[2]) ^ gf_mult(11, col[3])

result[c*4+3] = gf_mult(11, col[0]) ^ gf_mult(13, col[1]) ^ gf_mult(9, col[2]) ^ gf_mult(14, col[3])

return result

def inv_sub_bytes_8(state):

return [INV_SBOX

**for b in state]**

def inv_shift_rows_8(state):

return [

state[0], state[1], state[2], state[3],

state[4], state[5], state[6], state[7]

]

def decrypt_block_8(block, round_keys):

block = int.from_bytes(block, byteorder='big')

block = permute(block, INV_FP_TABLE)

block = block.to_bytes(8, byteorder='big')

state = list(block)

state = add_round_key(state, round_keys[16])

for i in range(15, 0, -1):

state = inv_mix_columns_8(state)

state = inv_shift_rows_8(state)

state = inv_sub_bytes_8(state)

state = add_round_key(state, round_keysdef inv_shift_rows_8(state):

return [

state[0], state[1], state[2], state[3],

state[4], state[5], state[6], state[7]

]

def decrypt_block_8(block, round_keys):

block = int.from_bytes(block, byteorder='big')

block = permute(block, INV_FP_TABLE)

block = block.to_bytes(8, byteorder='big')

state = list(block)

state = add_round_key(state, round_keys[16])

for i in range(15, 0, -1):

state = inv_mix_columns_8(state)

state = inv_shift_rows_8(state)

state = inv_sub_bytes_8(state)

state = add_round_key(state, round_keys

*)*

state = add_round_key(state, round_keys[0])

block = int.from_bytes(state, byteorder='big')

block = permute(block, INV_CP_TABLE)

return block.to_bytes(8, byteorder='big')

def decrypt_message(ciphertext, key):

block_size = 8 # 64-bit block size = 8 bytes

round_keys = key_expansion(key)

plaintext = b''

for i in range(0, len(ciphertext), block_size):

block = ciphertext[i:i+block_size]

plaintext += decrypt_block_8(block, round_keys)

print("Plain Text: ", plaintext.hex)

return unpad(plaintext).decode('utf-8')

key = b'\x01' * 16 #128-bit key

# plaintext = b'\x06' * 8 #64-bit plaintext

message = "I love cybersecurity"

round_keys = key_expansion(key)

for i, rk in enumerate(round_keys):

print(f"Round Key {i}: {rk.hex()}")

# Encrypt

# ciphertext = encrypt_block_8(plaintext, round_keys)

ciphertext = encrypt_message(message, key)

print("Ciphertext:", ciphertext)

# Decrypt

# decrypted_text = decrypt_block_8(ciphertext, round_keys)

decrypted_text = decrypt_message(ciphertext, key)

print("Decrypted Text:", decrypted_text)

</code></pre>state = add_round_key(state, round_keys[0])

block = int.from_bytes(state, byteorder='big')

block = permute(block, INV_CP_TABLE)

return block.to_bytes(8, byteorder='big')

def decrypt_message(ciphertext, key):

block_size = 8 # 64-bit block size = 8 bytes

round_keys = key_expansion(key)

plaintext = b''

for i in range(0, len(ciphertext), block_size):

block = ciphertext[i:i+block_size]

plaintext += decrypt_block_8(block, round_keys)

print("Plain Text: ", plaintext.hex)

return unpad(plaintext).decode('utf-8')

key = b'\x01' * 16 #128-bit key

# plaintext = b'\x06' * 8 #64-bit plaintext

message = "I love cybersecurity"

round_keys = key_expansion(key)

for i, rk in enumerate(round_keys):

print(f"Round Key {i}: {rk.hex()}")

# Encrypt

# ciphertext = encrypt_block_8(plaintext, round_keys)

ciphertext = encrypt_message(message, key)

print("Ciphertext:", ciphertext)

# Decrypt

# decrypted_text = decrypt_block_8(ciphertext, round_keys)

decrypted_text = decrypt_message(ciphertext, key)

print("Decrypted Text:", decrypted_text)

</code></pre>