Reputation: 261
I am having a requirement that i have to encrypt some of the fields in a table. I am using Django 1.3.1 and postgres 9.1. I am referring to this app django-fields :-
https://github.com/svetlyak40wt/django-fields/blob/master/src/django_fields/fields.py
Here is my code :-
patient_type = EncryptedCharField(max_length=80, choices=CHOICES.PATIENT_TYPES)
date_of_birth = EncryptedDateField(null=True, blank=True)
gender = EncryptedCharField(max_length=1024, choices=CHOICES.GENDERS, blank=True)
contact_phone = EncryptedCharField(max_length=1024, blank=True)
security_question = models.ForeignKey(SecurityQuestion, null=True, blank=True)
security_answer = EncryptedCharField(max_length=1024, null=True, blank=True)
It stores everything in encrypted form in the database except date_of_birth.It throws this error
Traceback: File "/usr/local/lib/python2.7/dist-packages/django/core/handlers/base.py" in get_response 111. response = callback(request, *callback_args, **callback_kwargs) File "/home/user/slave/old_careprep/CPMS-Source/careprep/../careprep/utilities/decorators.py" in _dec 14. return view_func(request, *args, **kwargs) File "/home/user/slave/old_careprep/CPMS-Source/careprep/../careprep/visit/views.py" in setup 202. patient.save() File "/usr/local/lib/python2.7/dist-packages/django/db/models/base.py" in save 460. self.save_base(using=using, force_insert=force_insert, force_update=force_update) File "/usr/local/lib/python2.7/dist-packages/django/db/models/base.py" in save_base 553. result = manager._insert(values, return_id=update_pk, using=using) File "/usr/local/lib/python2.7/dist-packages/django/db/models/manager.py" in _insert 195. return insert_query(self.model, values, **kwargs) File "/usr/local/lib/python2.7/dist-packages/django/db/models/query.py" in insert_query 1436. return query.get_compiler(using=using).execute_sql(return_id) File "/usr/local/lib/python2.7/dist-packages/django/db/models/sql/compiler.py" in execute_sql 791. cursor = super(SQLInsertCompiler, self).execute_sql(None) File "/usr/local/lib/python2.7/dist-packages/django/db/models/sql/compiler.py" in execute_sql 735. cursor.execute(sql, params) File "/usr/local/lib/python2.7/dist-packages/django/db/backends/util.py" in execute 34. return self.cursor.execute(sql, params) File "/usr/local/lib/python2.7/dist-packages/django/db/backends/postgresql_psycopg2/base.py" in execute 44. return self.cursor.execute(query, args)
Exception Type: DatabaseError at /visit/setup/ Exception Value: invalid input syntax for type date: "$AES$55403376ed906e119b0f7779554fbb51" LINE 1: ...L, NULL, '$AES$0452edae035cc33c4084e7b0fb39edd7', '$AES$5540... ^ Help will be appreciated.
Thanks
Upvotes: 0
Views: 426
Reputation: 970
Solution in short
Use custom encryption fields
Here's an example for EncryptedCharField
and EncryptedDateField
class EncryptedCharField(CharField):
def _get_cipher(self):
return Fernet(SECRET_KEY)
def from_db_value(self, value, expression, connection):
cipher = self._get_cipher()
if value:
return cipher.decrypt(value.encode()).decode()
return value
def get_prep_value(self, value):
if value:
cipher = self._get_cipher()
return cipher.encrypt(value.encode()).decode()
return value
class EncryptedDateField(DateField):
def _get_cipher(self):
return Fernet(SECRET_KEY)
def to_python(self, value: Any) -> Any:
cipher = self._get_cipher()
if value:
date = cipher.decrypt(value.encode()).decode()
return datetime.datetime.strptime(date, "%Y-%m-%d").date()
return value
def from_db_value(self, value, expression, connection):
return self.to_python(value)
def get_prep_value(self, value):
if value:
cipher = self._get_cipher()
return cipher.encrypt(str(value).encode()).decode()
return value
def get_internal_type(self):
return "TextField"
Explaination -
Data in CharFields are expected to be strings, when you're using EncryptedCharField
the encrypted data is being stored as string in database.
for eg. in field gender
value (Male
) will be stored in encrypted form gAAAAABktoZJ-fQdjJH4OgPs3riR2Fg6vqgUhduunXMW3pAYwJ47j1rhAUeXH5dTwT1ZlurteqTpUlm9p8oLJg34hPd5XTtubA==
when you fetch data for this particular value you get gAAAAABktoZJ-fQdjJH4OgPs3riR2Fg6vqgUhduunXMW3pAYwJ47j1rhAUeXH5dTwT1ZlurteqTpUlm9p8oLJg34hPd5XTtubA==
and then you decrypt it.
in case of date_of_birth
field, when you try to encrypt data it will break, because encryption algorithms works on bytes type.
for fields expecting strings (CharField or TextField)
encode -> encrypt -> decode -> save
.
for fields like DateTime, JSONField, BooleanField
etc.
convert in string -> encode -> encrypt -> decode -> save
.
Upvotes: 0
Reputation: 261
I realised that i was using DateField earlier if i convert DateField to CharField and then apply EncryptedCharField it solves my problem
Upvotes: 1