root / elixir / trunk / elixir / ext / encrypted.py @ 236

Revision 236, 2.9 kB (checked in by ged, 6 years ago)

- migrate to attribute-based syntax in all examples and documentation.
- completed doc

Line 
1'''
2An encryption plugin for Elixir utilizing the excellent PyCrypto library, which
3can be downloaded here: http://www.amk.ca/python/code/crypto
4
5Values for columns that are specified to be encrypted will be transparently
6encrypted and safely encoded for storage in a unicode column using the powerful
7and secure Blowfish Cipher using a specified "secret" which can be passed into
8the plugin at class declaration time.
9
10Example usage:
11
12    from elixir import *
13    from elixir.ext.encrypted import acts_as_encrypted
14   
15    class Person(Entity):
16        name = Field(Unicode)
17        password = Field(Unicode)
18        ssn = Field(Unicode)
19        acts_as_encrypted(for_columns=['password', 'ssn'], with_secret='secret')
20
21The above Person entity will automatically encrypt and decrypt the password and
22ssn columns on save, update, and load.  Different secrets can be specified on
23an entity by entity basis, for added security.
24'''
25
26from Crypto.Cipher          import Blowfish 
27from elixir.statements      import Statement
28from sqlalchemy.orm         import MapperExtension, EXT_PASS
29
30
31#
32# encryption and decryption functions
33#
34
35def encrypt_value(value, secret):
36    return Blowfish.new(secret, Blowfish.MODE_CFB).encrypt(value).encode('string_escape')
37
38def decrypt_value(value, secret):
39    return Blowfish.new(secret, Blowfish.MODE_CFB).decrypt(value.decode('string_escape'))
40
41
42#
43# acts_as_encrypted statement
44#
45
46class ActsAsEncrypted(object):   
47    def __init__(self, entity, for_fields=[], with_secret='abcdef'):
48       
49        def perform_encryption(instance, decrypt=False):
50            for column_name in for_fields:
51                current_value = getattr(instance, column_name)
52                if current_value:
53                    if decrypt:
54                        new_value = decrypt_value(current_value, with_secret)
55                    else:
56                        new_value = encrypt_value(current_value, with_secret)
57                    setattr(instance, column_name, new_value)
58       
59        def perform_decryption(instance):
60            perform_encryption(instance, decrypt=True)
61       
62        class EncryptedMapperExtension(MapperExtension):           
63           
64            def before_insert(self, mapper, connection, instance):
65                perform_encryption(instance)
66                return EXT_PASS
67           
68            def before_update(self, mapper, connection, instance):       
69                perform_encryption(instance)
70                return EXT_PASS
71           
72            def populate_instance(self, mapper, selectcontext, row, instance, *args, **kwargs):
73                mapper.populate_instance(selectcontext, instance, row, *args, **kwargs)
74                perform_decryption(instance)
75                return True
76       
77        # make sure that the entity's mapper has our mapper extension
78        entity._descriptor.add_mapper_extension(EncryptedMapperExtension())
79
80
81acts_as_encrypted = Statement(ActsAsEncrypted)
82
83
84__all__ = [
85    'acts_as_encrypted'
86]
Note: See TracBrowser for help on using the browser.