예제 #1
0
 def test_unpadder_invalid_token(self):
     data = ('8000000000075bcd15303132333435363738396162636465660ecd40b0f64'
             '8f001b78b5a77b334b40fbbff559444b3325233e71c24e53f6028116b0377'
             'b910ebe5498396de36dee59b')
     with freeze_time(123456789):
         fernet = FernetBytes()
         with self.assertRaises(InvalidToken):
             fernet.decrypt(binascii.unhexlify(data))
예제 #2
0
 def test_decryptor_invalid_token(self):
     data = ('8000000000075bcd153031323334353637383961626364656629b930b1955'
             'ddaec2d74fb4ff565d549d94cc75de940d1d25507f30763f05c412390d15d'
             'a26bccee69f1b4543e75')
     with freeze_time(123456789):
         fernet = FernetBytes()
         with self.assertRaises(InvalidToken):
             fernet.decrypt(binascii.unhexlify(data))
예제 #3
0
 def test_unpadder_invalid_token(self):
     data = ('8000000000075bcd15303132333435363738396162636465660ecd40b0f64'
             '8f001b78b5a77b334b40fbbff559444b3325233e71c24e53f6028116b0377'
             'b910ebe5498396de36dee59b')
     with freeze_time(123456789):
         fernet = FernetBytes()
         with self.assertRaises(InvalidToken):
             fernet.decrypt(binascii.unhexlify(data))
예제 #4
0
 def test_decryptor_invalid_token(self):
     data = ('8000000000075bcd153031323334353637383961626364656629b930b1955'
             'ddaec2d74fb4ff565d549d94cc75de940d1d25507f30763f05c412390d15d'
             'a26bccee69f1b4543e75')
     with freeze_time(123456789):
         fernet = FernetBytes()
         with self.assertRaises(InvalidToken):
             fernet.decrypt(binascii.unhexlify(data))
예제 #5
0
 def test_encrypt_decrypt(self):
     value = b'hello'
     iv = b'0123456789abcdef'
     data = ('8000000000075bcd153031323334353637383961626364656629b930b1955'
             'ddaec2d74fb4ff565280abdc39baf116e80f116496cde9515bd7d938e5c74'
             'd60bc186286e701ba4fb4004')
     with freeze_time(123456789):
         fernet = FernetBytes()
         self.assertEqual(fernet._encrypt_from_parts(value, iv),
                          binascii.unhexlify(data))
         self.assertEqual(fernet.decrypt(binascii.unhexlify(data)), value)
예제 #6
0
 def test_encrypt_decrypt(self):
     value = b'hello'
     iv = b'0123456789abcdef'
     data = ('8000000000075bcd153031323334353637383961626364656629b930b1955'
             'ddaec2d74fb4ff565280abdc39baf116e80f116496cde9515bd7d938e5c74'
             'd60bc186286e701ba4fb4004')
     with freeze_time(123456789):
         fernet = FernetBytes()
         self.assertEqual(fernet._encrypt_from_parts(value, iv),
                          binascii.unhexlify(data))
         self.assertEqual(fernet.decrypt(binascii.unhexlify(data)), value)
