2.4. Symmetric-key Cryptography#

In symmetric-key cryptography the same key is used to both encrypt the plaintext to ciphertext and decrypt the ciphertext to plaintext.

../../_images/plaintext_ciphertext_symmetric.png

2.4.1. Simple Example#

We previously saw a simple substitution letter where we substituted letters with other letters using a normal alphabet and a mixed alphabet where we created the mixed alphabet using a key. In this example the key is \(\textcolor{red}{IMAGINATION}\).

Plaintext

A

B

C

D

E

F

G

H

I

J

K

L

M

Ciphertext

\(\textcolor{red}{I}\)

\(\textcolor{red}{M}\)

\(\textcolor{red}{A}\)

\(\textcolor{red}{G}\)

\(\textcolor{red}{N}\)

\(\textcolor{red}{T}\)

\(\textcolor{red}{O}\)

B

C

D

E

F

H

Plaintext

N

O

P

Q

R

S

T

U

V

W

X

Y

Z

Ciphertext

J

K

L

P

Q

R

S

U

V

W

X

Y

Z

Plaintext:

UNITED WE STAND DIVIDED WE FALL

Ciphertext:

UJCSNG WN RSIJG GCVCGNG WN TIFF

If you know the key you can ‘unlock’ the encryption because you can determine what the mixed alphabet looks like and therefore you know the mapping between the plaintext and the ciphertext.

2.5. In Practice#

Simple ciphers like a substitution cipher are vulnerable to brute force attacks or frequency analysis and can be broken. Modern encryption algorithms incorporate several clever techniques to create encryption that is resistant to these kinds of attacks.

Symmetric-key encryption algorithms achieve a high level of security in two ways:

  • Confusion, which is decorrelating the input plain text from the output cipher text

  • Diffusion, which is hidings the plain text by spreading it over a greater number of characters

2.5.1. Blocks#

Modern encryption algorithms work by breaking the plain text into fixed size chunks called blocks. Each block is processed through the algorithm separately.

The “block size” is the length of the data, in bits, that each block contains. Generally block sizes are fixed for an encryption algorithm, or there are variations of the algorithms for common block sizes e.g. 128 bits or 256 bits.

The image below shows a simplified example with a 16 bit block size.

../../_images/blocks.png

In contrast, simple substitution ciphers like a Caesar cipher can be thought of as using a block size of 1 character, since each character is processed separately.

Larger block sizes improve security by making it much harder to find repeating patterns or “collisions” that could be exploited to reveal the underlying plaintext. In other words, larger block sizes increase the confusion.

2.5.2. Substitution-Permutation Networks#

Modern encryption algorithms rely on repetitions of two operations: substitution and permutation. Both steps are performed by what is called “boxes” i.e. there are “S-Boxes” and “P-Boxes”, which are just complicated functions.

Substitution (S-Boxes)

The substitution step replaces segments of the data with different values using carefully designed substitution rules (functions). This process adds confusion to the encryption process and the more complex the substitution process is, the greater the confusion.

Permutation (P-Boxes)

The permutation step rearranges the bits (or bytes) within a block according to a fixed rule. This rearrangement spreads the influence of each input bit across many output bits. The combined effect is that a small change in the plaintext or key will result in a dramatic change in the ciphertext. In other words permutation process increases diffusion.

2.5.3. Rounds#

In practice, modern encryption algorithms repeat the substitution and permutation steps a fixed number of times. Each repetition is called a round. Repeating the process compounds the confusion and diffusion properties.

2.5.5. Disadvantages#

The main disadvantage of symmetric-key cryptography is the both parties need to know what they key is. For example, if Alice wanted to send a secret message to Stevie using a symmetric cipher, both Alice and Stevie need to know what the key is. But say Alice and Stevie are in two different cities, how do they share the secret key? They can’t encrypt anything yet because they need to share a key to encrypt, so they would have to send the key securely somehow in plaintext, which runs the risk that someone else sees the key. The most secure way to share the key would be to meet in person to share the key, but this could be quite impractical, especially if they wanted to periodically change their secret key. We’ll see later that you can get around this using asymmetric cryptography.

Demo: Crypto Module - Symmetric

Implementing encryption and decryption in code can be quite tricky and error prone.

To simplify the process and save you time, we’ve provided you with a module called crypto that implements Symmetric-key encryption. This page serves to explain how to use this module.

Note

A copy of this module has been provided in the files for this page.

Generating Keys

The static method Symmetric.generate_key returns a new randomly generated key as a str.

Example

from crypto import Symmetric

key = Symmetric.generate_key()

print(key)

Encrypting

The static method Symmetric.encrypt(message, key):

  • accepts two parameters:

    • message which is the str to encrypt

    • key which is a key str previously generated by Symmetric.generate_key

  • returns the ciphertext as a str.

