AES (Advanced Encryption Standard)

AES is a specification for the encryption of electronic data.

    - https://www.javainuse.com/aesgenerator
- https://zhangzeyu2001.medium.com/attacking-cbc-mode-bit-flipping-7e0a1c185511

Decrypt

GPG

gpg --decrypt example.gpg

OpenSSL

# AES-256-CBC
openssl aes-256-cbc -d -in encrypted_text -out decrypted.txt

# AES-256-CBC (PBKDF2)
openssl aes-256-cbc -pbkdf2 -iter 10000 -d -in encrypted_text -out decrypted.txt


Encrypt

GPG

gpg --symmetric --cipher-algo CIPHER message.txt

OpenSSL

# AES-256-CBC
openssl aes-256-cbc -e -in message.txt -out encrypted_message

# AES-256-CBC (PBKDF2)
openssl aes-256-cbc -pbkdf2 -iter 10000 -e -in message.txt -out encrypted_message


Implement AES in Python

Reference: https://medium.com/quick-code/aes-implementation-in-python-a82f582f51c2

We need pycryptodome for implementing AES easily.

pip install pycryptodome

Below is a Python script for AES encryption and decryption.

import hashlib
from Crypto import Random
from Crypto.Cipher import AES
from base64 import b64encode, b64decode

class AESCipher(object):
    def __init__(self, key):
        # AES block size is 128 bit
        self.block_size = AES.block_size
        # Generate unique 256 bit key
        self.key = hashlib.sha256(key.encode()).digest()

    def encrypt(self, plaintext):
        plaintext = self.__pad(plaintext)
        # IV (Initialization Vector) is the same size as the block size
        iv = Random.new().read(self.block_size)
        cipher = AES.new(self.key, AES.MODE_CBC, iv)
        ciphertext = cipher.encrypt(plaintext.encode())
        return b64encode(iv + ciphertext).decode('utf-8')

    def decrypt(self, ciphertext):
        ciphertext = b64decode(ciphertext)
        iv = ciphertext[:self.block_size]
        cipher = AES.new(self.key, AES.MODE_CBC, iv)
        plaintext = cipher.decrypt(ciphertext[self.block_size:]).decode('utf-8')
        return self.__unpad(plaintext)

    # Pad a plaintext for it to be a multiple of 128 bits.
    def __pad(self, plaintext):
        num_of_bytes_to_pad = self.block_size - len(plaintext) % self.block_size
        ascii_str = chr(num_of_bytes_pad)
        pad_str = num_of_bytes_to_pad * ascii_str
        pad_plaintext = plaintext + pad_str
        return pad_plaintext

    @staticmethod
    def __unpad(plaintext):
        last_char = plaintext[len(plaintext) -1:]
        bytes_to_remove = ord(last_char)
        return plaintext[:-bytes_to_remove]