예제 #7
0
class EncryptedMixin(object):
    """
    A field mixin storing encrypted data

    :param bytes key: This is an optional argument.

        Allows for specifying an instance specific encryption key.
    :param int ttl: This is an optional argument.

        The amount of time in seconds that a value can be stored for. If the
        time to live of the data has passed, it will become unreadable.
        The expired value will return an :class:`Expired` object.
    """
    supported_lookups = ('isnull', )

    def __init__(self, *args, **kwargs):
        self.key = kwargs.pop('key', None)
        self.ttl = kwargs.pop('ttl', None)

        self._fernet = FernetBytes(self.key)
        super(EncryptedMixin, self).__init__(*args, **kwargs)

    @property
    def description(self):
        return _('Encrypted %s') % super(EncryptedMixin, self).description

    def _dump(self, value):
        return self._fernet.encrypt(pickle.dumps(value))

    def _load(self, value):
        try:
            return pickle.loads(self._fernet.decrypt(value, self.ttl))
        except SignatureExpired:
            return Expired

    def check(self, **kwargs):
        errors = super(EncryptedMixin, self).check(**kwargs)
        # Django 1.8 compatibility for `self.rel`
        if getattr(self, 'remote_field', getattr(self, 'rel', None)):
            errors.append(
                checks.Error(
                    'Base field for encrypted cannot be a related field.',
                    hint=None,
                    obj=self,
                    id='encrypted.E002'))
        return errors

    def clone(self):
        name, path, args, kwargs = super(EncryptedMixin, self).deconstruct()
        # Determine if the class that subclassed us has been subclassed.
        if not self.__class__.__mro__.index(EncryptedMixin) > 1:
            return encrypt(
                self.base_class(*args, **kwargs), self.key, self.ttl)
        return self.__class__(*args, **kwargs)

    def deconstruct(self):
        name, path, args, kwargs = super(EncryptedMixin, self).deconstruct()
        # Determine if the class that subclassed us has been subclassed.
        if not self.__class__.__mro__.index(EncryptedMixin) > 1:
            path = "%s.%s" % (encrypt.__module__, encrypt.__name__)
            args = [self.base_class(*args, **kwargs)]
            kwargs = {}
            if self.ttl is not None:
                kwargs['ttl'] = self.ttl
        return name, path, args, kwargs

    def get_lookup(self, lookup_name):
        if lookup_name not in self.supported_lookups:
            return
        return super(EncryptedMixin, self).get_lookup(lookup_name)

    def get_transform(self, lookup_name):
        if lookup_name not in self.supported_lookups:
            return
        return super(EncryptedMixin, self).get_transform(lookup_name)

    def get_internal_type(self):
        return "BinaryField"

    def get_db_prep_value(self, value, connection, prepared=False):
        value = models.Field.get_db_prep_value(self, value, connection,
                                               prepared)
        if value is not None:
            return connection.Database.Binary(self._dump(value))
        return value

    get_db_prep_save = models.Field.get_db_prep_save

    def from_db_value(self, value, expression, connection, context):
        if value is not None:
            return self._load(force_bytes(value))
        return value
예제 #8
0
class EncryptedMixin:
    """
    A field mixin storing encrypted data

    :param bytes key: This is an optional argument.

        Allows for specifying an instance specific encryption key.
    :param int ttl: This is an optional argument.

        The amount of time in seconds that a value can be stored for. If the
        time to live of the data has passed, it will become unreadable.
        The expired value will return an :class:`Expired` object.
    """
    supported_lookups = ('isnull', )

    def __init__(self, *args, **kwargs):
        self.key = kwargs.pop('key', None)
        self.ttl = kwargs.pop('ttl', None)

        self._fernet = FernetBytes(self.key)
        super(EncryptedMixin, self).__init__(*args, **kwargs)

    @property
    def description(self):
        return _('Encrypted %s') % super(EncryptedMixin, self).description

    def _dump(self, value):
        return self._fernet.encrypt(pickle.dumps(value))

    def _load(self, value):
        try:
            return pickle.loads(self._fernet.decrypt(value, self.ttl))
        except SignatureExpired:
            return Expired

    def check(self, **kwargs):
        errors = super(EncryptedMixin, self).check(**kwargs)
        if getattr(self, 'remote_field', None):
            errors.append(
                checks.Error(
                    'Base field for encrypted cannot be a related field.',
                    hint=None,
                    obj=self,
                    id='encrypted.E002'))
        return errors

    def clone(self):
        name, path, args, kwargs = super(EncryptedMixin, self).deconstruct()
        # Determine if the class that subclassed us has been subclassed.
        if not self.__class__.__mro__.index(EncryptedMixin) > 1:
            return encrypt(self.base_class(*args, **kwargs), self.key,
                           self.ttl)
        return self.__class__(*args, **kwargs)

    def deconstruct(self):
        name, path, args, kwargs = super(EncryptedMixin, self).deconstruct()
        # Determine if the class that subclassed us has been subclassed.
        if not self.__class__.__mro__.index(EncryptedMixin) > 1:
            path = "%s.%s" % (encrypt.__module__, encrypt.__name__)
            args = [self.base_class(*args, **kwargs)]
            kwargs = {}
            if self.ttl is not None:
                kwargs['ttl'] = self.ttl
        return name, path, args, kwargs

    def get_lookup(self, lookup_name):
        if lookup_name not in self.supported_lookups:
            return
        return super(EncryptedMixin, self).get_lookup(lookup_name)

    def get_transform(self, lookup_name):
        if lookup_name not in self.supported_lookups:
            return
        return super(EncryptedMixin, self).get_transform(lookup_name)

    def get_internal_type(self):
        return "BinaryField"

    def get_db_prep_value(self, value, connection, prepared=False):
        value = models.Field.get_db_prep_value(self, value, connection,
                                               prepared)
        if value is not None:
            return connection.Database.Binary(self._dump(value))
        return value

    get_db_prep_save = models.Field.get_db_prep_save

    def from_db_value(self, value, *args, **kwargs):
        if value is not None:
            return self._load(force_bytes(value))
        return value
