Examples

The following have been adapted from Pycryptodome’s documentation.

Encrypt data with AES

The following code generates a new 32 byte key and encrypts a piece of data. We use the GCM mode because it allows the receiver to detect any unauthorized modification (similarly, we could have used other authenticated encryption modes like EAX, CCM or SIV)

import os
from pyflocker.ciphers import AES

data = b"baba booey; fafa fooey; le fishe; monke"
key, nonce = os.urandom(32), os.urandom(16)

cipher = AES.new(True, key, AES.MODE_GCM, nonce)
ciphertext = cipher.update(data)
cipher.finalize()
tag = cipher.calculate_tag()

print("Plaintext:", data)
print("Ciphertext:", ciphertext)
print("Tag:", tag)

We can also use other symmetric ciphers like Camellia and ChaCha20.

Encrypt files and file-like objects with symmetric cipher

The following code creates a symmetric cipher (here Camellia cipher) and reads data from a file and writes the encrypted data into another file.

from pyflocker.ciphers import Camellia
from pyflocker.ciphers.modes import Modes

infile = open("somedata.bin", "rb")
outfile = open("encrypted.bin", "wb")
key, nonce = os.urandom(32), os.urandom(16)

cipher = Camellia.new(True, key, Modes.MODE_CTR, nonce, file=infile)
cipher.update_into(outfile)

print("Tag:", cipher.calculate_tag())

Similarly, we can also use AES and ChaCha20.

Important

Only those modes that are not defined in pyflocker.ciphers.modes.special support file encryption/decryption.

Quick file encryption and decryption

The following code demonstrates the use of pyflocker.locker for encrypting and decrypting files

from pyflocker import locker
password = b"my-super-secret-password"
locker.locker("top-secret-file.txt", password)

You can use a different AES mode too.

from pyflocker import locker
from pyflocker.ciphers import AES
password = b"my-super-secret-password"
locker.locker("top-secret-file.txt", password, aes_mode=AES.MODE_CFB8)

Important

Only those modes that are not defined in pyflocker.ciphers.modes.special support file encryption/decryption.

Creating, Serializing and Loading an asymmetric key

Here, we will use RSA as an example.

Creation

from pyflocker.ciphers import RSA
private = RSA.generate(2048)
public = RSA.public_key()

Serialization

By default, RSA uses PKCS8 format with PEM encoding, but you can use different parameters.

passphrase = b"no not this"

# Serialize the private key
with open("private.pem", "wb") as file:
    file.write(private.serialize(passphrase=passphrase))

# Serialize the public key
with open("public.pem", "wb") as file:
    file.write(public.serialize())

Loading the keys

# Load the private key
with open("private.pem", "rb") as file:
    private = RSA.load_private_key(file.read(), passphrase)

# Load the public key
with open("public.pem", "rb") as file:
    public = RSA.load_public_key(file.read())

Encryption and Decryption with RSA

The following code encrypts a piece of data for a receiver we have the RSA public key of. The RSA public key is stored in a file called receiver.pem.

Since we want to be able to encrypt an arbitrary amount of data, we use a hybrid encryption scheme. We use RSA with PKCS#1 OAEP for asymmetric encryption of an AES session key. The session key can then be used to encrypt all the actual data.

Here, we will use the CTR mode with HMAC to allow detection of unauthorized modifications. You can use any mode.

First, we will create a file to read data from:

data = b"""\
Hello world this is a text that will be encrypted.
Add some more of your own here.
"""

with open("somedata.txt", "wb") as file:
    file.write(data)

Encryption

Next, we will read the data from somedata.txt and encrypt it.

import os
from pyflocker.ciphers import AES, RSA, OAEP

# Load the receiver's public key.
with open("receiver.pem", "rb") as file:
    public = RSA.load_public_key(file.read())

# Create an AES cipher with session key:
# This will be used to encrypt an arbitrary amount of data.
session_key, nonce = os.urandom(32), os.urandom(16)
cipher_aes = AES.new(
    True,
    session_key,
    AES.MODE_CTR,
    nonce,
    use_hmac=True,
)

# Use the public key to encrypt the session key.
cipher_rsa = public.encryptor(OAEP())
enc_session_key = cipher_rsa.encrypt(session_key)

with open("somedata.txt", "rb") as file:
    ciphertext = cipher_aes.update(file.read())

# Calculate the cipher tag
cipher_aes.finalize()
tag = cipher_aes.calculate_tag()

with open("encrypted.bin", "wb") as file:
    file.write(
        b"".join(
            (
                enc_session_key,
                nonce,
                tag,
                ciphertext,
            )
        )
    )

Decryption

Decryption process is the inverse of encryption. The receiver will decrypt the encrypted session key and use it to decrypt the encrypted file (here encrypted.bin)

from pyflocker.ciphers import AES, RSA, OAEP

# The receiver loads their private key.
with open("private.pem", "rb") as file:
    private = RSA.load_private_key(file.read())

# Read the encrypted file and separate the parts.
with open("encrypted.bin", "rb") as file:
    (
        enc_session_key,
        nonce,
        tag,
        ciphertext,
    ) = [file.read(n) for n in (private.n.bit_length() // 8, 16, 16, -1)]

# Decrypt the session key and create a cipher.
dec = private.decryptor(OAEP())
session_key = dec.decrypt(enc_session_key)

cipher_aes = AES.new(
    False,
    session_key,
    AES.MODE_CTR,
    nonce,
    use_hmac=True,
)

# Decrypt the ciphertext and verify the decryption.
plaintext = cipher_aes.update(ciphertext)
cipher_aes.finalize(tag)

print(plaintext)