I'm playing around with a project that is python backend-based. I'll have Django for the "core" stuff and FastAPI for some crawlers. I'm encrpting some data to the DB with Django using the Fernet
module and a custom Field
.
class EncryptedField(models.CharField):
description = "Save encrypted data to DB an read as string on application level."
def __init__(self, *args, **kwargs):
kwargs["max_length"] = 1000
super().__init__(*args, **kwargs)
@cached_property
def fernet(self) -> Fernet:
return Fernet(key=settings.FERNET_KEY)
def get_internal_type(self) -> str:
return "BinaryField"
def get_db_prep_save(
self, value: Any, connection: BaseDatabaseWrapper
) -> Union[memoryview, None]:
value = super().get_db_prep_save(value, connection)
if value is not None:
encrypted_value = self.fernet.encrypt(data=force_bytes(s=value))
return connection.Database.Binary(encrypted_value)
def from_db_value(self, value: bytes, *args) -> Union[str, None]:
if value is not None:
decrypted_value = self.fernet.decrypt(token=force_bytes(s=value))
return self.to_python(value=force_str(s=decrypted_value))
Everything work as expected, the problem is when I try to decrypt the value on FastAPI side:
def decrypt(value: bytes):
return Fernet(FERNET_KEY).decrypt(token=value)
Some important information:
settings.FERNET_KEY == FERNET_KEY
, ie, I'm using the same key on both sides.from_db_value
-> value
-> b"gAAAAABhSm94ADjyQES3JL-EiEX4pH2odwJnJe2qsuGk_K685vseoVNN6kuoF9CRdf2GxiIViOgiKVcZMk5olg7FrJL2cmMFvg=="
user.encrypted_field
-> value
-> b"pbkdf2_sha256$260000$RzIJ5Vg3Yx8JTz4y5ZHttZ$0z9CuQiPCJrBZqc/5DvxiEcbNHZpu8hAZgmibAe7nrQ="
. I actually enter inside the DB and checked that this is the value stored there. user
comes from here:
from sqlmodel import Session, select
from .models import User
async def get_user(db: Session, username: str) -> str:
statement = select(User).where(User.username == username)
return db.exec(statement).first()
So I'm wondering there's something before from_db_value
that's converting the value somehow?!
One final alternative would be to decrypt the value on Django and send it directly to FastAPI, but I'd prefer not to do so.
How can I decrypt the value on FastAPI?
It is enough to decode the value:
def decrypt(value: bytes):
return Fernet(FERNET_KEY).decrypt(token=value)
Are you sure you are trying to decrypt the same data? To me, this looks like an encrypted password field and some other field.
mysql> select first_name, password from users_user where login='test'
+------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------+
| first_name | password |
| gAAAAABhSm94ADjyQES3JL-EiEX4pH2odwJnJe2qsuGk_K685vseoVNN6kuoF9CRdf2GxiIViOgiKVcZMk5olg7FrJL2cmMFvg== | pbkdf2_sha256$260000$RzIJ5Vg3Yx8JTz4y5ZHttZ$0z9CuQiPCJrBZqc/5DvxiEcbNHZpu8hAZgmibAe7nrQ= |
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With