Example

from crypto import Symmetric

message = "SECRET"
key = "1xzcBiDwPPAsUVScnms_3aw8APdFz9C1e_jrxm0rXhM="

ciphertext = Symmetric.encrypt(message, key)

print(ciphertext)

Decrypting

The static method Symmetric.decrypt(encrypted, key):

  • accepts two parameters:

    • encrypted which is the cipher text

    • key which is a key str previously generated by Symmetric.generate_key

  • returns the cipher text as a str.

Example

from crypto import Symmetric

cipher_text = "gAAAAABnxp7a2nQKoa87xg6So-XyEN7DYHU-0g1OS_PWSra2Fkp54eukT1OMYQKoGhkHuAeLrSO1p_6Ktz21gVIF631oyT8Ldg=="
key = "1xzcBiDwPPAsUVScnms_3aw8APdFz9C1e_jrxm0rXhM="

plaintext = Symmetric.decrypt(ciphertext, key)

print(plaintext)

Code Samples

demo.py#
from crypto import Symmetric

# Generate key
key = Symmetric.generate_key()
print("key:", key)

# Encrypting
message = "SECRET"
ciphertext = Symmetric.encrypt(message, key)
print("\nCiphertext:", ciphertext)

# Decrypting
plaintext = Symmetric.decrypt(ciphertext, key)
print("\nPlaintext:", plaintext)
crypto.py
crypto.py#
from typing import List
from cryptography.hazmat.primitives.asymmetric import rsa, padding as asym_padding
from cryptography.hazmat.primitives import hashes, serialization
import base64
from cryptography.fernet import Fernet

class Symmetric:
    @staticmethod
    def generate_key() -> str:
        # Returns a Base64-encoded key as an ASCII string
        return Fernet.generate_key().decode('ascii')

    @staticmethod
    def encrypt(message: str, key: str) -> str:
        if not isinstance(message, str):
            raise TypeError("message must be a string")
        if not isinstance(key, str):
            raise TypeError("key must be a string")
        if len(message) == 0:
            raise ValueError("message must not be empty")

        try:
            message_bytes = message.encode('ascii')
        except Exception as e:
            raise ValueError("Failed to encode message in ASCII") from e

        try:
            key_bytes = key.encode('ascii')
        except Exception as e:
            raise ValueError("Failed to encode key in ASCII") from e

        return Fernet(key_bytes).encrypt(message_bytes).decode('ascii')

    @staticmethod
    def decrypt(encrypted: str, key: str) -> str:
        if not isinstance(encrypted, str):
            raise TypeError("encrypted must be a string")
        if not isinstance(key, str):
            raise TypeError("key must be a string")

        try:
            encrypted_bytes = encrypted.encode("ascii")
        except Exception as e:
            raise ValueError("Failed to encode encrypted message in ASCII") from e

        try:
            key_bytes = key.encode('ascii')
        except Exception as e:
            raise ValueError("Failed to encode key in ASCII") from e

        return Fernet(key_bytes).decrypt(encrypted_bytes).decode('ascii')
Code Challenge: Encrypt a Message

You’ve been given a module called crypto which contains a class called Symmetric. Use the Symmetric class to encrypt a message provided by the user.

Your program must:

  • generate a new symmetric encryption key

  • encrypt a message that the user inputs with the generated key

  • print both the key and the message to the terminal

Write your program in exercise.py.

Example

Enter your message: hello

KEY (KEEP THIS SECRET):
R8MpSi4Qc6SrcbKVtylFJbgCwHP-1VTy28dOrTcdNWw=

ENCRYPTED MESSAGE:
gAAAAABnw7v8j55BJ6PJyWRuFATj1YBH0e-QhBpJanDOI4fosH17FBgmMI71UdRphtGzWfx22cBB0J_waGJKXwDU0z9TJNeifA==

Note

Because the encryption process is random, even if you use the same key you will likely get different encrypted messages!

Solution

Solution is locked

Code Challenge: Decrypt a Message

You’ve been given a module called crypto which contains a class called Symmetric. Use the Symmetric class to decrypt a message provided by the user.

Your program must:

  • read a key and message from the terminal

  • decrypt the message

  • print the decrypted message to the terminal

Write your program in exercise.py.

Example

Enter the key:
R8MpSi4Qc6SrcbKVtylFJbgCwHP-1VTy28dOrTcdNWw=

Enter the encrypted message:
gAAAAABnw7v8j55BJ6PJyWRuFATj1YBH0e-QhBpJanDOI4fosH17FBgmMI71UdRphtGzWfx22cBB0J_waGJKXwDU0z9TJNeifA==

Original Message:
hello

Note

You can test your code using the example key and message above or generate them from the previous exercise!

Solution

Solution is locked