Cifrar un fichero y obtenerlo descifrado usando FAST-API

Tiempo de lectura: 2 minutos

Hoy vamos a aprender cómo podemos almacenar un fichero cifrado y cómo descifrarlo para devolverlo en un response.

Vamos a utilizar la librería Fernet.

pip install cryptography

Primero vamos a crear una clave de cifrado con Fernet

def generate_key():
    key = Fernet.generate_key()
    return key.decode('utf-8')

Con esta función podemos obtener una clave aleatoria para Fernet, debemos almacenarla bien ya que se usará para descifrar los ficheros cifrados.

Ahora con estas funciones podremos cifrar y descifrar nuestros ficheros, se almacenarán con .enc

from cryptography.fernet import Fernet
import os
from dotenv import load_dotenv

load_dotenv()
FERNET_KEY = bytes(os.getenv("FERNET_KEY"), "utf-8")

fernet = Fernet(FERNET_KEY)

def generate_key():
    key = Fernet.generate_key()
    return key.decode('utf-8')

def cipher_file(original_file: bytes, save_path: str):
    new_file_name = save_path + ".enc"
    encrypted_data = fernet.encrypt(original_file)

    with open(new_file_name, "wb") as encrypted_file:
        encrypted_file.write(encrypted_data)


def decipher_file(encrypted_file_path: str):
    # Leer el contenido cifrado desde el archivo
    with open(encrypted_file_path, "rb") as encrypted_file:
        encrypted_data = encrypted_file.read()

    # Descifrar el contenido
    decrypted_data = fernet.decrypt(encrypted_data)

    # Devolver los datos descifrados directamente
    return decrypted_data


def decipher_file_in_path(encrypted_file_path: str):
    with open(encrypted_file_path, "rb") as encrypted_file:
        encrypted_data = encrypted_file.read()
        decrypted_data = fernet.decrypt(encrypted_data)

    return decrypted_data

Con la función cipher_file cifrará el fichero que pasamos por bytes y lo almacenará en la ruta indicada con .enc al final.

Para pasar los ficheros por bytes usamos esta función:

@api.post("/add_file", status_code=status.HTTP_201_CREATED)
def add_file( pdf_file: UploadFile = File(...)):
    upload_folder = "pdf"

    # Obtener fecha actual
    now = datetime.now()
    dt_string = now.strftime("%d_%m_%Y_%H_%M_%S")

    file_name = dt_string + ".pdf"
    file_route = os.path.join(upload_folder, file_name)
    cipher_file(pdf_file.file.read(), file_route)
   
    return {"filename": file_name}

Se suben ficheros de tipo File(…) y se almacenan cifrados

Para obtener el fichero cifrado, usamos el método decipher_file y devolverá el fichero descifrado en forma de bytes. Para poder devolver este fichero de forma de File tenemos que hacer lo siguiente:

@api.get("/get_file/{path}", status_code=status.HTTP_200_OK)
def get_file(path: str):
   
    # Verificar si el archivo existe
    if not os.path.exists(path):
        return {"error": "El archivo no existe"}

    # Obtengo decrypted_data de fernet.decrypt
    decrypted_data = decipher_file(ruta_fichero)
    #print("decrypted_data" + str(decrypted_data))

    # Devolver el fichero descifrado decrypted data tipo pdf (no tiene ruta)
    return StreamingResponse(io.BytesIO(decrypted_data), media_type="application/pdf", headers={"Content-Disposition": f"attachment; filename={"file"}"})
  

De esta forma devolverlos el archivo descifrado.

Y finalmente, si queremos descifrar el archivo dentro del propio directorio usaremos la función decipher_file_in_path, directamente sobreescribe el archivo dentro del directorio.

Deja un comentario