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.
Ingeniero en Informática, Investigador, me encanta crear cosas o arreglarlas y darles una nueva vida. Escritor y poeta. Más de 20 APPs publicadas y un libro en Amazon.