2
0
mirror of https://github.com/ComradCollective/Comrad synced 2024-11-16 00:12:48 +00:00
Comrad/komrade/backend/keymaker.py

373 lines
15 KiB
Python
Raw Normal View History

2020-09-05 16:26:37 +00:00
import os,sys; sys.path.append(os.path.abspath(os.path.join(os.path.abspath(os.path.join(os.path.dirname(__file__),'..')),'..')))
from komrade import *
2020-09-05 21:11:42 +00:00
from komrade.backend.crypt import *
2020-09-04 12:46:22 +00:00
class Keymaker(Logger):
2020-09-06 09:25:13 +00:00
def __init__(self,name=None,passphrase=None, path_crypt_keys=None, path_crypt_data=None):
2020-09-05 14:09:31 +00:00
self.name=name
self.passphrase=passphrase
for k in KEYNAMES:
func = lambda: self.keychain().get(k)
setattr(self,'_'+k,func)
2020-09-04 12:46:22 +00:00
### BASE STORAGE
@property
def crypt_keys(self):
if not hasattr(self,'_crypt_keys'):
2020-09-06 09:33:46 +00:00
self._crypt_keys = Crypt(fn=PATH_CRYPT_CA_KEYS)
2020-09-04 12:46:22 +00:00
return self._crypt_keys
@property
def crypt_data(self):
if not hasattr(self,'_crypt_data'):
2020-09-06 09:33:46 +00:00
self._crypt_data = Crypt(fn=PATH_CRYPT_CA_DATA)
2020-09-04 12:46:22 +00:00
return self._crypt_data
### STARTING WITH MOST ABSTRACT
2020-09-06 09:38:29 +00:00
def findkey(self, keyname, keychain=defaultdict(None), uri=None):
2020-09-05 14:09:31 +00:00
self.log(f'looking for key {keyname}, in keychain {keychain.keys()} or under crypt uri {uri}')
2020-09-04 14:07:17 +00:00
# look in keychain, then in crypt, for this key
given_key = keychain.get(keyname)
2020-09-05 14:09:31 +00:00
if given_key:
self.log(f'{keyname} found in keychain: {given_key}')
return given_key
2020-09-04 14:07:17 +00:00
found_key = self.crypt_keys.get(uri,prefix=f'/{keyname}/')
2020-09-05 14:09:31 +00:00
if found_key:
self.log(f'{keyname} found in crypt: {given_key}')
return found_key
self.log(f'{keyname} not found!!')
2020-09-04 14:07:17 +00:00
2020-09-06 09:38:29 +00:00
def getkey(self, keyname, keychain=defaultdict(None), uri=None):
2020-09-05 14:09:31 +00:00
self.log(f'keyname={keyname}, keychain={keychain.keys()}, uri={uri}')
2020-09-04 14:07:17 +00:00
# 1) I already have this key stored in either the keychain or the crypt; return straight away
key = self.findkey(keyname, keychain, uri)
2020-09-05 14:09:31 +00:00
if key:
self.log(f'>> I have {key} already, returning')
return key
2020-09-04 14:07:17 +00:00
## 2) I can assemble the key
2020-09-05 14:09:31 +00:00
self.log(f'assembling key: {keyname}_encr + {keyname}_decr')
2020-09-04 14:07:17 +00:00
key_encr = self.findkey(keyname+'_encr', keychain,uri)
key_decr = self.findkey(keyname+'_decr', keychain, uri)
key = self.assemble_key(key_encr, key_decr)
2020-09-04 14:07:17 +00:00
return key
def get_cell(self, str_or_key_or_cell):
2020-09-05 14:09:31 +00:00
self.log('getting decr cell for',str_or_key_or_cell)
if type(str_or_key_or_cell)==SCellSeal:
return str_or_key_or_cell
elif type(str_or_key_or_cell)==str:
return SCellSeal(passphrase=str_or_key_or_cell)
elif type(str_or_key_or_cell)==bytes:
2020-09-05 14:09:31 +00:00
return SCellSeal(key=str_or_key_or_cell)
def assemble_key(self, key_encr, key_decr):
2020-09-05 14:09:31 +00:00
self.log(f'assembling key: {key_decr} decrypting {key_encr}')
2020-09-04 14:07:17 +00:00
# need the encrypted half
if not key_encr:
self.log('!! encrypted half not given')
return
if not key_decr:
2020-09-05 14:09:31 +00:00
if self.passphrase:
key_decr = self.passphrase
else:
self.log('!! decryptor half not given')
return
2020-09-04 14:07:17 +00:00
# need some way to regenerate the decryptor
decr_cell = self.get_cell(key_decr)
2020-09-04 14:07:17 +00:00
# need the decryptor half
if not decr_cell:
self.log('!! decryptor cell not regenerable')
2020-09-04 14:07:17 +00:00
return
2020-09-04 12:46:22 +00:00
2020-09-04 14:07:17 +00:00
# decrypt!
try:
2020-09-05 14:09:31 +00:00
self.log(f'>> decrypting {key_encr} with cell {decr_cell}')
key = decr_cell.decrypt(key_encr)
2020-09-04 14:07:17 +00:00
self.log('assembled_key built:',key)
return key
except ThemisError as e:
self.log('!! decryption failed:',e)
2020-09-04 14:22:16 +00:00
# Concrete keys
## (1) Final keys
2020-09-04 12:46:22 +00:00
def pubkey(self, **kwargs):
2020-09-04 14:22:16 +00:00
return self.getkey(keyname='pubkey',uri=self.name,**kwargs)
2020-09-04 12:46:22 +00:00
def privkey(self, **kwargs):
2020-09-04 14:22:16 +00:00
return self.getkey(keyname='privkey',uri=self.pubkey(**kwargs),**kwargs)
2020-09-04 12:46:22 +00:00
def adminkey(self, **kwargs):
2020-09-04 14:22:16 +00:00
return self.getkey(keyname='adminkey',uri=self.privkey(**kwargs),**kwargs)
## (1-X) Encrypted halves
2020-09-04 12:46:22 +00:00
def pubkey_encr(self, **kwargs):
2020-09-04 14:22:16 +00:00
return self.getkey(uri=self.name,keyname='pubkey_encr',**kwargs)
2020-09-04 12:46:22 +00:00
def privkey_encr(self, **kwargs):
2020-09-05 14:09:31 +00:00
return self.getkey(uri=self.pubkey(**kwargs),keyname='privkey_encr',**kwargs)
2020-09-04 12:46:22 +00:00
def adminkey_encr(self, **kwargs):
2020-09-05 14:09:31 +00:00
return self.getkey(uri=self.privkey(**kwargs),keyname='adminkey_encr',**kwargs)
2020-09-04 12:46:22 +00:00
2020-09-04 14:22:16 +00:00
## (1-Y) Decrpytor halves
2020-09-04 12:46:22 +00:00
def pubkey_decr(self, **kwargs):
2020-09-04 14:22:16 +00:00
return self.getkey(uri=self.name,keyname='pubkey_decr',**kwargs)
2020-09-04 12:46:22 +00:00
def privkey_decr(self, **kwargs):
2020-09-05 14:09:31 +00:00
return self.getkey(uri=self.pubkey(**kwargs),keyname='privkey_decr',**kwargs)
2020-09-04 12:46:22 +00:00
def adminkey_decr(self, **kwargs):
2020-09-05 14:09:31 +00:00
return self.getkey(uri=self.privkey(**kwargs),keyname='adminkey_decr',**kwargs)
2020-09-04 14:22:16 +00:00
## Second halving!
## (1-X-X)
def pubkey_encr_encr(self, **kwargs):
return self.getkey(uri=self.name,keyname='pubkey_encr_encr',**kwargs)
def privkey_encr_encr(self, **kwargs):
2020-09-05 14:09:31 +00:00
return self.getkey(uri=self.pubkey_encr(**kwargs),keyname='privkey_encr_encr',**kwargs)
2020-09-04 14:22:16 +00:00
def adminkey_encr_encr(self, **kwargs):
2020-09-05 14:09:31 +00:00
return self.getkey(uri=self.privkey_encr(**kwargs),keyname='adminkey_encr_encr',**kwargs)
2020-09-04 14:22:16 +00:00
## (1-X-Y)
def pubkey_encr_decr(self, **kwargs):
return self.getkey(uri=self.name,keyname='pubkey_encr_decr',**kwargs)
def privkey_encr_decr(self, **kwargs):
2020-09-05 14:09:31 +00:00
return self.getkey(uri=self.pubkey_encr(**kwargs),keyname='privkey_encr_decr',**kwargs)
2020-09-04 14:22:16 +00:00
def adminkey_encr_decr(self, **kwargs):
2020-09-05 14:09:31 +00:00
return self.getkey(uri=self.privkey_encr(**kwargs),keyname='adminkey_encr_decr',**kwargs)
2020-09-04 14:22:16 +00:00
## (1-Y-X)
def pubkey_decr_encr(self, **kwargs):
return self.getkey(uri=self.name,keyname='pubkey_decr_encr',**kwargs)
def privkey_decr_encr(self, **kwargs):
2020-09-05 14:09:31 +00:00
return self.getkey(uri=self.pubkey_decr(**kwargs),keyname='privkey_decr_encr',**kwargs)
2020-09-04 14:22:16 +00:00
def adminkey_decr_encr(self, **kwargs):
2020-09-05 14:09:31 +00:00
return self.getkey(uri=self.privkey_decr(**kwargs),keyname='adminkey_decr_encr',**kwargs)
2020-09-04 14:22:16 +00:00
## (1-Y-Y)
def pubkey_decr_decr(self, **kwargs):
return self.getkey(uri=self.name,keyname='pubkey_decr_decr',**kwargs)
def privkey_decr_decr(self, **kwargs):
2020-09-05 14:09:31 +00:00
return self.getkey(uri=self.pubkey_decr(**kwargs),keyname='privkey_decr_decr',**kwargs)
2020-09-04 14:22:16 +00:00
def adminkey_decr_decr(self, **kwargs):
2020-09-05 14:09:31 +00:00
return self.getkey(uri=self.privkey_decr(**kwargs),keyname='adminkey_decr_decr',**kwargs)
2020-09-04 14:07:17 +00:00
2020-09-05 16:26:37 +00:00
# convenience functions
# Concrete keys
@property
2020-09-06 09:40:10 +00:00
def pubkey_(self): return self.keychain().get('pubkey')
2020-09-05 16:26:37 +00:00
@property
2020-09-06 09:40:10 +00:00
def privkey_(self, **kwargs): return self.keychain().get('privkey')
2020-09-05 16:26:37 +00:00
@property
2020-09-06 09:40:10 +00:00
def adminkey_(self, **kwargs): return self.keychain().get('adminkey')
2020-09-04 14:07:17 +00:00
2020-09-05 16:26:37 +00:00
## (1-X) Encrypted halves
@property
2020-09-06 09:40:10 +00:00
def pubkey_encr_(self, **kwargs):return self.keychain().get('pubkey_encr')
2020-09-05 16:26:37 +00:00
@property
2020-09-06 09:40:10 +00:00
def privkey_encr_(self, **kwargs): return self.keychain().get('privkey_encr')
2020-09-05 16:26:37 +00:00
@property
2020-09-06 09:40:10 +00:00
def adminkey_encr_(self, **kwargs): return self.keychain().get('adminkey_encr')
2020-09-05 16:26:37 +00:00
## (1-Y) Decrpytor halves
@property
2020-09-06 09:40:10 +00:00
def pubkey_decr_(self, **kwargs): return self.keychain().get('pubkey_decr')
2020-09-05 16:26:37 +00:00
@property
2020-09-06 09:40:10 +00:00
def privkey_decr_(self, **kwargs): return self.keychain().get('privkey_decr')
2020-09-05 16:26:37 +00:00
@property
2020-09-06 09:40:10 +00:00
def adminkey_decr_(self, **kwargs): return self.keychain().get('adminkey_decr')
2020-09-05 16:26:37 +00:00
## Second halving!
## (1-X-X)
@property
2020-09-06 09:40:10 +00:00
def pubkey_encr_encr_(self, **kwargs): return self.keychain().get('pubkey_encr_encr')
2020-09-05 16:26:37 +00:00
@property
2020-09-06 09:40:10 +00:00
def privkey_encr_encr_(self, **kwargs): return self.keychain().get('privkey_encr_encr')
2020-09-05 16:26:37 +00:00
@property
2020-09-06 09:40:10 +00:00
def adminkey_encr_encr_(self, **kwargs): return self.keychain().get('adminkey_encr_encr')
2020-09-05 16:26:37 +00:00
## (1-X-Y)
@property
2020-09-06 09:40:10 +00:00
def pubkey_encr_decr_(self, **kwargs): return self.keychain().get('pubkey_encr_decr')
2020-09-05 16:26:37 +00:00
@property
2020-09-06 09:40:10 +00:00
def privkey_encr_decr_(self, **kwargs): return self.keychain().get('privkey_encr_decr')
2020-09-05 16:26:37 +00:00
@property
2020-09-06 09:40:10 +00:00
def adminkey_encr_decr_(self, **kwargs): return self.keychain().get('adminkey_encr_decr')
2020-09-05 16:26:37 +00:00
## (1-Y-X)
@property
2020-09-06 09:40:10 +00:00
def pubkey_decr_encr_(self, **kwargs): return self.keychain().get('pubkey_decr_encr')
2020-09-05 16:26:37 +00:00
@property
2020-09-06 09:40:10 +00:00
def privkey_decr_encr_(self, **kwargs): return self.keychain().get('privkey_decr_encr')
2020-09-05 16:26:37 +00:00
@property
2020-09-06 09:40:10 +00:00
def adminkey_decr_encr_(self, **kwargs): return self.keychain().get('adminkey_decr_encr')
2020-09-05 16:26:37 +00:00
## (1-Y-Y)
@property
2020-09-06 09:40:10 +00:00
def pubkey_decr_decr_(self, **kwargs): return self.keychain().get('pubkey_decr_decr')
2020-09-05 16:26:37 +00:00
@property
2020-09-06 09:40:10 +00:00
def privkey_decr_decr_(self, **kwargs): return self.keychain().get('privkey_decr_decr')
2020-09-05 16:26:37 +00:00
@property
2020-09-06 09:40:10 +00:00
def adminkey_decr_decr_(self, **kwargs): return self.keychain().get('adminkey_decr_decr')
2020-09-05 16:26:37 +00:00
2020-09-04 14:07:17 +00:00
2020-09-04 12:46:22 +00:00
# Get key de-cryptors
def genkey_pass_keycell(self,pass_phrase,q_name='Read permissions?'):
if pass_phrase is None:
pass_key = GenerateSymmetricKey()
pass_cell = SCellSeal(key=pass_key)
else:
if pass_phrase is True: pass_phrase=getpass.getpass(f'Enter pass phrase [{q_name}]: ')
pass_key = None
pass_cell = SCellSeal(passphrase=pass_phrase)
self.log(f'pass_key [{q_name}] <--',pass_key)
self.log(f'pass_cell [{q_name}] <--',pass_cell)
return (pass_key, pass_cell)
2020-09-04 15:50:08 +00:00
def exists(self):
return self.crypt_keys.exists(self.name,prefix='/pubkey_encr/') or self.crypt_keys.exists(self.name,prefix='/pubkey_decr/') or self.crypt_keys.exists(self.name,prefix='/pubkey/')
### CREATING KEYS
def get_new_keys(self,pubkey_pass = None, privkey_pass = None, adminkey_pass = None):
# Get decryptor keys back from The Operator (one half of the Keymaker)
2020-09-05 14:09:31 +00:00
keychain = self.forge_new_keys(self.name)
self.log('create_keys() res from Operator? <-',keychain)
2020-09-04 15:50:08 +00:00
# Now lock the decryptor keys away, sealing it with a password of memory!
self.lock_new_keys(keychain)
def forge_new_keys(self,name,pubkey_is_public=False,return_all_keys=False):
self.log('forging new keys...')
# Create public and private keys
keypair = GenerateKeyPair(KEY_PAIR_TYPE.EC)
privkey = keypair.export_private_key()
pubkey = keypair.export_public_key()
adminkey = GenerateSymmetricKey()
# Create decryption/permission keys
pubkey_decr = GenerateSymmetricKey()
privkey_decr = GenerateSymmetricKey()
adminkey_decr = GenerateSymmetricKey() #SCellSeal(passphrase=passphrase)
# Encrypt original keys
pubkey_encr = SCellSeal(key=pubkey_decr).encrypt(pubkey)
privkey_encr = SCellSeal(key=privkey_decr).encrypt(privkey)
adminkey_encr = SCellSeal(key=adminkey_decr).encrypt(adminkey)
# store encrypted on my hardware
self.crypt_keys.set(name,pubkey_encr,prefix='/pubkey_encr/')
self.crypt_keys.set(pubkey,privkey_encr,prefix='/privkey_encr/')
self.crypt_keys.set(privkey,adminkey_encr,prefix='/adminkey_encr/')
# store permissions file?
secret_admin_val = pubkey_encr + BSEP + b'find,read,admin'
if pubkey_is_public: secret_admin_val += b'*'+BSEP+b'find'
secret_admin_val_encr = SCellSeal(key=adminkey).encrypt(secret_admin_val)
self.crypt_keys.set(adminkey,secret_admin_val_encr,prefix='/permkey_encr/')
# keep public key?
if pubkey_is_public: self.crypt_keys.set(name,pubkey_decr,prefix='/pubkey_decr/')
# send back decryption keys to client
if not return_all_keys: # default situation
keychain = {
'pubkey_decr':pubkey_decr,
'privkey_decr':privkey_decr,
'adminkey_decr':adminkey_decr
}
else: # only in special case!
keychain = {
'pubkey':pubkey,'pubkey_encr':pubkey_encr,'pubkey_decr':pubkey_decr,
'privkey':privkey,'privkey_encr':privkey_encr,'privkey_decr':privkey_decr,
'adminkey':adminkey,'adminkey_encr':adminkey_encr,'adminkey_decr':adminkey_decr
}
return keychain
2020-09-05 14:09:31 +00:00
def lock_new_keys(self,keychain,passphrase=None):
2020-09-04 15:50:08 +00:00
# we're not going to store the decryptor keys directly though
2020-09-05 14:09:31 +00:00
if not passphrase:
if self.passphrase:
passphrase=self.passphrase
else:
self.passphrase=passphrase=getpass.getpass('Forge the password of memory: ')
2020-09-04 15:50:08 +00:00
cell = SCellSeal(passphrase=passphrase)
2020-09-05 14:09:31 +00:00
2020-09-04 15:50:08 +00:00
# encrypt the decryptor keys
pubkey_decr_encr = cell.encrypt(keychain['pubkey_decr'])
privkey_decr_encr = cell.encrypt(keychain['privkey_decr'])
adminkey_decr_encr = cell.encrypt(keychain['adminkey_decr'])
2020-09-05 14:09:31 +00:00
# set to crypt and keychain
2020-09-04 15:50:08 +00:00
self.crypt_keys.set(self.name,pubkey_decr_encr,prefix='/pubkey_decr_encr/')
2020-09-05 14:09:31 +00:00
#keychain['pubkey_decr_encr']=pubkey_decr_encr
2020-09-04 15:50:08 +00:00
self.crypt_keys.set(keychain['pubkey_decr'],privkey_decr_encr,prefix='/privkey_decr_encr/')
2020-09-05 14:09:31 +00:00
#keychain['privkey_decr_encr']=privkey_decr_encr
2020-09-04 15:50:08 +00:00
self.crypt_keys.set(keychain['privkey_decr'],adminkey_decr_encr,prefix='/adminkey_decr_encr/')
2020-09-05 14:09:31 +00:00
#keychain['adminkey_decr_encr']=adminkey_decr_encr
2020-09-04 15:50:08 +00:00
# store decryption keys if not passworded?
2020-09-05 14:09:31 +00:00
pub_ddk,priv_ddk,admin_ddk=[x+'key_decr_decr_key' for x in ['pub','priv','admin']]
if pub_ddk in keychain:
self.crypt_keys.set(self.name, keychain[pub_ddk], prefix=f'/{pub_ddk}/')
if priv_ddk in keychain:
self.crypt_keys.set(self.name, keychain[priv_ddk], prefix=f'/{priv_ddk}/')
if admin_ddk in keychain:
self.crypt_keys.set(self.name, keychain[admin_ddk], prefix=f'/{admin_ddk}/')
2020-09-04 15:50:08 +00:00
2020-09-05 14:09:31 +00:00
# # return protected keychain
# todel = ['pubkey_decr','privkey_decr','adminkey_decr']
# for x in todel:
# if x in keychain:
# del keychain[x]
# # add encr versions
# keychain
# del keychain['pubkey_decr']
# del keychain['privkey_decr']
# del keychain['adminkey_decr']
# return ()
return passphrase
# def load_concrete_keychain():
# keychain = {}
# for keyname in KEYNAMES:
# keychain=self.findkey(keyname, keychain, uri)
def keychain(self,passphrase=None,force=False,**kwargs):
# assemble as many keys as we can!
if not force and hasattr(self,'_keychain') and self._keychain: return self._keychain
if passphrase: self.passphrase=passphrase
_keychain = defaultdict(None)
for keyname in reversed(KEYNAMES+KEYNAMES):
self.log('??',keyname,'...')
if hasattr(self,keyname):
method=getattr(self,keyname)
res=method(keychain=_keychain, **kwargs)
self.log('res <--',res)
if res:
_keychain[keyname]=res
return _keychain