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

Revision 336, 3.3 kB (checked in by ged, 7 years ago)

update Elixir to work with SA0.5

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.. sourcecode:: python
13
14    from elixir import *
15    from elixir.ext.encrypted import acts_as_encrypted
16   
17    class Person(Entity):
18        name = Field(Unicode)
19        password = Field(Unicode)
20        ssn = Field(Unicode)
21        acts_as_encrypted(for_columns=['password', 'ssn'],
22                          with_secret='secret')
23
24The above Person entity will automatically encrypt and decrypt the password and
25ssn columns on save, update, and load.  Different secrets can be specified on
26an entity by entity basis, for added security.
27'''
28
29from Crypto.Cipher          import Blowfish 
30from elixir.statements      import Statement
31from sqlalchemy.orm         import MapperExtension, EXT_CONTINUE
32
33__all__ = ['acts_as_encrypted']
34__doc_all__ = []
35
36
37#
38# encryption and decryption functions
39#
40
41def encrypt_value(value, secret):
42    return Blowfish.new(secret, Blowfish.MODE_CFB) \
43                   .encrypt(value).encode('string_escape')
44
45def decrypt_value(value, secret):
46    return Blowfish.new(secret, Blowfish.MODE_CFB) \
47                   .decrypt(value.decode('string_escape'))
48
49
50#
51# acts_as_encrypted statement
52#
53
54class ActsAsEncrypted(object):   
55
56    def __init__(self, entity, for_fields=[], with_secret='abcdef'):
57       
58        def perform_encryption(instance, decrypt=False):
59            for column_name in for_fields:
60                current_value = getattr(instance, column_name)
61                if current_value:
62                    if decrypt:
63                        new_value = decrypt_value(current_value, with_secret)
64                    else:
65                        new_value = encrypt_value(current_value, with_secret)
66                    setattr(instance, column_name, new_value)
67       
68        def perform_decryption(instance):
69            perform_encryption(instance, decrypt=True)
70       
71        class EncryptedMapperExtension(MapperExtension):           
72           
73            def before_insert(self, mapper, connection, instance):
74                perform_encryption(instance)
75                return EXT_CONTINUE
76           
77            def before_update(self, mapper, connection, instance):       
78                perform_encryption(instance)
79                return EXT_CONTINUE
80           
81            def populate_instance(self, mapper, selectcontext, row, instance, 
82                                  *args, **kwargs):
83                #FIXME: this is not available anymore in 0.5
84                #<jek> Gedd: on_load will do what you want here. 
85                #the example in test/orm/instrumentation is the most succinct
86                mapper.populate_instance(selectcontext, instance, row, 
87                                         *args, **kwargs)
88                perform_decryption(instance)
89                return True
90       
91        # make sure that the entity's mapper has our mapper extension
92        entity._descriptor.add_mapper_extension(EncryptedMapperExtension())
93
94
95acts_as_encrypted = Statement(ActsAsEncrypted)
Note: See TracBrowser for help on using the browser.