diff --git a/komrade/backend/callers.py b/komrade/backend/callers.py index eb99d6b..892967e 100644 --- a/komrade/backend/callers.py +++ b/komrade/backend/callers.py @@ -11,8 +11,33 @@ class Caller(Operator): Variant of an Operator which handles local keys and keymaking. """ + def ring_ring(self,msg_encr_caller2caller): + # ring 1: encrypt caller2phone + msg_encr_caller2caller_caller2phone = self.package_msg_to( + msg_encr_caller2caller, + self.op + ) + self.log('msg_encr_caller2caller_caller2phone',msg_encr_caller2caller_caller2phone) + + + # ring 2: dial and get response + resp_msg_encr_caller2caller_caller2phone = self.phone.ring_ring( + msg_encr_caller2caller_caller2phone + ) + self.log('resp_msg_encr_caller2caller_caller2phone',resp_msg_encr_caller2caller_caller2phone) + + + # ring 3: decrypt and send back + resp_msg_encr_caller2caller = self.unpackage_msg_from( + resp_msg_encr_caller2caller_caller2phone + ) + self.log('resp_msg_encr_caller2caller',resp_msg_encr_caller2caller) + + return resp_msg_encr_caller2caller + def get_new_keys(self, name = None, passphrase = DEBUG_DEFAULT_PASSPHRASE, is_group=None): + # get needed metadata if not name: name=self.name if name is None: name = input('\nWhat is the name for this account? ') @@ -22,14 +47,13 @@ class Caller(Operator): # is_group = input('\nIs this a group account? [y/N]').strip().lower() == 'y' # form request - req_json = { - '_route':'forge_new_keys', + msg_to_op = { + '_please':'forge_new_keys', 'name':name, 'passphrase':hashish(passphrase.encode()) } - # ask operator - phone_res = self.phone.ring_ring(json_phone2phone=req_json) + phone_res = self.phone.ring_ring(msg_to_op) # URI id uri_id = phone_res.get('uri_id') diff --git a/komrade/backend/keymaker.py b/komrade/backend/keymaker.py index aedf667..ab6f94e 100644 --- a/komrade/backend/keymaker.py +++ b/komrade/backend/keymaker.py @@ -85,24 +85,61 @@ class Keymaker(Logger): # set defaults self.name=name self._uri_id=uri_id + self._pubkey=None self._keychain=keychain self.passphrase=passphrase self.path_crypt_keys=path_crypt_keys self.path_crypt_data=path_crypt_data + @property + def pubkey(self): + if not self._pubkey: self._pubkey = self.crypt_keys.get(self.name, prefix='/pubkey/') + if not self._pubkey: self._pubkey = b64decode(self.load_qr.get(self.name, prefix='/pubkey/').encode()) + return self._pubkey + + def keychain(self,look_for=KEYMAKER_DEFAULT_ALL_KEY_NAMES): + keys = {'pubkey':self.pubkey} + uri = self.uri_id + + # get from cache + for keyname in look_for: + key = self.crypt_keys.get(uri,prefix=f'/{keyname}/') + if key: + keys[keyname]=key + + # try to assemble + keys = self.assemble(self.assemble(keys)) + + return keys + + + @property + def pubkey(self): + if not self._pubkey: self._pubkey = self.crypt_keys.get(self.name, prefix='/pubkey/') + if not self._pubkey: self._pubkey = b64decode(self.load_qr.get(self.name, prefix='/pubkey/').encode()) + return self._pubkey + @property + def privkey(self): return self.keychain()['privkey'] + @property + def adminkey(self): return self.keychain()['adminkey'] + + + + def load_qr(self,name): + # try to load? + contact_fnfn = os.path.join(PATH_QRCODES,name+'.png') + print(contact_fnfn,os.path.exists(contact_fnfn)) + if not os.path.exists(contact_fnfn): return + # with open(contact_fnfn,'rb') as f: dat=f.read() + from pyzbar.pyzbar import decode + from PIL import Image + return decode(Image.open(contact_fnfn))[0].data + + @property def uri_id(self): if not hasattr(self,'_uri_id') or not self._uri_id: - - # try to load? - contact_fnfn = os.path.join(PATH_QRCODES,self.name+'.png') - print(contact_fnfn,os.path.exists(contact_fnfn)) - if not os.path.exists(contact_fnfn): return - - # with open(contact_fnfn,'rb') as f: dat=f.read() - from pyzbar.pyzbar import decode - from PIL import Image - self._uri_id = uri_id = decode(Image.open(contact_fnfn))[0].data + self._uri_id = b64encode(self.pubkey) return self._uri_id @@ -343,45 +380,45 @@ class Keymaker(Logger): return SCellSeal(key=str_or_key_or_cell) - def keychain(self, - passphrase=DEBUG_DEFAULT_PASSPHRASE, - extra_keys={}, - keys_to_gen=KEYMAKER_DEFAULT_KEYS_TO_GEN, - uri_id=None, - **kwargs): - - # assemble as many keys as we can! - self.log(f'''keychain( - passphrase={passphrase}, - extra_keys={extra_keys}, - keys_to_gen={keys_to_gen}, - uri_id={uri_id}, - **kwargs = {kwargs} - )''') - - if not uri_id: uri_id = self.uri_id - if not uri_id and not self.uri_id: - raise KomradeException('Need URI id to complete finding of keys!') - self.log('getting keychain for uri ID:',uri_id) - - # if not force and hasattr(self,'_keychain') and self._keychain: return self._keychain - if passphrase: self.passphrase=passphrase - - # start off keychain - _keychain = {**extra_keys, **self._keychain} - self.log('_keychain at start of keychain() =',_keychain) + # def keychain(self, + # passphrase=DEBUG_DEFAULT_PASSPHRASE, + # extra_keys={}, + # keys_to_gen=KEYMAKER_DEFAULT_KEYS_TO_GEN, + # uri_id=None, + # **kwargs): + + # # assemble as many keys as we can! + # self.log(f'''keychain( + # passphrase={passphrase}, + # extra_keys={extra_keys}, + # keys_to_gen={keys_to_gen}, + # uri_id={uri_id}, + # **kwargs = {kwargs} + # )''') + + # if not uri_id: uri_id = self.uri_id + # if not uri_id and not self.uri_id: + # raise KomradeException('Need URI id to complete finding of keys!') + # self.log('getting keychain for uri ID:',uri_id) + + # # if not force and hasattr(self,'_keychain') and self._keychain: return self._keychain + # if passphrase: self.passphrase=passphrase + + # # start off keychain + # _keychain = {**extra_keys, **self._keychain} + # self.log('_keychain at start of keychain() =',_keychain) - # find - for keyname in keys_to_gen: - if keyname in _keychain and _keychain[keyname]: continue - # self.log('??',keyname,keyname in self._keychain,'...') - newkey = self.crypt_keys.get(uri_id,prefix=f'/{keyname}/') - if newkey: _keychain[keyname] = newkey + # # find + # for keyname in keys_to_gen: + # if keyname in _keychain and _keychain[keyname]: continue + # # self.log('??',keyname,keyname in self._keychain,'...') + # newkey = self.crypt_keys.get(uri_id,prefix=f'/{keyname}/') + # if newkey: _keychain[keyname] = newkey - # return - _keychain = self.assemble(_keychain) - self._keychain = _keychain - return _keychain + # # return + # _keychain = self.assemble(_keychain) + # self._keychain = _keychain + # return _keychain diff --git a/komrade/backend/operators.py b/komrade/backend/operators.py index fcb2c9e..5800c69 100644 --- a/komrade/backend/operators.py +++ b/komrade/backend/operators.py @@ -99,475 +99,16 @@ class Operator(Keymaker): - def write_to(self,another): - pass + def package_msg_to(self,msg,another): + msg = { + '_from_pub':self.pubkey, + '_from_name':self.name, + '_to_pub':another.pubkey, + '_to_name':another.name + '_msg':msg, + } + return self.encrypt_to_send(msg, self.privkey, another.pubkey) - - # async def req(self,json_phone={},json_caller={},caller=None): - def ring_ring(self, - from_phone=None, - to_phone=None, - - from_caller=None, - to_caller=None, - - json_phone2phone={}, - json_caller2phone={}, # (person) -> operator or operator -> (person) - json_caller2caller={}): - - - self.log(f""" - RING RING! - from_phone={from_phone}, to_phone={to_phone}, - from_caller={from_caller}, to_caller={to_caller}, - json_phone2phone={json_phone2phone}, - json_caller2phone={json_caller2phone}, - json_caller2caller={json_caller2caller}, - """) - - ## defaults - unencr_header=b'' - encrypted_message_from_telephone_to_op = b'' - encrypted_message_from_caller_to_op = b'' - encrypted_message_from_caller_to_caller = b'' - - print('uri phone',from_phone.uri_id) - from_phone_keychain = from_phone.keychain() - - - - from_phone_pubkey_encr=from_phone_keychain.get('pubkey_encr') - from_phone_privkey=from_phone_keychain.get('privkey') - - to_phone_keychain = to_phone.keychain() - to_phone_pubkey_decr=to_phone_keychain.get('pubkey_decr') - to_phone_pubkey=to_phone_keychain.get('pubkey') - - self.log('from_phone',type(from_phone),'to_phone',type(to_phone)) - self.log('from_phone_keychain',from_phone_keychain) - self.log('to_phone_keychain',to_phone_keychain) - - - ### LAYERS OF ENCRYPTION: - # 1) unencr header - # Telephone sends half its and the operator's public keys - self.log('Layer 1: from_phone_pubkey_encr header:',from_phone_pubkey_encr) - self.log('Layer 1: to_phone_pubkey_decr header:',to_phone_pubkey_decr) - - unencr_header = from_phone_pubkey_encr + BSEP2 + to_phone_pubkey_decr - self.log('Layer 1: Unencrypted header:',unencr_header) - - ## Encrypt level 1: from Phone to Op - if json_phone2phone: - encrypted_message_from_telephone_to_op = self.encrypt_to_send( - msg_json = json_phone2phone, - from_privkey = from_phone_privkey, - to_pubkey = to_phone_pubkey - ) - self.log('Layer 2: Phone 2 op:',encrypted_message_from_telephone_to_op) - - ## Level 2: from Caller to Op - if json_caller2phone and from_caller: - encrypted_message_from_caller_to_op = self.encrypt_to_send( - msg_json = json_caller2phone, - from_privkey = from_caller.keychain().get('privkey'), - to_pubkey = to_phone_pubkey - ) - self.log('Layer 3: Caller 2 op:',encrypted_message_from_telephone_to_op) - - # 2) Level 3: from Caller to Caller - if json_caller2caller and from_caller and to_caller: - encrypted_message_from_caller_to_caller = self.encrypt_to_send( - msg_json = json_caller2caller, - from_privkey = from_caller.keychain().get('privkey'), - to_pubkey = to_caller.keychain().get('pubkey') - ) - self.log('Layer 3: Caller 2 Caller:',encrypted_message_from_telephone_to_op) - - MSG_PIECES = [ - unencr_header, - encrypted_message_from_telephone_to_op, - encrypted_message_from_caller_to_op, - encrypted_message_from_caller_to_caller - ] - - self.log(b'\n ~~~ \n'.join(MSG_PIECES)) - MSG = BSEP.join(MSG_PIECES) - self.log('MSG',MSG) - MSG_b64 = b64encode(MSG) - self.log(b' ~~~ ring ring ~~~ rriing ~~~',MSG_b64) - - msg_b64_str = MSG_b64.decode() - self.log(b' ~~~ rirrrrng ring ~~~~ ring ~~ rrrrriing ~~~',msg_b64_str) - - ## escape slashes - msg_b64_str_esc=msg_b64_str.replace('/','_') - - - return msg_b64_str_esc - - - def answer_phone(self,data_b64_str_esc, from_phone=None,to_phone=None): - ## escape slashes - data_b64_s=data_b64_str_esc.replace('_','/') - - self.log('Pronto!\n ... '+data_b64_s+' ...?') - - # if not isBase64(data_b64_s): - # self.log('incoming data not b64') - # return OPERATOR_INTERCEPT_MESSAGE - - # string -> b64 bytes - data_b64_b = data_b64_s.encode() - self.log('data_b64_b',data_b64_b) - - # b64 -> raw bytes - data = b64decode(data_b64_b) - self.log('data',data) - - # split - self.log('BSEP count',data.count(BSEP)) - self.log(data.split(BSEP)) - assert data.count(BSEP) == 3 - ( - unencr_header, # Tele.pubkey_encr|Op.pubkey_decr - data_encr_phone2phone, - data_encr_caller2phone, - data_encr_caller2caller - ) = data.split(BSEP) - - self.log('unencr_header',unencr_header) - self.log('data_encr_phone2phone',data_encr_phone2phone) - self.log('data_encr_caller2phone',data_encr_caller2phone) - self.log('data_encr_caller2caller',data_encr_caller2caller) - - # set up - DATA = {} - - # layer 1: unencr - # get other keys from halfkeys - # from_phone_pubkey,to_phone_pubkey = self.reassemble_nec_keys_using_header(unencr_header) - if not from_phone or not to_phone: - from_phone,to_phone = self.discover_which_phones_from_header(unencr_header) - - - self.log(f'I am {to_phone} and I am answering the phone! from {from_phone}') - - # layer 2: I know I (either Telephone or Operator) am the recipient of this msg - from_phone_keychain = from_phone.keychain() - from_phone_pubkey=from_phone_keychain.get('pubkey') - to_phone_keychain = to_phone.keychain() - to_phone_privkey=to_phone_keychain.get('privkey') - - self.log('data_encr_phone2phone',data_encr_phone2phone) - self.log('from_phone_pubkey',from_phone_pubkey,from_phone) - self.log('to_phone_privkey',to_phone_privkey,to_phone) - - # 2) decrypt from phone - data_phone2phone = self.decrypt_from_send( - msg_encr=data_encr_phone2phone, - from_pubkey=from_phone_pubkey, - to_privkey=to_phone_privkey - ) - self.log('data_phone2phone',data_phone2phone) - - # 3) decrypt from caller - from_caller_pubkey = self.reassemble_necessary_keys_using_decr_phone_data(data_phone2phone) - data_caller2phone = self.decrypt_from_send( - msg_encr=data_encr_caller2phone, - from_pubkey=from_caller_pubkey, - to_privkey=to_phone_privkey - ) - self.log('data_caller2phone',data_caller2phone) - - - # @TODO: 4) Caller 2 Caller - #to_caller_pubkey = self.reassemble_necessary_keys_using_decr_caller_data(data_caller2phone) - # send this to caller... - - - DATA = {} - dict_merge(DATA,data_phone2phone) - dict_merge(DATA,data_caller2phone) - # dict_merge(DATA,data_caller2caller) - # dict_merge(DATA,data_by_caller) - self.log('DATA!!!!!',DATA) - return DATA - - - - - - # def encrypt_outgoing(self, - # data_from_sender1={}, - # data_from_sender2={}, - # privkey_from_sender1=None, - # privkey_from_sender2=None, - # to_pubkey=None, - # unencr_header=b''): - - - # # 2) encrypt to phone - # json_phone_encr = self.encrypt_to_send(data_from_sender1,from_phone_privkey,to_pubkey) - # self.log('json_phone_encr',json_phone_encr) - - # # 3) to caller - # json_caller_encr = self.encrypt_to_send(json_caller,from_caller_privkey,to_pubkey) - # self.log() - - # # return - # req_data_encr = unencr_header + BSEP + json_phone_encr + BSEP + json_caller_encr - # return req_data_encr - - def reassemble_nec_keys_using_header(self,unencr_header): - assert unencr_header.count(BSEP2)==1 - phone_pubkey_encr,op_pubkey_decr = unencr_header.split(BSEP2) - - # get phone pubkey - new_phone_keychain = self.phone.keychain(extra_keys={'pubkey_encr':phone_pubkey_encr},force=True) - new_op_keychain = self.keychain(extra_keys={'pubkey_decr':op_pubkey_decr},force=True) - - phone_pubkey = new_phone_keychain.get('pubkey') - op_pubkey = new_op_keychain.get('pubkey') - - self.log('reassembled phone/op pubkeys:',phone_pubkey,op_pubkey) - return (phone_pubkey,op_pubkey) - - def discover_which_phones_from_header(self,unencr_header): - assert unencr_header.count(BSEP2)==1 - from_phone_pubkey_encr,to_phone_pubkey_decr = unencr_header.split(BSEP2) - - phone_keychain = self.phone.keychain() - op_keychain = self.op.keychain() - op_pubkey_encr = op_keychain.get('pubkey_encr') - op_pubkey_decr = op_keychain.get('pubkey_decr') - phone_pubkey_encr = phone_keychain.get('pubkey_encr') - phone_pubkey_decr = phone_keychain.get('pubkey_encr') - - self.log('phone_keychain',phone_keychain) - self.log('op_keychain',op_keychain) - self.log('op_pubkey_encr',op_pubkey_encr) - self.log('op_pubkey_decr',op_pubkey_decr) - self.log('phone_pubkey_encr',phone_pubkey_encr) - self.log('phone_pubkey_decr',phone_pubkey_decr) - - # was this sent from Phone -> Op? - to_phone=None - from_phone=None - - op_fits_as_to_phone=False - tele_fits_as_to_phone=False - op_fits_as_from_phone=False - tele_fits_as_from_phone=False - - if op_pubkey_encr: - op_fits_as_to_phone = self.assemble_key(op_pubkey_encr,to_phone_pubkey_decr) - self.log('op_fits_as_to_phone',op_fits_as_to_phone) - return (self.phone,self.op) - if phone_pubkey_encr: - tele_fits_as_to_phone = self.assemble_key(phone_pubkey_encr,to_phone_pubkey_decr) - self.log('tele_fits_as_to_phone',tele_fits_as_to_phone) - return (self.op,self.phone) - if op_pubkey_decr: - op_fits_as_from_phone = self.assemble_key(from_phone_pubkey_encr, op_pubkey_decr) - self.log('op_fits_as_from_phone',op_fits_as_from_phone) - return (self.op,self.phone) - if phone_pubkey_decr: - tele_fits_as_from_phone = self.assemble_key(from_phone_pubkey_encr,phone_pubkey_decr) - self.log('tele_fits_as_from_phone',tele_fits_as_from_phone) - return (self.phone,self.op) - - - - - # # get phone pubkey - # new_phone_keychain = self.phone.keychain(extra_keys={'pubkey_encr':phone_pubkey_encr},force=True) - # new_op_keychain = self.keychain(extra_keys={'pubkey_decr':op_pubkey_decr},force=True) - - # phone_pubkey = new_phone_keychain.get('pubkey') - # op_pubkey = new_op_keychain.get('pubkey') - - # self.log('reassembled phone/op pubkeys:',phone_pubkey,op_pubkey) - # return (phone_pubkey,op_pubkey) - - - def reassemble_necessary_keys_using_decr_phone_data(self,decr_phone_data): - name=decr_phone_data.get('name') - if not name: return None - - try: - caller = Caller(name) - self.log('got caller on phone',name,caller) - return caller.pubkey_ - except: - return - - - - - - - - -### CREATE PRIME ENTITIES -def create_phonelines(): - ## CREATE OPERATOR - op = Operator(name=OPERATOR_NAME) - op_keys_to_keep_on_client = ['pubkey'] # kept on app, stored under name - op_keys_to_keep_on_3rdparty = ['privkey_decr'] # kept on .onion site - op_keys_to_keep_on_server = ['pubkey', # stored under name - 'privkey_encr', - 'adminkey_encr', - 'adminkey_decr_encr', - 'adminkey_decr_decr'] # kept on op server - - ## create phone - phone = Operator(name=TELEPHONE_NAME) - phone_keys_to_keep_on_client = ['pubkey','privkey_encr'] # kept on app; need both to init connection - phone_keys_to_keep_on_3rdparty = ['privkey_decr'] # dl by phone - phone_keys_to_keep_on_server = ['pubkey'] # kept on op server - - # create keys for Op - op_res = op.forge_new_keys( - keys_to_save=op_keys_to_keep_on_server, - keys_to_return=op_keys_to_keep_on_client + op_keys_to_keep_on_3rdparty # on clients only - ) - op_uri = op_res['uri_id'] - op_decr_keys = op_res['_keychain'] - - print('op_uri',op_uri) - print('op_decr_keys',op_decr_keys) - - # create keys for phone - phone_res = phone.forge_new_keys( - name=TELEPHONE_NAME, - keys_to_save=phone_keys_to_keep_on_server, # on server only - keys_to_return=phone_keys_to_keep_on_client + phone_keys_to_keep_on_3rdparty # on clients only - ) - phone_uri = phone_res['uri_id'] - phone_decr_keys = phone_res['_keychain'] - - print('phone_uri',phone_uri) - print('phone_decr_keys',phone_decr_keys) - - # store URIs - # op.save_uri_as_qrcode(odir=PATH_OPERATOR_WEB_CONTACTS_DIR) - # op.save_uri_as_qrcode() - - # phone.save_uri_as_qrcode(odir=PATH_OPERATOR_WEB_CONTACTS_DIR) - # phone.save_uri_as_qrcode() - - ## store remote keys - THIRD_PARTY_DICT = {OPERATOR_NAME:{}, TELEPHONE_NAME:{}} - for key in op_keys_to_keep_on_3rdparty: - if key in op_decr_keys: - THIRD_PARTY_DICT[OPERATOR_NAME][key]=op_decr_keys[key] - for key in phone_keys_to_keep_on_3rdparty: - if key in phone_decr_keys: - THIRD_PARTY_DICT[TELEPHONE_NAME][key]=phone_decr_keys[key] - - print('THIRD_PARTY_DICT',THIRD_PARTY_DICT) - - # store local keys - STORE_IN_APP = {OPERATOR_NAME:{}, TELEPHONE_NAME:{}} - for key in op_keys_to_keep_on_client: - if key in op_decr_keys: - STORE_IN_APP[OPERATOR_NAME][key]=op_decr_keys[key] - for key in phone_keys_to_keep_on_client: - if key in phone_decr_keys: - STORE_IN_APP[TELEPHONE_NAME][key]=phone_decr_keys[key] - print('STORE_IN_APP',STORE_IN_APP) - - # package - STORE_IN_APP_pkg = package_for_transmission(STORE_IN_APP) #package_for_transmission(STORE_IN_APP[TELEPHONE_NAME]) + BSEP + package_for_transmission(STORE_IN_APP[OPERATOR_NAME]) - THIRD_PARTY_DICT_pkg = package_for_transmission(THIRD_PARTY_DICT) #package_for_transmission(THIRD_PARTY_DICT[TELEPHONE_NAME]) + BSEP + package_for_transmission(THIRD_PARTY_DICT[OPERATOR_NAME]) - print('THIRD_PARTY_DICT_pkg',THIRD_PARTY_DICT_pkg) - print('THIRD_PARTY_DICT_pkg',THIRD_PARTY_DICT_pkg) - - - # encrypt - omega_key = KomradeSymmetricKeyWithoutPassphrase() - STORE_IN_APP_encr = b64encode(omega_key.encrypt(STORE_IN_APP_pkg)) - print('STORE_IN_APP_encr',STORE_IN_APP_encr) - - THIRD_PARTY_totalpkg = b64encode(omega_key.data + BSEP + omega_key.encrypt(THIRD_PARTY_DICT_pkg)) - print('THIRD_PARTY_totalpkg',THIRD_PARTY_totalpkg) - - # save - with open(PATH_BUILTIN_KEYCHAIN,'wb') as of: - of.write(STORE_IN_APP_encr) - print('STORE_IN_APP_encr',STORE_IN_APP_encr) - - with open(PATH_OPERATOR_WEB_KEYS_FILE,'wb') as of: - of.write(THIRD_PARTY_totalpkg) - print('THIRD_PARTY_DICT_encr',THIRD_PARTY_totalpkg) - - -def connect_phonelines(): - # globals - global OMEGA_KEY,OPERATOR_KEYCHAIN,TELEPHONE_KEYCHAIN - if OMEGA_KEY and OPERATOR_KEYCHAIN and TELEPHONE_KEYCHAIN: - return (OPERATOR_KEYCHAIN,TELEPHONE_KEYCHAIN) - - print('\n\n\n\nCONNECTING PHONELINES!\n\n\n\n') - - # import - from komrade.backend.mazes import tor_request - from komrade.backend import PATH_OPERATOR_WEB_KEYS_URL - - # load local keys - if not os.path.exists(PATH_BUILTIN_KEYCHAIN): - print('builtin keys not present??') - return - with open(PATH_BUILTIN_KEYCHAIN,'rb') as f: - local_builtin_keychain_encr = b64decode(f.read()) - - # load remote keys - print('??',PATH_OPERATOR_WEB_KEYS_URL) - r = komrade_request(PATH_OPERATOR_WEB_KEYS_URL) - if r.status_code!=200: - print('cannot authenticate the keymakers') - return - - # unpack remote pkg - - pkg = r.text - print('got from onion:',pkg) - pkg = b64decode(pkg) - print('got from onion:',pkg) - - OMEGA_KEY_b,remote_builtin_keychain_encr = pkg.split(BSEP) - print('OMEGA_KEY_b',OMEGA_KEY_b) - print('remote_builtin_keychain_encr',remote_builtin_keychain_encr) - - - OMEGA_KEY = KomradeSymmetricKeyWithoutPassphrase(key=OMEGA_KEY_b) - - print('loaded Omega',OMEGA_KEY) - # from komrade.utils import unpackage_from_transmission - remote_builtin_keychain = unpackage_from_transmission(OMEGA_KEY.decrypt(remote_builtin_keychain_encr)) - print('remote_builtin_keychain',remote_builtin_keychain) - - remote_builtin_keychain_phone_json,remote_builtin_keychain_op_json = remote_builtin_keychain[TELEPHONE_NAME],remote_builtin_keychain[OPERATOR_NAME] - print('remote_builtin_keychain_phone_json',remote_builtin_keychain_phone_json) - print('remote_builtin_keychain_op_json',remote_builtin_keychain_op_json) - - # unpack local pkg - local_builtin_keychain = unpackage_from_transmission(OMEGA_KEY.decrypt(local_builtin_keychain_encr)) - print('local_builtin_keychain',local_builtin_keychain) - - local_builtin_keychain_phone_json,local_builtin_keychain_op_json = local_builtin_keychain[TELEPHONE_NAME],local_builtin_keychain[OPERATOR_NAME] - print('local_builtin_keychain_phone_json',local_builtin_keychain_phone_json) - print('local_builtin_keychain_op_json',local_builtin_keychain_op_json) - - # set builtin keychains - TELEPHONE_KEYCHAIN={} - OPERATOR_KEYCHAIN={} - dict_merge(TELEPHONE_KEYCHAIN,local_builtin_keychain_phone_json) - dict_merge(OPERATOR_KEYCHAIN,local_builtin_keychain_op_json) - dict_merge(TELEPHONE_KEYCHAIN,remote_builtin_keychain_phone_json) - dict_merge(OPERATOR_KEYCHAIN,remote_builtin_keychain_op_json) - print('>>>> loaded OPERATOR_KEYCHAIN',OPERATOR_KEYCHAIN) - print('>>>> loaded TELEPHONE_KEYCHAIN',TELEPHONE_KEYCHAIN) - return (OPERATOR_KEYCHAIN,TELEPHONE_KEYCHAIN) + def unpackage_msg_from(self,msg_encr_b,another): + return self.decrypt_from_send(msg_encr_b,anonther.pubkey,self.privkey) \ No newline at end of file diff --git a/komrade/backend/people.py b/komrade/backend/people.py new file mode 100644 index 0000000..c8ea196 --- /dev/null +++ b/komrade/backend/people.py @@ -0,0 +1,90 @@ +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 * +from komrade.backend import * + + +class Person(Caller): + + def call_person(self,person): + pass + + + def ring_ring(self,msg_unencr,whom_to_call): + # ring 1: encrypt caller2phone + msg_encr_caller2caller = self.package_msg_to( + msg_unencr, + whom_to_call + ) + self.log('msg_encr_caller2caller',msg_encr_caller2caller) + + # ring 2: use 'Caller' class to dial and get response + resp_msg_encr_caller2caller = super().ring_ring( + msg_encr_caller2caller + ) + self.log('resp_msg_encr_caller2caller',resp_msg_encr_caller2caller) + + # ring 3: decrypt and send back + resp_msg_unencr = self.unpackage_msg_from( + msg_encr_caller2caller, + whom_to_call + ) + self.log('resp_msg_unencr',resp_msg_encr_caller2caller) + + return resp_msg_unencr + + + def register(self): + # get needed metadata + if not name: name=self.name + if name is None: + name = input('\nWhat is the name for this account? ') + if passphrase is None: + passphrase = getpass.getpass('\nEnter a memborable password: ') + # if is_group is None: + # is_group = input('\nIs this a group account? [y/N]').strip().lower() == 'y' + + # form request to operator + msg_to_op = {'_please':'forge_new_keys'} + + # call and ask operator to register us + resp = self.ring_ring( + whom=self.op, + msg_unencr=msg_to_op + ) + + + def get_new_keys(self, name = None, passphrase = DEBUG_DEFAULT_PASSPHRASE, is_group=None): + # get needed metadata + if not name: name=self.name + if name is None: + name = input('\nWhat is the name for this account? ') + if passphrase is None: + passphrase = getpass.getpass('\nEnter a memborable password: ') + # if is_group is None: + # is_group = input('\nIs this a group account? [y/N]').strip().lower() == 'y' + + + + phone_res = self.phone.ring_ring(msg_to_op) + + # URI id + uri_id = phone_res.get('uri_id') + returned_keys = phone_res.get('_keychain') + self.log('got URI from Op:',uri_id) + self.log('got returnd keys from Op:',returned_keys) + + stop + + # better have the right keys + assert set(KEYMAKER_DEFAULT_KEYS_TO_SAVE_ON_CLIENT) == set(returned_keys.keys()) + + # now save these keys! + saved_keys = self.save_keychain(name,returned_keys,uri_id=uri_id) + self.log('saved keys!',saved_keys) + + # better have the right keys + # assert set(KEYMAKER_DEFAULT_KEYS_TO_SAVE) == set(saved_keys.keys()) + + # success! + self.log('yay!!!!') + return saved_keys diff --git a/komrade/backend/phonelines.py b/komrade/backend/phonelines.py new file mode 100644 index 0000000..b6d33d1 --- /dev/null +++ b/komrade/backend/phonelines.py @@ -0,0 +1,173 @@ +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 * +from komrade.backend.crypt import * +from komrade.backend.keymaker import * +from komrade.backend.mazes import * +from komrade.backend.switchboard import * + + + + + +### CREATE PRIME ENTITIES +def create_phonelines(): + ## CREATE OPERATOR + op = Operator(name=OPERATOR_NAME) + op_keys_to_keep_on_client = ['pubkey'] # kept on app, stored under name + op_keys_to_keep_on_3rdparty = ['privkey_decr'] # kept on .onion site + op_keys_to_keep_on_server = ['pubkey', # stored under name + 'privkey_encr', + 'adminkey_encr', + 'adminkey_decr_encr', + 'adminkey_decr_decr'] # kept on op server + + ## create phone + phone = Operator(name=TELEPHONE_NAME) + phone_keys_to_keep_on_client = ['pubkey','privkey_encr'] # kept on app; need both to init connection + phone_keys_to_keep_on_3rdparty = ['privkey_decr'] # dl by phone + phone_keys_to_keep_on_server = ['pubkey'] # kept on op server + + # create keys for Op + op_res = op.forge_new_keys( + keys_to_save=op_keys_to_keep_on_server, + keys_to_return=op_keys_to_keep_on_client + op_keys_to_keep_on_3rdparty # on clients only + ) + op_uri = op_res['uri_id'] + op_decr_keys = op_res['_keychain'] + + print('op_uri',op_uri) + print('op_decr_keys',op_decr_keys) + + # create keys for phone + phone_res = phone.forge_new_keys( + name=TELEPHONE_NAME, + keys_to_save=phone_keys_to_keep_on_server, # on server only + keys_to_return=phone_keys_to_keep_on_client + phone_keys_to_keep_on_3rdparty # on clients only + ) + phone_uri = phone_res['uri_id'] + phone_decr_keys = phone_res['_keychain'] + + print('phone_uri',phone_uri) + print('phone_decr_keys',phone_decr_keys) + + # store URIs + # op.save_uri_as_qrcode(odir=PATH_OPERATOR_WEB_CONTACTS_DIR) + # op.save_uri_as_qrcode() + + # phone.save_uri_as_qrcode(odir=PATH_OPERATOR_WEB_CONTACTS_DIR) + # phone.save_uri_as_qrcode() + + ## store remote keys + THIRD_PARTY_DICT = {OPERATOR_NAME:{}, TELEPHONE_NAME:{}} + for key in op_keys_to_keep_on_3rdparty: + if key in op_decr_keys: + THIRD_PARTY_DICT[OPERATOR_NAME][key]=op_decr_keys[key] + for key in phone_keys_to_keep_on_3rdparty: + if key in phone_decr_keys: + THIRD_PARTY_DICT[TELEPHONE_NAME][key]=phone_decr_keys[key] + + print('THIRD_PARTY_DICT',THIRD_PARTY_DICT) + + # store local keys + STORE_IN_APP = {OPERATOR_NAME:{}, TELEPHONE_NAME:{}} + for key in op_keys_to_keep_on_client: + if key in op_decr_keys: + STORE_IN_APP[OPERATOR_NAME][key]=op_decr_keys[key] + for key in phone_keys_to_keep_on_client: + if key in phone_decr_keys: + STORE_IN_APP[TELEPHONE_NAME][key]=phone_decr_keys[key] + print('STORE_IN_APP',STORE_IN_APP) + + # package + STORE_IN_APP_pkg = package_for_transmission(STORE_IN_APP) #package_for_transmission(STORE_IN_APP[TELEPHONE_NAME]) + BSEP + package_for_transmission(STORE_IN_APP[OPERATOR_NAME]) + THIRD_PARTY_DICT_pkg = package_for_transmission(THIRD_PARTY_DICT) #package_for_transmission(THIRD_PARTY_DICT[TELEPHONE_NAME]) + BSEP + package_for_transmission(THIRD_PARTY_DICT[OPERATOR_NAME]) + print('THIRD_PARTY_DICT_pkg',THIRD_PARTY_DICT_pkg) + print('THIRD_PARTY_DICT_pkg',THIRD_PARTY_DICT_pkg) + + + # encrypt + omega_key = KomradeSymmetricKeyWithoutPassphrase() + STORE_IN_APP_encr = b64encode(omega_key.encrypt(STORE_IN_APP_pkg)) + print('STORE_IN_APP_encr',STORE_IN_APP_encr) + + THIRD_PARTY_totalpkg = b64encode(omega_key.data + BSEP + omega_key.encrypt(THIRD_PARTY_DICT_pkg)) + print('THIRD_PARTY_totalpkg',THIRD_PARTY_totalpkg) + + # save + with open(PATH_BUILTIN_KEYCHAIN,'wb') as of: + of.write(STORE_IN_APP_encr) + print('STORE_IN_APP_encr',STORE_IN_APP_encr) + + with open(PATH_OPERATOR_WEB_KEYS_FILE,'wb') as of: + of.write(THIRD_PARTY_totalpkg) + print('THIRD_PARTY_DICT_encr',THIRD_PARTY_totalpkg) + + +def connect_phonelines(): + # globals + global OMEGA_KEY,OPERATOR_KEYCHAIN,TELEPHONE_KEYCHAIN + if OMEGA_KEY and OPERATOR_KEYCHAIN and TELEPHONE_KEYCHAIN: + return (OPERATOR_KEYCHAIN,TELEPHONE_KEYCHAIN) + + print('\n\n\n\nCONNECTING PHONELINES!\n\n\n\n') + + # import + from komrade.backend.mazes import tor_request + from komrade.backend import PATH_OPERATOR_WEB_KEYS_URL + + # load local keys + if not os.path.exists(PATH_BUILTIN_KEYCHAIN): + print('builtin keys not present??') + return + with open(PATH_BUILTIN_KEYCHAIN,'rb') as f: + local_builtin_keychain_encr = b64decode(f.read()) + + # load remote keys + print('??',PATH_OPERATOR_WEB_KEYS_URL) + r = komrade_request(PATH_OPERATOR_WEB_KEYS_URL) + if r.status_code!=200: + print('cannot authenticate the keymakers') + return + + # unpack remote pkg + + pkg = r.text + print('got from onion:',pkg) + pkg = b64decode(pkg) + print('got from onion:',pkg) + + OMEGA_KEY_b,remote_builtin_keychain_encr = pkg.split(BSEP) + print('OMEGA_KEY_b',OMEGA_KEY_b) + print('remote_builtin_keychain_encr',remote_builtin_keychain_encr) + + + OMEGA_KEY = KomradeSymmetricKeyWithoutPassphrase(key=OMEGA_KEY_b) + + print('loaded Omega',OMEGA_KEY) + # from komrade.utils import unpackage_from_transmission + remote_builtin_keychain = unpackage_from_transmission(OMEGA_KEY.decrypt(remote_builtin_keychain_encr)) + print('remote_builtin_keychain',remote_builtin_keychain) + + remote_builtin_keychain_phone_json,remote_builtin_keychain_op_json = remote_builtin_keychain[TELEPHONE_NAME],remote_builtin_keychain[OPERATOR_NAME] + print('remote_builtin_keychain_phone_json',remote_builtin_keychain_phone_json) + print('remote_builtin_keychain_op_json',remote_builtin_keychain_op_json) + + # unpack local pkg + local_builtin_keychain = unpackage_from_transmission(OMEGA_KEY.decrypt(local_builtin_keychain_encr)) + print('local_builtin_keychain',local_builtin_keychain) + + local_builtin_keychain_phone_json,local_builtin_keychain_op_json = local_builtin_keychain[TELEPHONE_NAME],local_builtin_keychain[OPERATOR_NAME] + print('local_builtin_keychain_phone_json',local_builtin_keychain_phone_json) + print('local_builtin_keychain_op_json',local_builtin_keychain_op_json) + + # set builtin keychains + TELEPHONE_KEYCHAIN={} + OPERATOR_KEYCHAIN={} + dict_merge(TELEPHONE_KEYCHAIN,local_builtin_keychain_phone_json) + dict_merge(OPERATOR_KEYCHAIN,local_builtin_keychain_op_json) + dict_merge(TELEPHONE_KEYCHAIN,remote_builtin_keychain_phone_json) + dict_merge(OPERATOR_KEYCHAIN,remote_builtin_keychain_op_json) + + print('>>>> loaded OPERATOR_KEYCHAIN',OPERATOR_KEYCHAIN) + print('>>>> loaded TELEPHONE_KEYCHAIN',TELEPHONE_KEYCHAIN) + return (OPERATOR_KEYCHAIN,TELEPHONE_KEYCHAIN) diff --git a/komrade/backend/switchboard.py b/komrade/backend/switchboard.py index e1760dc..873977a 100644 --- a/komrade/backend/switchboard.py +++ b/komrade/backend/switchboard.py @@ -7,56 +7,9 @@ from komrade.backend import * from flask import Flask, request, jsonify from flask_classful import FlaskView -# PATH_OPERATOR_WEB_KEYS_URI = hashish(b'keys') -# PATH_OPERATOR_WEB_KEYS_FILE = f'/home/ryan/www/website-komrade/.builtin.keys' -# PATH_OPERATOR_WEB_KEYS_URL = f'http://{KOMRADE_ONION}/.builtin.keys' - -# print(PATH_OPERATOR_WEB_KEYS_URL) - - -OPERATOR = None -TELEPHONE = None -from flask_classful import FlaskView, route - class TheSwitchboard(FlaskView, Logger): default_methods = ['GET'] excluded_methods = ['phone','op','send'] - - @route('/.builtin.keys/') - def keys(self): - if not os.path.exists(PATH_OPERATOR_WEB_KEYS_FILE): - self.log('no keys file exists!',PATH_OPERATOR_WEB_KEYS_FILE) - return OPERATOR_INTERCEPT_MESSAGE - with open(PATH_OPERATOR_WEB_KEYS_FILE,'rb') as f: - return f.read() - - @property - def phone(self): - global TELEPHONE - from komrade.backend.the_telephone import TheTelephone - if not TELEPHONE: TELEPHONE=TheTelephone() - return TELEPHONE - - @property - def op(self): - global OPERATOR - from komrade.backend.the_operator import TheOperator - if not OPERATOR: OPERATOR=TheOperator() - return OPERATOR - - def send(self,res): - return res - - def route(self,msg): - # give to The Operator - # try: - self.log('Success! your message was: '+str(msg)) - res = self.op.recv(msg) - self.log('Your return result should be:',res) - return self.send(res) - # except AssertionError as e: - # self.log('got exception!!',e) - return OPERATOR_INTERCEPT_MESSAGE def get(self,msg): self.log('Incoming call!:',msg) @@ -65,7 +18,10 @@ class TheSwitchboard(FlaskView, Logger): return OPERATOR_INTERCEPT_MESSAGE # unenescape msg = msg.replace('_','/') - return self.route(msg) + str_msg_from_op = self.op.route(msg) + str_msg_from_op = msg.replace('_','/') + self.log('Switchboard got msg back from Operator:',str_msg_from_op) + return str_msg_from_op def run_forever(port='8080'): global OPERATOR,TELEPHONE,TELEPHONE_KEYCHAIN,OPERATOR_KEYCHAIN diff --git a/komrade/backend/the_operator.py b/komrade/backend/the_operator.py index 987279a..a0d0bf2 100644 --- a/komrade/backend/the_operator.py +++ b/komrade/backend/the_operator.py @@ -59,32 +59,19 @@ class TheOperator(Operator): return self.send(encr_msg_to_send) - def recv(self,data): - # decrypt - self.log('recv 1: got',data) - - # answer the phone! - data_in = self.answer_phone(data, from_phone=self.phone, to_phone=self) - self.log('recv 2: answer_phone gave me',data_in) - - # route - return self.route(data_in) - # self.log('recv 3: route gave me',encr_result) - - # # send - # return self.send(encr_result) - - def send(self,encr_data_b): self.log(type(encr_data_b),encr_data_b,'sending!') return encr_data_b def route(self, data): + # route incoming call from the switchboard + + res=None - route = data.get('_route') + route = data.get('_please') if not route: return OPERATOR_INTERCEPT_MESSAGE - del data['_route'] + del data['_please'] if route == 'forge_new_keys': return self.forge_new_keys(**data) diff --git a/komrade/backend/the_telephone.py b/komrade/backend/the_telephone.py index 79608d3..53c0012 100644 --- a/komrade/backend/the_telephone.py +++ b/komrade/backend/the_telephone.py @@ -36,40 +36,44 @@ class TheTelephone(Operator): self.log("DIALING THE OPERATOR:",URL) ringring=komrade_request(URL) if ringring.status_code==200: - um_yes_hello = ringring.text - return self.answer_phone(um_yes_hello, - from_phone=self.op, - to_phone=self - ) + + # response back from Operator! + encr_str_response_from_op = ringring.text + self.log('encr_str_response_from_op',encr_str_response_from_op) + + return encr_str_response_from_op.encode() else: self.log('!! error in request',ringring.status_code,ringring.text) return None - def ring_ring(self, - from_caller=None, - to_caller=None, - json_phone2phone={}, - json_caller2phone={}, # (person) -> operator or operator -> (person) - json_caller2caller={}): - - encr_msg_to_send = super().ring_ring( - from_phone=self, - to_phone=self.op, - from_caller=from_caller, - to_caller=to_caller, - json_phone2phone=json_phone2phone, - json_caller2phone=json_caller2phone, # (person) -> operator - json_caller2caller=json_caller2caller) + def ring_ring(self,msg_encr_caller2caller_caller2phone): + + # ring 1: encrypt + msg_encr_caller2caller_caller2phone_phone2phone = self.package_msg_to( + msg_encr_caller2caller, + self.op + ) + self.log('final form of encr msg!',msg_encr_caller2caller_caller2phone_phone2phone) + + # ring 2: dial and get response + msg_encr_caller2caller_caller2phone_phone2phone = self.send_and_receive(msg_encr_caller2caller_phone2phone) + msg_encr_caller2caller_caller2phone_phone2phone: return + + # ring 3: decrypt + msg_encr_caller2caller_caller2phone = self.unpackage_msg_from( + msg_encr_caller2caller_caller2phone_phone2phone, + self.op + ) + + return msg_encr_caller2caller_caller2phone - return self.send_and_receive(encr_msg_to_send) - def test_call(): caller = Caller('marx33') #Caller('marx') # caller.boot(create=True) # print(caller.keychain()) # phone = TheTelephone() - # req_json = {'_route':'forge_new_keys','name':name, 'pubkey_is_public':pubkey_is_public}} + # req_json = {'_please':'forge_new_keys','name':name, 'pubkey_is_public':pubkey_is_public}} # req_json_s = jsonify(req_json) # res = phone.req({'forge_new_keys':{'name':'marx', 'pubkey_is_public':True}}) # print(res) diff --git a/komrade/constants.py b/komrade/constants.py index 75a7a15..1241ede 100644 --- a/komrade/constants.py +++ b/komrade/constants.py @@ -122,6 +122,9 @@ KEYMAKER_DEFAULT_KEY_TYPES = { 'privkey_decr_encr':ENCRYPTED_KEY, 'adminkey_decr_encr':ENCRYPTED_KEY } + +KEYMAKER_DEFAULT_ALL_KEY_NAMES = sorted(list(KEYMAKER_DEFAULT_KEY_TYPES.keys()), key=lambda x: x.count('_')) + WHY_MSG = 'Forge the password of memory: '