def test_initialize_many(self): """ Check that multiple keys generated, wrapped with users' public keys, and stored in a keystore can be retrieved and unwrapped with the users' secret keys. """ keygen = KeyGen('Sixteen byte key') keystore = DummyKeyStore() key_infos = [('attr' + str(i), i, 'meta' + str(i), 16) for i in xrange(self.num_keys)] users = {} RSA_sks = {} for i in xrange(self.num_users): userid = 'user' + str(i) RSA_key = RSA.generate(3072) RSA_sks[userid] = RSA_key RSA_pk = RSA_key.publickey() info = random.sample(key_infos, random.randint(1, len(key_infos))) users[userid] = (RSA_pk, info) keygen.initialize_users(users, keystore) for userid in users: RSA_pk, info = users[userid] for attr, vers, meta, keylen in info: keywrap = keystore.retrieve(userid, attr, vers, meta) self.assertEqual( utils.unwrap_key(keywrap, RSA_sks[userid]), keygen._generate_key(attr, vers, meta, keylen))
def test_init_many_from_file(self): """ Check that multiple keys generated, wrapped with users' public keys, and stored in a keystore can be retrieved and unwrapped with the users' secret keys when input comes from a configuration file. """ keygen = KeyGen('Sixteen byte key') keystore = DummyKeyStore() user_info = { 'user1': [('attr1', 1, 'AES_GCM', 16), ('attr2', 1, 'AES_GCM', 16), ('attr3', 2, 'AES_GCM', 16)], 'user2': [('attr2', 1, 'AES_GCM', 16), ('attr4', 2, 'AES_GCM', 16)], 'user3': [('attr1', 1, 'AES_GCM', 16), ('attr4', 2, 'AES_GCM', 16)] } self.create_configs_from_dict(user_info, TMP_PATH + '/user_info_test.cfg') keygen.init_from_file(TMP_PATH + '/user_info_test.cfg', keystore) for userid in user_info: key_infos = user_info[userid] f = open(TMP_PATH + '/' + userid + '_privkey.pem', 'r') RSA_sk = RSA.importKey(f.read()) f.close() for attr, vers, meta, keylen in key_infos: keywrap = keystore.retrieve(userid, attr, vers, meta) self.assertEqual( utils.unwrap_key(keywrap, RSA_sk), keygen._generate_key(attr, vers, meta, keylen))
def test_equal_inputs(self): """ Check that the same inputs result in the same key. """ keygen = KeyGen('Sixteen byte key') key1 = keygen._generate_key('attr', 1, 'metadata', 16) key2 = keygen._generate_key('attr', 1, 'metadata', 16) self.assertEqual(key1, key2)
def test_keylen(self): """ Check that generated keys are of expected length. """ keygen = KeyGen('Sixteen byte key') for i in xrange(65): key = keygen._generate_key('attr', 1, 'metadata', i) self.assertEqual(i, len(key))
def test_diff_keylens_same_info(self): """ Check that keys generated for the same attribute, version, and metadata but different key lengths do not have a common prefix of the shorter key length. """ keygen = KeyGen('Sixteen byte key') key1 = keygen._generate_key('attr', 1, 'metadata', 16) key2 = keygen._generate_key('attr', 1, 'metadata', 32) self.assertNotEqual(key1, key2[:16])
def test_initialize_single(self): """ Check that a key generated, wrapped with a user's public key, and stored in a keystore can be retrieved and unwrapped with the user's secret key. """ RSA_key = RSA.generate(3072) RSA_pk = RSA_key.publickey() keygen = KeyGen('Sixteen byte key') keystore = DummyKeyStore() orig_key = keygen._generate_key('attr', 1, 'meta', 16) keygen.initialize_users( {'userid': (RSA_pk, [('attr', 1, 'meta', 16)])}, keystore) keywrap = keystore.retrieve('userid', 'attr', 1, 'meta') self.assertEqual(utils.unwrap_key(keywrap, RSA_key), orig_key)
def run_pki_insert(genpath=DEMO_USERS, user='******', conn=None): """ Insert elements into the PKI as specified by the config file located at genpath. Returns: ks - the keystore object initialized this way """ if conn is None: print 'Logging in to Accumulo...' conn = pyaccumulo.Accumulo(host='localhost', port=42424, user='******', password='******') print 'Logged in. Creating key store...' print 'Deleting existing metadata tables' for table_name in ['__VERSION_METADATA__','__ATTR_TABLE__','__KEYWRAP_METADATA__']: if conn.table_exists(table_name): print 'Deleting table ', table_name conn.delete_table(table_name) ks = AccumuloAttrKeyStore(conn) print 'Key store created.' print master_secret = 'master secret key' print 'Initializing key store with dummy master secret "master secret key"...' kg = KeyGen(master_secret) users = KeyGen.file_to_dict(genpath) for _, infos in users.itervalues(): for _, _, metadata, _ in infos: if conn.table_exists(metadata): print ' Found existing table:', metadata print ' Deleting to have a clean slate.' conn.delete_table(metadata) kg.initialize_users(users, ks) #get private keys to unwrap things f = open(PRIV_KEYS+user+'_privkey.pem','r') priv_key = RSA.importKey(f.read()) print 'Key store initialized.' return EncryptionPKIAccumulo(conn, user, priv_key), KeyStoreFrontEnd(ks)
def test_diff_inputs(self): """ Check that different inputs result in different keys. """ keygen = KeyGen('Sixteen byte key') key1 = keygen._generate_key('attr1', 1, 'metadata', 16) key2 = keygen._generate_key('attr2', 1, 'metadata', 16) self.assertNotEqual(key1, key2) key1 = keygen._generate_key('attr', 2, 'metadata', 16) key2 = keygen._generate_key('attr', 3, 'metadata', 16) self.assertNotEqual(key1, key2) key1 = keygen._generate_key('attr', 1, 'metadata1', 16) key2 = keygen._generate_key('attr', 1, 'metadata2', 16) self.assertNotEqual(key1, key2)
def run_revoke(user, attr, genpath=DEMO_USERS, conn=None): if conn is None: conn = pyaccumulo.Accumulo(host='localhost', port=42424, user='******', password='******') ks = AccumuloAttrKeyStore(conn) master_secret = 'master secret key' kg = KeyGen(master_secret) users = KeyGen.file_to_dict(genpath) user_keys = {} for k_user, k_tuple in users.iteritems(): user_keys[k_user] = k_tuple[0] print "Revoking user %s's access to attribute %s." %(user, attr) kg.revoke(user, attr, ks, ks, ks, user_keys)
def test_nonexistent_publickey_file(self): """ Check that creating a dictionary from a configuration file that does not exist raises an IOError. """ keygen = KeyGen('Sixteen byte key') f = open(TMP_PATH + '/user_info_nonexistent.cfg', 'w') f.write('[userA]\n') f.write('public_key: user1_nonexistent.pem\n') f.write('key_info: attr1|v1|AES_GCM|16') f.close() try: users = keygen.file_to_dict(TMP_PATH + '/user_info_nonexistent.cfg') except IOError: self.assertTrue(True, 'error') else: self.assertTrue( False, 'No error raised on a nonexistent public key file')
def test_initialize_diff_users_same_info(self): """ Check that two different users can recover the same key for the same attribute, version, metadata, key length combination. """ RSA_key1 = RSA.generate(3072) RSA_pk1 = RSA_key1.publickey() RSA_key2 = RSA.generate(3072) RSA_pk2 = RSA_key2.publickey() keygen = KeyGen('Sixteen byte key') keystore = DummyKeyStore() keygen.initialize_users( { 'user1': (RSA_pk1, [('attr', 1, 'meta', 16)]), 'user2': (RSA_pk2, [('attr', 1, 'meta', 16)]) }, keystore) keywrap1 = keystore.retrieve('user1', 'attr', 1, 'meta') keywrap2 = keystore.retrieve('user2', 'attr', 1, 'meta') self.assertEqual(utils.unwrap_key(keywrap1, RSA_key1), utils.unwrap_key(keywrap2, RSA_key2))
def test_initialize_empty(self): """ Check that a key generated from empty string inputs, wrapped with a user's public key, and stored in a keystore can be retrieved and unwrapped with the user's secret key. """ RSA_key = RSA.generate(3072) RSA_pk = RSA_key.publickey() keygen = KeyGen('Sixteen byte key') keystore = DummyKeyStore() params = [('', 'attr', 1, 'meta'), ('userid', '', 1, 'meta'), ('userid', 'attr', 0, 'meta'), ('userid', 'attr', 1, ''), ('', '', 0, '')] for userid, attr, vers, meta in params: orig_key = keygen._generate_key(attr, vers, meta, 16) keygen.initialize_users( {userid: (RSA_pk, [(attr, vers, meta, 16)])}, keystore) keywrap = keystore.retrieve(userid, attr, vers, meta) self.assertEqual(utils.unwrap_key(keywrap, RSA_key), orig_key)
def test_diff_keygens(self): """ Check that key generators with different master secret keys result in different keys. """ keygen1 = KeyGen('Sixteen byte key') keygen2 = KeyGen('sixteen byte key') key1 = keygen1._generate_key('attr', 1, 'metadata', 16) key2 = keygen2._generate_key('attr', 1, 'metadata', 16) self.assertNotEqual(key1, key2)
def test_revocation_all_attrs(self): """ Tests that revoking all of a user's attributes removes the appropriate entries from the keystore and the user/attr maps and generates wraps of new keys for the correct set of users. """ keygen = KeyGen('Sixteen byte key') ks = DummyKeyStore() attr_user_dict = { 'A': ['user1', 'user2', 'user3'], 'B': ['user1', 'user2'], 'C': ['user1', 'user3'] } attr_user_map = LocalAttrUserMap(attr_user_dict) user_attr_dict = { 'user1': ['A', 'B', 'C'], 'user2': ['A', 'B'], 'user3': ['A', 'C'] } user_attr_map = LocalUserAttrMap(user_attr_dict) user_sks = {} user_pks = {} for i in range(1, 4): userid = 'user' + str(i) RSA_key = RSA.generate(3072) user_sks[userid] = RSA_key RSA_pk = RSA_key.publickey() user_pks[userid] = RSA_pk key_infos = { 'user1': [ KeyInfo('A', 1, 'meta1', 'keywrap1', 16), KeyInfo('A', 1, 'meta2', 'keywrap2', 16), KeyInfo('B', 1, 'meta1', 'keywrap4', 16), KeyInfo('B', 1, 'meta2', 'keywrap5', 16), KeyInfo('C', 1, 'meta1', 'keywrap6', 16), KeyInfo('C', 1, 'meta2', 'keywrap7', 16) ], 'user2': [ KeyInfo('A', 1, 'meta2', 'keywrap8', 16), KeyInfo('A', 1, 'meta3', 'keywrap9', 16), KeyInfo('B', 1, 'meta1', 'keywrap10', 16), KeyInfo('B', 1, 'meta2', 'keywrap11', 16) ], 'user3': [ KeyInfo('A', 1, 'meta1', 'keywrap12', 16), KeyInfo('A', 1, 'meta2', 'keywrap13', 16), KeyInfo('A', 1, 'meta3', 'keywrap14', 16), KeyInfo('C', 1, 'meta1', 'keywrap15', 16), KeyInfo('C', 1, 'meta2', 'keywrap16', 16) ] } for user in key_infos: ks.batch_insert(user, key_infos[user]) #revoke all attributes from a user keygen.revoke_all_attrs('user1', ks, attr_user_map, user_attr_map, user_pks) #check that keywraps for revoked user were removed from keystore for i in range(1, 3): self.assertRaises(PKILookupError, ks.retrieve, 'user1', 'A', 1, 'meta' + str(i)) self.assertRaises(PKILookupError, ks.retrieve, 'user1', 'B', 1, 'meta' + str(i)) self.assertRaises(PKILookupError, ks.retrieve, 'user1', 'C', 1, 'meta' + str(i)) #check that updated user/attr maps are correct self.assertEqual(set(attr_user_map.users_by_attribute('A')), set(['user2', 'user3'])) self.assertEqual(attr_user_map.users_by_attribute('B'), ['user2']) self.assertEqual(attr_user_map.users_by_attribute('C'), ['user3']) self.assertEqual(user_attr_map.attributes_by_user('user1'), []) self.assertEqual(set(user_attr_map.attributes_by_user('user2')), set(['A', 'B'])) self.assertEqual(set(user_attr_map.attributes_by_user('user3')), set(['A', 'C'])) #check that metadatas for revoked attrs have correct version numbers self.assertEqual(ks.retrieve_latest_version_number('meta1', 'A'), 2) self.assertEqual(ks.retrieve_latest_version_number('meta2', 'A'), 2) self.assertEqual(ks.retrieve_latest_version_number('meta3', 'A'), 1) self.assertEqual(ks.retrieve_latest_version_number('meta1', 'B'), 2) self.assertEqual(ks.retrieve_latest_version_number('meta2', 'B'), 2) #check that other users with revoked attrs got new keywraps that decrypt #to keys of the correct length kw_2_2_A = ks.retrieve_latest_version('user2', 'meta2', 'A').keywrap kw_3_1_A = ks.retrieve_latest_version('user3', 'meta1', 'A').keywrap kw_3_2_A = ks.retrieve_latest_version('user3', 'meta2', 'A').keywrap kw_2_1_B = ks.retrieve_latest_version('user2', 'meta1', 'B').keywrap kw_2_2_B = ks.retrieve_latest_version('user2', 'meta2', 'B').keywrap kw_3_1_C = ks.retrieve_latest_version('user3', 'meta1', 'C').keywrap kw_3_2_C = ks.retrieve_latest_version('user3', 'meta2', 'C').keywrap self.assertEqual(len(utils.unwrap_key(kw_2_2_A, user_sks['user2'])), 16) self.assertEqual(len(utils.unwrap_key(kw_3_1_A, user_sks['user3'])), 16) self.assertEqual(len(utils.unwrap_key(kw_3_2_A, user_sks['user3'])), 16) self.assertEqual(len(utils.unwrap_key(kw_2_1_B, user_sks['user2'])), 16) self.assertEqual(len(utils.unwrap_key(kw_2_2_B, user_sks['user2'])), 16) self.assertEqual(len(utils.unwrap_key(kw_3_1_C, user_sks['user3'])), 16) self.assertEqual(len(utils.unwrap_key(kw_3_2_C, user_sks['user3'])), 16) #revoke all attributes from a user and update some key lengths keylens = {'meta2': 24} keygen.revoke_all_attrs('user2', ks, attr_user_map, user_attr_map, user_pks, keylens) #check that new keys for other users have correct key lengths kw_3_2_A = ks.retrieve_latest_version('user3', 'meta2', 'A').keywrap kw_3_3_A = ks.retrieve_latest_version('user3', 'meta3', 'A').keywrap self.assertEqual(len(utils.unwrap_key(kw_3_2_A, user_sks['user3'])), 24) self.assertEqual(len(utils.unwrap_key(kw_3_3_A, user_sks['user3'])), 16)
def test_negative_keylen(self): """ Check that negative key lengths raise an exception. """ keygen = KeyGen('Sixteen byte key') self.assertRaises(ValueError, keygen._generate_key, 'attr', 1, 'metadata', -1)