예제 #9
0
class EncryptedField(models.Field):
    @property
    def description(self):
        return _('Encrypted %s') % self.base_field.description

    def __init__(self, base_field, **kwargs):
        """
        :type base_field: django.db.models.fields.Field
        :rtype: None
        """
        key = kwargs.pop('key', None)
        ttl = kwargs.pop('ttl', None)

        self._fernet = FernetBytes(key)
        self._ttl = ttl
        self.base_field = base_field
        super(EncryptedField, self).__init__(**kwargs)

    @property
    def model(self):
        try:
            return self.__dict__['model']
        except KeyError:
            raise AttributeError("'%s' object has no attribute 'model'" %
                                 self.__class__.__name__)

    @model.setter
    def model(self, model):
        self.__dict__['model'] = model
        self.base_field.model = model

    def check(self, **kwargs):
        errors = super(EncryptedField, self).check(**kwargs)
        if getattr(self.base_field, 'remote_field', self.base_field.rel):
            errors.append(
                checks.Error(
                    'Base field for encrypted cannot be a related field.',
                    hint=None,
                    obj=self,
                    id='encrypted.E002'
                )
            )
        else:
            # Remove the field name checks as they are not needed here.
            base_errors = self.base_field.check()
            if base_errors:
                messages = '\n    '.join('%s (%s)' % (error.msg, error.id) for error in base_errors)
                errors.append(
                    checks.Error(
                        'Base field for encrypted has errors:\n    %s' % messages,
                        hint=None,
                        obj=self,
                        id='encrypted.E001'
                    )
                )
        return errors

    def deconstruct(self):
        name, path, args, kwargs = super(EncryptedField, self).deconstruct()
        kwargs.update({
            'base_field': self.base_field,
        })
        return name, path, args, kwargs

    def run_validators(self, value):
        super(EncryptedField, self).run_validators(value)
        self.base_field.run_validators(value)

    def validate(self, value, model_instance):
        super(EncryptedField, self).validate(value, model_instance)
        self.base_field.validate(value, model_instance)

    def set_attributes_from_name(self, name):
        super(EncryptedField, self).set_attributes_from_name(name)
        self.base_field.set_attributes_from_name(name)

    def get_internal_type(self):
        return "BinaryField"

    def pre_save(self, model_instance, add):
        return self._fernet.encrypt(
            pickle.dumps(self.base_field.pre_save(model_instance, add)))

    def get_db_prep_value(self, value, connection, prepared=False):
        value = super(EncryptedField, self).get_db_prep_value(value, connection, prepared)
        if value is not None:
            return connection.Database.Binary(value)
        return value

    def from_db_value(self, value, expression, connection, context):
        if value:
            try:
                return pickle.loads(self._fernet.decrypt(value, self._ttl))
            except SignatureExpired:
                return Expired
        return value