Files
2016-11-01 13:24:49 -04:00

343 lines
13 KiB
Python

## **************
## Copyright 2015 MIT Lincoln Laboratory
## Project: PACE
## Authors: ATLH
## Description: Framework for demoing the encryption code
## Modifications:
## Date Name Modification
## ---- ---- ------------
## 09 Apr 2015 ATLH Original file
## **************
import os
import sys
this_dir = os.path.dirname(os.path.dirname(__file__))
base_dir = os.path.join(this_dir, '../..')
sys.path.append(base_dir)
import pyaccumulo
from StringIO import StringIO
import base64
from Crypto.PublicKey import RSA
import subprocess
from pace.encryption.acc_encrypt import AccumuloEncrypt, Encryptor
from pace.encryption.encryption_pki import DummyEncryptionPKI, EncryptionPKIAccumulo
from pace.encryption.AES_encrypt import Pycrypto_AES_CFB
from pace.encryption.encryption_exceptions import DecryptionException
from pace.pki.keygen import KeyGen
from pace.pki.accumulo_keystore import AccumuloKeyStore, AccumuloAttrKeyStore
from pace.pki.frontend import KeyStoreFrontEnd
ABS_PATH = os.path.dirname(__file__)
DEMO_USERS = ABS_PATH + '../pki/user_info.cfg'
PRIV_KEYS = ABS_PATH + '../pki/'
# Default elements to use
expressive_elems = [('MITLL', '(a&b)|c','Analytics','Rooms','1200'),
('MITLL', '(a&b)|c','Analytics','Employees','4000'),
('Boston', '(a&b)|c','Analytics','Population','3000000'),
('Cambridge', '(a&b)|c','Analytics','Population','400000')]
#Tuples of accumulo elements: row, vis, colFam, colQual, and value
vis_elems = [('Analytics', 'a','','','120'),
('Average', 'a&b','','','200'),
('Median', '(a&b)|c','','','160'),
('Total', '(a&b)|(c&d)|(b&d)|(b&c)','','','320')]
new_vis_elems = [('Sum', 'c&d','','','1200'),
('Minimum', 'b','','','120')]
empty_vis = [('Sum', '','','','1200')]
descriptions = {'expressive' : "Row contains: Row encrypted with Pycrypto_AES_SIV\n"+\
"ColFamily contains: ColFamily & ColQualifier encrypted with Pycrypto_AES_CFB\n"+\
"ColQualifier contains: Nothing\n"+\
"Value contains: Value encrypted with AES_GCM\n",
'identity' : "Row contains: Row unecrypted\n"+\
"ColFamily contains: ColFamily & ColQualifier concatentated\n"+\
"ColQualifier contains: Nothing\n"+\
"Value contains: Value unencrypted \n",
'vis' : "Value contains: Value encrypted with VIS_AES_CFB",
'print' : "",
'vis_print':'',
'none': "Currently using no encryption scheme"}
schema = { 'expressive' : '[row]\n'+\
'key_id = Pycrypto_AES_SIV\n'+\
'encryption = Pycrypto_AES_SIV\n'+\
'[colFamily]\n'+\
'key_id = Pycrypto_AES_CFB\n'+\
'cell_sections = colFamily,colQualifier\n'+\
'encryption = Pycrypto_AES_CFB\n'+\
'[value]\n'+\
'key_id = Pycrypto_AES_CFB\n'+\
'encryption = Pycrypto_AES_GCM',
'identity': '[row]\n'+\
'key_id = Identity\n'+\
'encryption = Identity\n'+\
'[colFamily]\n'+\
'key_id = Identity\n'+\
'cell_sections = colFamily,colQualifier\n'+\
'encryption = Identity\n'+\
'[value]\n'+\
'key_id = Identity\n'+\
'encryption = Identity',
'vis' : '[value]\n'+\
'key_id = VIS_AES_CFB\n'+\
'cell_key_length = 32\n'+\
'encryption = VIS_AES_CFB',
'none': '[row]\n'+\
'key_id = Identity\n'+\
'encryption = Identity\n',
'print':'[row]\n'+\
'key_id = Identity\n'+\
'encryption = Identity\n',
'vis_print':'[row]\n'+\
'key_id = Identity\n'+\
'encryption = Identity\n'}
def mutation_from_kv_tuple(tup):
""" Define a pyaccumulo mutation from a (key, value) formatted tuple.
"""
row, cv, cf, cq, val = tup
print 'Inserting entry: \n Row - %s,\n Column_Visibility - %s,\n Column_Family - %s,\n Column_Qualifier - %s,\n Value - %s' % (row,cv,cf,cq,val)
m = pyaccumulo.Mutation(row)
m.put(cf=cf, cq=cq, cv=cv, val=val)
return m
def grant_auths(table='demo', user='user3'):
"""
Grants read/write priviledges for the user
for the necessary tables in the demo, also sets
user's attributes to a,c,d,e
"""
print "Setting ", user, "'s attributes to a,c,d,e"
_ = subprocess.call("/usr/local/accumulo-1.7.0/bin/accumulo shell -u root -p secret -e 'setauths -u "+user+" -s a,c,d,e'", stdout=subprocess.PIPE, shell=True)
tables = ['__VERSION_METADATA__','__KEYWRAP_METADATA__',"VIS_AES_CFB"]
tables.append(table)
print "Granting read/write access to tables:"
for tab in tables:
print " Table ", tab
_ = subprocess.call("/usr/local/accumulo-1.7.0/bin/accumulo shell -u root -p secret -e 'grant Table.READ -t "+tab+" -u "+user+"'", stdout=subprocess.PIPE, shell=True)
_ = subprocess.call("/usr/local/accumulo-1.7.0/bin/accumulo shell -u root -p secret -e 'grant Table.WRITE -t "+tab+" -u "+user+"'", stdout=subprocess.PIPE, shell=True)
def write_list_to_table(conn, encrypter, table, data):
""" Write a list to an Accumulo table.
Arguments:
conn - a pyaccumulo connection to an Accumulo instance
encrypter - an AccumuloEncrypt instance
table - the name of the table to write to
data - the list to write to the table, formatted as a list of
(key, cf, cq, value) tuples
"""
if not conn.table_exists(table):
conn.create_table(table)
wr = conn.create_batch_writer(table)
for tup in data:
m = mutation_from_kv_tuple(tup)
enc_mut = encrypter.encrypt(m)
for mut in enc_mut:
wr.add_mutation(mut)
wr.close()
def run_insert(conn=None,
data=expressive_elems,
table='demo',
config_name = 'expressive',
PKI_object=None):
""" Insert a list into the accumulo table specified.
Arguments:
conn - the Accumulo connection to use
data - the list to insert into the Accumulo table
table - the name of the table to insert to
default_vis - the default visibility label to use. default: '(a&b)|c'
config_filept - file pointer to the configuration file for encryption
PKI_object - matches the interface on encryption PKI OBJECT, default is
DummyEncryptionPKI
"""
if conn is None:
conn = pyaccumulo.Accumulo(host='localhost',
port=42424,
user='root',
password='secret')
if PKI_object is None:
PKI_object = DummyEncryptionPKI(conn=conn)
config_filept = StringIO(schema[config_name])
encrypter = AccumuloEncrypt(config_filept, PKI_object)
print "\nEnrypting with the following schema: \n\n" + descriptions[config_name]
write_list_to_table(conn, encrypter, table, data)
def run_retrieve(conn=None,
table='demo',
config_name = 'expressive',
PKI_object=None):
""" Retrieves and decrypts values from the specified table,
outputting the appropriate error messages if not.
Arguments:
conn - the Accumulo connection to use
data - the list to insert into the Accumulo table
table - the name of the table to insert to
config_filept - file pointer to the configuration file for encryption
PKI_object - matches the interface on encryption PKI OBJECT, default is
DummyEncryptionPKI
"""
if conn is None:
conn = pyaccumulo.Accumulo(host='localhost',
port=42424,
user='root',
password='secret')
if PKI_object is None:
PKI_object = DummyEncryptionPKI(conn=conn)
total = 0
config_filept = StringIO(schema[config_name])
decrypter = AccumuloEncrypt(config_filept, PKI_object)
for entry in conn.scan(table):
total = total + 1
try:
cell = decrypter.decrypt(entry)
if config_name == 'print':
print 'Entry: \n Row - %s,\n Column_Visibility - %s,\n Column_Family - %s,\n Column_Qualifier - %s,\n Value - %s\n' %(base64.b64encode(cell.row),
cell.cv,
base64.b64encode(cell.cf),
base64.b64encode(cell.cq),
base64.b64encode(cell.val))
elif config_name == 'vis_print':
print 'Entry: \n Row - %s,\n Column_Visibility - %s,\n Column_Family - %s,\n Column_Qualifier - %s,\n Value - %s\n' %(cell.row,
cell.cv,
cell.cf,
cell.cq,
base64.b64encode(cell.val))
else:
print 'Entry: \n Row - %s,\n Column_Visibility - %s,\n Column_Family - %s,\n Column_Qualifier - %s,\n Value - %s\n' % (cell.row, cell.cv,cell.cf,cell.cq,cell.val)
except DecryptionException as ve:
print 'Error: Entry failed to decrypt.'
print 'Error message:', ve.msg
print
print 'Finished, decrypted %d total entries.' %(total)
def run_search(conn=None,
table='demo',
config_name = 'expressive',
PKI_object=None,
row_range='Analytics'):
""" Retrieves and decrypts values from the specified table,
outputting the appropriate error messages if not.
Arguments:
conn - the Accumulo connection to use
data - the list to insert into the Accumulo table
table - the name of the table to insert to
config_filept - file pointer to the configuration file for encryption
PKI_object - matches the interface on encryption PKI OBJECT, default is
DummyEncryptionPKI
row_range - the keyword to search for
"""
if conn is None:
conn = pyaccumulo.Accumulo(host='localhost',
port=42424,
user='root',
password='secret')
if PKI_object is None:
PKI_object = DummyEncryptionPKI(conn=conn)
total = 0
enc_config_filept = StringIO(schema[config_name])
dec_config_filept = StringIO(schema[config_name])
encrypter = AccumuloEncrypt(enc_config_filept, PKI_object)
enc_row, _ = encrypter.encrypt_search(row_range, None)
range = pyaccumulo.Range(srow = enc_row, sinclude = True,
erow = enc_row, einclude = True)
for entry in conn.scan(table, scanrange=range):
total = total + 1
try:
cell = encrypter.decrypt(entry)
print "Entry: (%s, %s, %s, %s)" % (cell.row, cell.cf, cell.cq, cell.val)
except DecryptionException as ve:
print 'Error: Entry failed to decrypt.'
print 'Error message:', ve.msg
print
print 'Finished, decrypted %d total entries.' %(total)
def run_pki_insert(genpath=DEMO_USERS, user='user1', 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='root', password='secret')
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 run_revoke(user, attr, genpath=DEMO_USERS, conn=None):
if conn is None:
conn = pyaccumulo.Accumulo(host='localhost', port=42424,
user='root', password='secret')
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)