A.      Set up pipenv on your system.

-          Pipenv: Python Dev Workflow for Humans: https://pipenv.pypa.io/en/latest/

-          Pipenv Installation: https://pipenv.pypa.io/en/latest/installation.html

NOTE: Make sure the PATH environment variable is configured correctly.

 

 

B.      Set up a virtualenv for your project.

 

C.       Create a virtual shell and install the cryptography package.

 

D.      Run the following sample script to encrypt something using AES in CBC (Cipher Block Chaining) mode.

import secrets

from cryptography.hazmat.backends import default_backend

from cryptography.hazmat.primitives.ciphers import (Cipher, algorithms, modes)

 

key = b'key must be 128, 196 or 256 bits'

 

def encrypt(data):

    iv = secrets.token_bytes(16) # generates a random byte string.

    cipher = Cipher(

        algorithms.AES(key),

        modes.CBC(iv),

        backend=default_backend())

 

    encryptor = cipher.encryptor()

    return encryptor.update(data) + encryptor.finalize()

 

plaintext = b'the same message' * 2

print("plaintext: ", plaintext)

x = encrypt(plaintext)

print("x: ", x)

y = encrypt(plaintext)

print("y: ", y)

# CBC mode produces different ciphertexts

# when encrypting identical plaintexts with the same key.

# CBC mode achieves this by individualizing plaintext with

# an initialization vector (IV).

print("Is x[:16] == x[16:]?", x[:16] == x[16:])

print("Is x == y?", x == y)

 

# Q: How to decrypt x and y?

 

Q: How would you revise the above script to decrypt x and y successfully?

Hint: The decryption process needs not only the ciphertext and the key, but also the iv used during the encryption process.

import secrets

from cryptography.hazmat.backends import default_backend

from cryptography.hazmat.primitives.ciphers import (

Cipher, algorithms, modes)

 

key = b'key must be 128, 196 or 256 bits'

 

def encrypt(data):

    iv = secrets.token_bytes(16) # generates a random byte string.

    cipher = Cipher(

        algorithms.AES(key),

        modes.CBC(iv),

        backend=default_backend())

 

    encryptor = cipher.encryptor()

    return encryptor.update(data) + encryptor.finalize(), iv

 

plaintext = b'the same message' * 2

print("plaintext: ", plaintext)

x, ivx = encrypt(plaintext)

print("x: ", x, ", ivx: ", ivx)

y, ivy = encrypt(plaintext)

print("y: ", y, ", ivy: ", ivy)

# CBC mode produces different ciphertexts

# when encrypting identical plaintexts with the same key.

# CBC mode achieves this by individualizing plaintext with

# an initialization vector (IV).

#print("Is x[:16] == x[16:]?", x[:16] == x[16:])

#print("Is x == y?", x == y)

 

# Q1: How to decrypt x and y?

cipherx = Cipher(

        algorithms.AES(key),

        modes.CBC(ivx),

        backend=default_backend())

decryptor = cipherx.decryptor()

decryptedx = decryptor.update(x) + decryptor.finalize()

print("decryptedx: ", decryptedx)

 

ciphery = Cipher(

        algorithms.AES(key),

        modes.CBC(ivy),

        backend=default_backend())

decryptor = ciphery.decryptor()

decryptedy = decryptor.update(y) + decryptor.finalize()

print("decryptedy: ", decryptedy)

 

# Q2: How to reduce the redundancy in coding?