Невозможно расшифровать зашифрованные байтовые данные, хранящиеся в базе данных
Я написал 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.