Невозможно расшифровать зашифрованные байтовые данные, хранящиеся в базе данных

Я написал 2 функции на языке python, одну для шифрования данных и другую для расшифровки данных, которые выглядят следующим образом.

from app.settings import DATA_KEY
import logging
from cryptography.hazmat.primitives.ciphers.aead import AESSIV
import base64

cipher_suite = AESSIV(DATA_KEY)

error_logger = logging.getLogger("error_logger")


def encrypt_field(input_text):
    try:
        if isinstance(input_text, str):
            input_text = input_text.encode()
        enc_text = cipher_suite.encrypt(input_text, associated_data = None)
        print(f"enc_text is {enc_text}")
        enc_text_base_64 = base64.b64encode(enc_text)
        print(f"encrypted_text is {enc_text_base_64}")
        return enc_text_base_64
    
    except Exception as e:
        error_logger.error(f"exception in encrypt field {str(e)} on field {input_text}")
        return input_text


def decrypt_field(input_text):
    try:
        print(f"input in decrypt field is {input_text} its type is {type(input_text)}")
        enc_text = base64.b64decode(input_text)
        print(f"enc text is {enc_text}")
        decrypted_field = cipher_suite.decrypt(enc_text, associated_data = None)
        print(f"decrypted_field is {decrypted_field}")
        return decrypted_field.decode('utf-8')
    
    except Exception as e:
        print(e)
        error_logger.error(f"exception in decrypt_field {e} on field {input_text}")
        return input_text
    
    

Мне удается зашифровать и сохранить данные в db, однако при чтении данных из db и попытке расшифровать их я получаю вместо исходного текста строку utf-8 bytestring. Что я делаю не так? Моя версия Django - 5.0, версия Python - 3.10.11, а база данных - PostgreSQL.

Вот как я пытаюсь расшифровать значения после чтения данных с помощью queryset

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = get_user_model()
        
        fields = ['username', 'email']

    def get_username(self, obj):
        return decrypt_field(obj.username)
    
    def get_email(self, obj):
        return decrypt_field(obj.email)

а это моя модель

class User(AbstractUser):
    username = models.CharField(max_length=300, unique=True)
    first_name = models.CharField(null=True, blank=True)
    middle_name = models.CharField(max_length=100, null=True, blank=True)
    last_name = models.CharField(max_length=100, null=True, blank=True)
    phone = models.CharField(max_length=50, null=True, blank=True)
    password = models.CharField(max_length=150, null=True, blank=True)
    password_reset_required = models.SmallIntegerField(null=True, blank=True)
    username_field = "email"

при вызове функции расшифровки вместо оригинального email и имени пользователя, которые я указал

redgrave@example.com

Вместо этого я получаю

"b'CSPex4eChMQousC2Sn5JBCvge6j2X73iiQIZ5O5l9d2AliVBWiPGoGe5pKVTzEVAlIYcBxbe+1gufGXhnIQKCQ=='"

Я пробовал хранить данные как в BinaryField, так и в TextField модели Django, добавляя дополнительные поля в модель с binary и TextField в качестве datatype. но безрезультатно, результат тот же. Я также пробовал хранить данные как закодированные байтовые данные без base64encde, но они не могут быть декодированы позже и приводят к ошибке неопределенного символа.

Я думаю, что вы можете просто упростить свою реализацию:

import base64

from cryptography.hazmat.primitives.ciphers.aead import AESSIV

DATA_KEY = b"ABCDEFGH" * 4  # VERY SECRET!
cipher_suite = AESSIV(DATA_KEY)


def encrypt_text_to_base64(input_text: str) -> str:
    if not isinstance(input_text, str):
        raise TypeError("Input must be text")
    enc_text = cipher_suite.encrypt(input_text.encode("utf-8"), associated_data=None)
    return base64.b64encode(enc_text).decode("ascii")


def decode_base64_to_text(input_text: str | bytes) -> str:
    return cipher_suite.decrypt(
        base64.b64decode(input_text), associated_data=None
    ).decode("utf-8")


plain = "Hello, world!"
encrypted = encrypt_text_to_base64(plain)
encrypted_bytes = encrypted.encode("utf-8")
decrypted = decode_base64_to_text(encrypted)
decrypted_from_bytes = decode_base64_to_text(encrypted_bytes)

print(f"{plain=}")
print(f"{encrypted=}")
print(f"{encrypted_bytes=}")
print(f"{decrypted=}")
print(f"{decrypted_from_bytes=}")


try:
    print(decode_base64_to_text("f" + encrypted[1:]))
except Exception as e:
    print("Failed to decrypt tampered data:", repr(e))

Это распечатывается

plain='Hello, world!'
encrypted='1mtatTQy3/GRFv0tUd3Mp66V8uDbeKDqn8rKytU='
encrypted_bytes=b'1mtatTQy3/GRFv0tUd3Mp66V8uDbeKDqn8rKytU='
decrypted='Hello, world!'
decrypted_from_bytes='Hello, world!'
Failed to decrypt tampered data: InvalidTag()

Так что вы можете видеть, что функция расшифровки работает как для base64-in-bytes, так и для base64-as-a-string.

Вернуться на верх