2020from cassandra .policies import ColDesc
2121
2222from cassandra .column_encryption .policies import AES256ColumnEncryptionPolicy , \
23- AES256_KEY_SIZE_BYTES
23+ AES256_KEY_SIZE_BYTES , AES256_BLOCK_SIZE_BYTES
2424
2525def setup_module ():
2626 use_singledc ()
@@ -32,25 +32,28 @@ def _recreate_keyspace(self, session):
3232 session .execute ("CREATE KEYSPACE foo WITH replication = {'class': 'SimpleStrategy', 'replication_factor': '1'}" )
3333 session .execute ("CREATE TABLE foo.bar(encrypted blob, unencrypted int, primary key(unencrypted))" )
3434
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+
3541 def test_end_to_end_prepared (self ):
3642
3743 # We only currently perform testing on a single type/expected value pair since CLE functionality is essentially
3844 # independent of the underlying type. We intercept data after it's been encoded when it's going out and before it's
3945 # 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
4247
4348 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 )
4850 cluster = TestCluster (column_encryption_policy = cl_policy )
4951 session = cluster .connect ()
5052 self ._recreate_keyspace (session )
5153
5254 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 ))
5457
5558 # A straight select from the database will now return the decrypted bits. We select both encrypted and unencrypted
5659 # 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):
6669
6770 def test_end_to_end_simple (self ):
6871
69- expected = 67890
70- expected_type = "int"
72+ expected = 1
7173
7274 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 )
7776 cluster = TestCluster (column_encryption_policy = cl_policy )
7877 session = cluster .connect ()
7978 self ._recreate_keyspace (session )
8079
8180 # 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 ))
8385
8486 # A straight select from the database will now return the decrypted bits. We select both encrypted and unencrypted
8587 # 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):
9294 (encrypted ,unencrypted ) = session .execute (prepared , [expected ]).one ()
9395 self .assertEquals (expected , encrypted )
9496 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