Login

Encrypted Custom Model Field

Author:
ncristian
Posted:
August 17, 2014
Language:
Python
Version:
1.6
Tags:
custom-model-field encrypted
Score:
1 (after 1 ratings)

Custom model field to support two ways encryption. The key is provided in the app settings.py file. It should be at least 32 chars.

usage

Assuming that you placed the new code into fields.py

from app.fields import EncyptedField

class Account(models.Model):
    password = EncryptedField()
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# -*- coding: utf-8 -*-

import types
import base64

from Crypto import Random
from Crypto.Cipher import AES

from django.db import models
from app.settings import FIELD_ENCRYPTION_KEY


class EncryptedField(models.Field):
    __metaclass__ = models.SubfieldBase

    def __init__(self, *args, **kwargs):
        self.prefix = kwargs.pop('prefix', '_')
        super(EncryptedField, self).__init__(*args, **kwargs)

    def get_internal_type(self):
        return 'TextField'

    def to_python(self, value):
        if value is None or not isinstance(value, types.StringTypes):
            return value

        if self.is_encrypted(value):
            value = value[len(self.prefix):]    # cut prefix
            value = base64.b64decode(value)

            iv, encrypted = value[:AES.block_size], value[AES.block_size:]  # extract iv

            crypto = AES.new(FIELD_ENCRYPTION_KEY[:32], AES.MODE_CBC, iv)
            raw_decrypted = crypto.decrypt(encrypted)
            value = raw_decrypted.rstrip("\0").decode('unicode_escape')

        return value

    def get_db_prep_value(self, value, connection, prepared=False):
        if not prepared:
            iv = Random.new().read(AES.block_size)
            crypto = AES.new(FIELD_ENCRYPTION_KEY[:32], AES.MODE_CBC, iv)

            if isinstance(value, types.StringTypes):
                value = value.encode('unicode_escape')
                value = value.encode('ascii')
            else:
                value = str(value)

            tag_value = (value + (AES.block_size - len(value) % AES.block_size) * "\0")
            value = self.prefix + base64.b64encode(iv + crypto.encrypt(tag_value))

        return value

    def is_encrypted(self, value):
        """checks if a string is encrypted against a static predefined prefix"""
        if self.prefix and value.startswith(self.prefix):
            return True
        else:
            return False

More like this

  1. Encryption Fields by zbyte64 6 years, 9 months ago
  2. JSONField by Jasber 6 years, 2 months ago
  3. EncryptField by volksman 6 years, 9 months ago
  4. Transparent encryption for model fields by shadfc 7 years ago
  5. Custom model field to store dict object in database by rudyryk 5 years, 3 months ago

Comments

Please login first before commenting.