1 | import os, os.path, logging |
---|
2 | |
---|
3 | import pkg_resources |
---|
4 | pkg_resources.require( "pycrypto" ) |
---|
5 | |
---|
6 | from Crypto.Cipher import Blowfish |
---|
7 | from Crypto.Util.randpool import RandomPool |
---|
8 | from Crypto.Util import number |
---|
9 | |
---|
10 | log = logging.getLogger( __name__ ) |
---|
11 | |
---|
12 | if os.path.exists( "/dev/urandom" ): |
---|
13 | # We have urandom, use it as the source of random data |
---|
14 | random_fd = os.open( "/dev/urandom", os.O_RDONLY ) |
---|
15 | def get_random_bytes( nbytes ): |
---|
16 | value = os.read( random_fd, nbytes ) |
---|
17 | # Normally we should get as much as we need |
---|
18 | if len( value ) == nbytes: |
---|
19 | return value.encode( "hex" ) |
---|
20 | # If we don't, keep reading (this is slow and should never happen) |
---|
21 | while len( value ) < nbytes: |
---|
22 | value += os.read( random_fd, nbytes - len( value ) ) |
---|
23 | return value.encode( "hex" ) |
---|
24 | else: |
---|
25 | def get_random_bytes( nbytes ): |
---|
26 | nbits = nbytes * 8 |
---|
27 | random_pool = RandomPool( 1064 ) |
---|
28 | while random_pool.entropy < nbits: |
---|
29 | random_pool.add_event() |
---|
30 | random_pool.stir() |
---|
31 | return str( number.getRandomNumber( nbits, random_pool.get_bytes ) ) |
---|
32 | |
---|
33 | class SecurityHelper( object ): |
---|
34 | def __init__( self, **config ): |
---|
35 | self.id_secret = config['id_secret'] |
---|
36 | self.id_cipher = Blowfish.new( self.id_secret ) |
---|
37 | def encode_id( self, obj_id ): |
---|
38 | # Convert to string |
---|
39 | s = str( obj_id ) |
---|
40 | # Pad to a multiple of 8 with leading "!" |
---|
41 | s = ( "!" * ( 8 - len(s) % 8 ) ) + s |
---|
42 | # Encrypt |
---|
43 | return self.id_cipher.encrypt( s ).encode( 'hex' ) |
---|
44 | def decode_id( self, obj_id ): |
---|
45 | return int( self.id_cipher.decrypt( obj_id.decode( 'hex' ) ).lstrip( "!" ) ) |
---|
46 | def decode_string_id( self, obj_id ): |
---|
47 | return self.id_cipher.decrypt( obj_id.decode( 'hex' ) ).lstrip( "!" ) |
---|
48 | def encode_guid( self, session_key ): |
---|
49 | # Session keys are strings |
---|
50 | # Pad to a multiple of 8 with leading "!" |
---|
51 | s = ( "!" * ( 8 - len( session_key ) % 8 ) ) + session_key |
---|
52 | # Encrypt |
---|
53 | return self.id_cipher.encrypt( s ).encode( 'hex' ) |
---|
54 | def decode_guid( self, session_key ): |
---|
55 | # Session keys are strings |
---|
56 | return self.id_cipher.decrypt( session_key.decode( 'hex' ) ).lstrip( "!" ) |
---|
57 | def get_new_guid( self ): |
---|
58 | # Generate a unique, high entropy 128 bit random number |
---|
59 | return get_random_bytes( 16 ) |
---|
60 | |
---|