20
20
from cassandra .policies import ColDesc
21
21
22
22
from cassandra .column_encryption .policies import AES256ColumnEncryptionPolicy , \
23
- AES256_KEY_SIZE_BYTES
23
+ AES256_KEY_SIZE_BYTES , AES256_BLOCK_SIZE_BYTES
24
24
25
25
def setup_module ():
26
26
use_singledc ()
@@ -32,25 +32,28 @@ def _recreate_keyspace(self, session):
32
32
session .execute ("CREATE KEYSPACE foo WITH replication = {'class': 'SimpleStrategy', 'replication_factor': '1'}" )
33
33
session .execute ("CREATE TABLE foo.bar(encrypted blob, unencrypted int, primary key(unencrypted))" )
34
34
35
+ def _create_policy (self , key , iv = None ):
36
+ cl_policy = AES256ColumnEncryptionPolicy ()
37
+ col_desc = ColDesc ('foo' ,'bar' ,'encrypted' )
38
+ cl_policy .add_column (col_desc , key , "int" )
39
+ return (col_desc , cl_policy )
40
+
35
41
def test_end_to_end_prepared (self ):
36
42
37
43
# We only currently perform testing on a single type/expected value pair since CLE functionality is essentially
38
44
# independent of the underlying type. We intercept data after it's been encoded when it's going out and before it's
39
45
# encoded when coming back; the actual types of the data involved don't impact us.
40
- expected = 12345
41
- expected_type = "int"
46
+ expected = 0
42
47
43
48
key = os .urandom (AES256_KEY_SIZE_BYTES )
44
- cl_policy = AES256ColumnEncryptionPolicy ()
45
- col_desc = ColDesc ('foo' ,'bar' ,'encrypted' )
46
- cl_policy .add_column (col_desc , key , expected_type )
47
-
49
+ (_ , cl_policy ) = self ._create_policy (key )
48
50
cluster = TestCluster (column_encryption_policy = cl_policy )
49
51
session = cluster .connect ()
50
52
self ._recreate_keyspace (session )
51
53
52
54
prepared = session .prepare ("insert into foo.bar (encrypted, unencrypted) values (?,?)" )
53
- session .execute (prepared , (expected ,expected ))
55
+ for i in range (100 ):
56
+ session .execute (prepared , (i , i ))
54
57
55
58
# A straight select from the database will now return the decrypted bits. We select both encrypted and unencrypted
56
59
# values here to confirm that we don't interfere with regular processing of unencrypted vals.
@@ -66,20 +69,19 @@ def test_end_to_end_prepared(self):
66
69
67
70
def test_end_to_end_simple (self ):
68
71
69
- expected = 67890
70
- expected_type = "int"
72
+ expected = 1
71
73
72
74
key = os .urandom (AES256_KEY_SIZE_BYTES )
73
- cl_policy = AES256ColumnEncryptionPolicy ()
74
- col_desc = ColDesc ('foo' ,'bar' ,'encrypted' )
75
- cl_policy .add_column (col_desc , key , expected_type )
76
-
75
+ (col_desc , cl_policy ) = self ._create_policy (key )
77
76
cluster = TestCluster (column_encryption_policy = cl_policy )
78
77
session = cluster .connect ()
79
78
self ._recreate_keyspace (session )
80
79
81
80
# Use encode_and_encrypt helper function to populate date
82
- session .execute ("insert into foo.bar (encrypted, unencrypted) values (%s,%s)" ,(cl_policy .encode_and_encrypt (col_desc , expected ), expected ))
81
+ for i in range (1 ,100 ):
82
+ self .assertIsNotNone (i )
83
+ encrypted = cl_policy .encode_and_encrypt (col_desc , i )
84
+ session .execute ("insert into foo.bar (encrypted, unencrypted) values (%s,%s)" , (encrypted , i ))
83
85
84
86
# A straight select from the database will now return the decrypted bits. We select both encrypted and unencrypted
85
87
# values here to confirm that we don't interfere with regular processing of unencrypted vals.
@@ -92,3 +94,42 @@ def test_end_to_end_simple(self):
92
94
(encrypted ,unencrypted ) = session .execute (prepared , [expected ]).one ()
93
95
self .assertEquals (expected , encrypted )
94
96
self .assertEquals (expected , unencrypted )
97
+
98
+ def test_end_to_end_different_cle_contexts (self ):
99
+
100
+ expected = 2
101
+
102
+ key = os .urandom (AES256_KEY_SIZE_BYTES )
103
+
104
+ # Simulate the creation of two AES256 policies at two different times. Python caches
105
+ # default param args at function definition time so a single value will be used any time
106
+ # the default val is used. Upshot is that within the same test we'll always have the same
107
+ # IV if we rely on the default args, so manually introduce some variation here to simulate
108
+ # what actually happens if you have two distinct sessions created at two different times.
109
+ iv1 = os .urandom (AES256_BLOCK_SIZE_BYTES )
110
+ (col_desc1 , cl_policy1 ) = self ._create_policy (key , iv = iv1 )
111
+ cluster1 = TestCluster (column_encryption_policy = cl_policy1 )
112
+ session1 = cluster1 .connect ()
113
+ self ._recreate_keyspace (session1 )
114
+
115
+ # Use encode_and_encrypt helper function to populate date
116
+ for i in range (1 ,100 ):
117
+ self .assertIsNotNone (i )
118
+ encrypted = cl_policy1 .encode_and_encrypt (col_desc1 , i )
119
+ session1 .execute ("insert into foo.bar (encrypted, unencrypted) values (%s,%s)" , (encrypted , i ))
120
+ session1 .shutdown ()
121
+ cluster1 .shutdown ()
122
+
123
+ # Explicitly clear the class-level cache here; we're trying to simulate a second connection from a completely new process and
124
+ # that would entail not re-using any cached ciphers
125
+ AES256ColumnEncryptionPolicy ._build_cipher .cache_clear ()
126
+ cache_info = cl_policy1 .cache_info ()
127
+ self .assertEqual (cache_info .currsize , 0 )
128
+
129
+ iv2 = os .urandom (AES256_BLOCK_SIZE_BYTES )
130
+ (_ , cl_policy2 ) = self ._create_policy (key , iv = iv2 )
131
+ cluster2 = TestCluster (column_encryption_policy = cl_policy2 )
132
+ session2 = cluster2 .connect ()
133
+ (encrypted ,unencrypted ) = session2 .execute ("select encrypted, unencrypted from foo.bar where unencrypted = %s allow filtering" , (expected ,)).one ()
134
+ self .assertEquals (expected , encrypted )
135
+ self .assertEquals (expected , unencrypted )
0 commit comments