From e6929ae7c79b0408aca5afa28dfc9adec2d80ab3 Mon Sep 17 00:00:00 2001 From: quadrismegistus Date: Thu, 20 Aug 2020 02:39:26 +0100 Subject: [PATCH] decryption!? --- app/main.py | 5 +- p2p/.keys.global.json | 1 + p2p/api.py | 114 ++++++++++++++++++++++++++++++++++-------- p2p/crypto.py | 41 +++++++++++---- 4 files changed, 128 insertions(+), 33 deletions(-) create mode 100644 p2p/.keys.global.json diff --git a/app/main.py b/app/main.py index 32665b3..7a9027e 100644 --- a/app/main.py +++ b/app/main.py @@ -44,8 +44,8 @@ dutchwhite=229,219,181 COLOR_TOOLBAR= smokyblack #5,5,5 #russiangreen #pinetreegreen #kombugreen #(12,5,5) #russiangreen COLOR_BG = (0,73,54) # COLOR_ICON = (201,203,163) -COLOR_LOGO = grullo#russiangreen #(0,0,0) #(0,0,0) #(151,177,140) #(132,162,118) #(109,140,106) -COLOR_ICON = grullo#russiangreen #(0,0,0) #COLOR_LOGO +COLOR_LOGO = dutchwhite#russiangreen #(0,0,0) #(0,0,0) #(151,177,140) #(132,162,118) #(109,140,106) +COLOR_ICON = dutchwhite#russiangreen #(0,0,0) #COLOR_LOGO COLOR_TEXT =dutchwhite #(241,233,203) #COLOR_ICON #(207,219,204) #(239,235,206) # (194,211,187) # (171,189,163) # (222,224,198) # COLOR_LOGO #(223, 223, 212) COLOR_CARD = smokyblack #skin2 #huntergreen #(30,23,20) #(51,73,45) # (67,92,61) #(12,9,10) # COLOR_TOOLBAR = (8s9,59,43) @@ -221,6 +221,7 @@ class MainApp(MDApp): title = 'Komrade' logged_in=False store = JsonStore('../p2p/.keys.json') + store_global = JsonStore('../p2p/.keys.global.json') login_expiry = 60 * 60 * 24 * 7 # once a week texture = ObjectProperty() diff --git a/p2p/.keys.global.json b/p2p/.keys.global.json new file mode 100644 index 0000000..c380777 --- /dev/null +++ b/p2p/.keys.global.json @@ -0,0 +1 @@ +{"_keys": {"private": "-----BEGIN PRIVATE KEY-----\nMIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCwc6j5VyvdRgtx\nLhXgHnJg4qqzJjXHiJyQJhYEPChBzoI1prqspOaHPE2d9BY5ArqOzoKmZop8TUi8\npzbnQO5v44m//PqnLx17CM25E5r83TqBK2bAD8appm9kktZZ5/EVjkceKZLat0lD\nSXRI7Xaphhn8WtRJ2zexcMcs/wQamrh5/J86GWPbuqHnPM79Cd+56RWkY+ou3Eqr\ng5Xka5QZJNzXeIHe2tQvTAfMwlAHVfV9qMkf9Ui4R3TUhc9Tp++vNHdfctVAakIG\n5TAVkMVAe6ruIw5VUO9kttsJ3EJRVuNjbmwUcpT3UG+XD9lZ6bX3SOtmjP425Umm\nE4d3oUT/AgMBAAECggEAB5cCBq+kOGFh7p1f3YMRwm8djpUvLQUITv8EZWw9Aw+h\n9DLWxsRVEi4a3Jd6OTuP0MK7RfMVM+GTJmI+71WQrAlqjHKSSYyyRO+NAdABE61k\nbdfzFIHZNsTs97OFOtrKOPYkwvxgz72gjh9jvBtSxln5ViyGAyNF0wEZ4Cqb/5Tj\n37v/8Vyb34EEFHKip3pHDlsbBKEHWMLElc89JgbzL1xxo9jeHetKwzTkLYu+VxBc\nZAoFwwCuMFxBEUgacIEoPUAT5zDxP89dOPF4MTId78bCphDft1XdsH4iu66knwPm\nddMIDgtv1f4JkZXtE4mUbexh0VLVDGzmTffJ/tSTMQKBgQDUigVEMBDbkJRA7BxR\nIjy8CE8MZwqmnR6V4I+qn+qoIX/ydPYx3T5RQ8viO3LnxXK90ZlCmy+xVOks2u62\n/lAY9WULm+Z3fY8+n/Lhm9TETk5UHfQmiwqYRUH0t4iktsXZ2zaOb1MbuFcxGH7h\nd7tSYlMo3w8xsNQAt9sc5G8WVwKBgQDUiIrdOzQZ2wG6etW+aXlFax3clYXyITbR\nhyHIdlnDKhQpHBVXSmfegRmVrmCUxd10euTFW8Z7agxUXhqd3PZrnv3nJ0Y4GLVS\nvoSAiyRtBbqyASynqFlRXn8M17IfrZb81+gkvoF4kkKRzbWv6wVvhf46nCM5qCB5\nnjTJgimNmQKBgClmkUwNCNucOCTFWWa8gpQmEi/aSorWBEUxrwqPiAgkLmYuPl7M\nN/1gdXCmH+Xh4k3zbCU7UXj7j0g7hVCEDVovQvWV8rjH7oVGZutnjXSHxF5CT3LK\nls++ffCLZ8SeDcA4IVJxgQDfUaywltaYmhacLJLDkJQfW8ygA8CHBtSVAoGAD3c0\nK68gNnVyZcCEh0ujkIKf9KpIyfrSw2KC+dRq6cHJH8i0YNrAPjfExdifnJPdbpl2\nxknMYrSv2v/SDgTDRceXEFgSSwi5QSEuATCe4PQWxtdBCZ49iadHtYaIprd6EkIf\n2XSndT+nana+ruN6TMhCXL957LsoSdFSZAt9vJkCgYAoMBzZOWkPUZOuGAWGtgLo\n+CIlYWGYC8My4ynrOBXKQnVs/9ZCEupFm8PBDCkDlkdjUCRQEeYBItg4SKs4IhxX\niODoNMK+phXRRgiH9uZkV6c5wqeyLPIvDU0o62tS7jArApHXC07OS4kN+nGkMABK\nhNwy7RjbFtiLZJN85LKLLQ==\n-----END PRIVATE KEY-----\n", "public": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsHOo+Vcr3UYLcS4V4B5y\nYOKqsyY1x4ickCYWBDwoQc6CNaa6rKTmhzxNnfQWOQK6js6CpmaKfE1IvKc250Du\nb+OJv/z6py8dewjNuROa/N06gStmwA/GqaZvZJLWWefxFY5HHimS2rdJQ0l0SO12\nqYYZ/FrUSds3sXDHLP8EGpq4efyfOhlj27qh5zzO/QnfuekVpGPqLtxKq4OV5GuU\nGSTc13iB3trUL0wHzMJQB1X1fajJH/VIuEd01IXPU6fvrzR3X3LVQGpCBuUwFZDF\nQHuq7iMOVVDvZLbbCdxCUVbjY25sFHKU91Bvlw/ZWem190jrZoz+NuVJphOHd6FE\n/wIDAQAB\n-----END PUBLIC KEY-----\n"}} \ No newline at end of file diff --git a/p2p/api.py b/p2p/api.py index 34c1223..cc8b9cb 100644 --- a/p2p/api.py +++ b/p2p/api.py @@ -9,7 +9,7 @@ import asyncio,time # logger.setLevel(logging.DEBUG) sys.path.append('../p2p') # logger.info(os.getcwd(), sys.path) - +BSEP=b'||||' try: from .crypto import * @@ -90,7 +90,7 @@ class Api(object): # self.log('Yawn, getting tired. Going to sleep') # self.root.ids.btn1.trigger_action() - #i += 1 + i += 1 await asyncio.sleep(60) # pass except asyncio.CancelledError as e: @@ -119,18 +119,18 @@ class Api(object): if type(key_or_keys) in {list,tuple,dict}: keys = key_or_keys - res = await asyncio.gather(*[node.get(key) for key in keys]) + res = await asyncio.gather(*[self.unpack_well_documented_val(await node.get(key)) for key in keys]) #log('RES?',res) else: key = key_or_keys - res = await node.get(key) + res = await self.unpack_well_documented_val(await node.get(key)) #node.stop() return res return await _get() - def well_documented_val(self,val): + def well_documented_val(self,val,sep=BSEP,encrypt=True): """ What do we want to store with @@ -139,17 +139,23 @@ class Api(object): 3) Public key of author 4) Signature of value by author """ - from binascii import a2b_uu as ascii2binary - from binascii import b2a_uu as binary2ascii - timestamp=time.time() self.log('timestamp =',timestamp) - value = str(val) - try: - value_bytes = value.encode('utf-8') - except UnicodeDecodeError: - value_bytes = value.encode('ascii') + if type(val)!=bytes: + value = str(val) + try: + value_bytes = value.encode('utf-8') + except UnicodeDecodeError: + value_bytes = value.encode('ascii') + else: + value_bytes=val + + + # encrypt? + self.log('value while unencrypted =',value_bytes) + value_bytes = encrypt_msg(value_bytes, self.public_key_global) + self.log('value while encrypted = ',value_bytes) #self.log('value =',value) @@ -161,20 +167,46 @@ class Api(object): signature = sign_msg(value_bytes, self.private_key) self.log('signature =',signature) + ## Verify! + authentic = verify_msg(value_bytes,signature,self.public_key) + self.log('message is authentic for set??',authentic) + # value_bytes_ascii = ''.join([chr(x) for x in value_bytes]) # jsond = {'time':timestamp, 'val':value_bytes_ascii, 'pub':pem_public_key, 'sign':signature} # jsonstr=jsonify(jsond) - sep=b'||||' + WDV = sep.join([str(timestamp).encode(), value_bytes,pem_public_key,signature]) # self.log('WDV = 'mWD) # self.log(WDV.split(sep)) - self.log('well_documented_val() =',WDV) + # self.log('well_documented_val() =',WDV) return WDV + async def unpack_well_documented_val(self,WDV,sep=BSEP): + self.log('WDV???',WDV) + time,val,pub,sign = WDV.split(sep) + pub=load_public_key(pub) + + # verify + authentic = verify_msg(val,sign,pub) + self.log('message is authentic for GET?',authentic) + + if not authentic: + self.log('inauthentic message!') + return None + + # decrypt + self.log('val before decryption = ',val) + val = decrypt_msg(val, self.private_key_global) + self.log('val after decryption = ',val) + + time=float(time.decode()) + #val=val.decode() + return time,val,pub,sign + async def set(self,key_or_keys,value_or_values): async def _set(): @@ -203,12 +235,26 @@ class Api(object): res = await self.get(key_or_keys) self.log('GET_JSON',res) if type(res)==list: - # self.log('is a list!',json.loads(res[0])) - return [None if x is None else json.loads(x) for x in res] + jsonl=[] + for time,val,pub,sign in res: + dat=json.loads(val.decode()) + if type(dat)==dict: + dat['_time']=time + dat['_pub']=pub + dat['_sign']=sign + jsonl.append(dat) + return jsonl else: #log('RES!!!',res) - return None if res is None else json.loads(res) + time,val,pub,sign = res + dat = None if res is None else json.loads(val.decode()) + if type(dat)==dict: + dat['_time']=time + dat['_pub']=pub + dat['_sign']=sign + self.log('RETURNING -->',dat) + return dat async def set_json(self,key,value): @@ -241,6 +287,8 @@ class Api(object): if person is not None: return {'error':'Username already exists'} private_key,public_key = new_keys(password=passkey,save=False) + self._private_key = private_key + self._public_key = public_key pem_private_key = save_private_key(private_key,password=passkey,return_instead=True) pem_public_key = save_public_key(public_key,return_instead=True) @@ -248,10 +296,11 @@ class Api(object): private=str(pem_private_key.decode()), public=str(pem_public_key.decode())) #(private_key,password=passkey) await self.set_person(name,public_key) - - return {'success':'Account created', 'username':name} + + + def load_private_key(self,password): if not self.app_storage.exists('_keys'): return {'error':'No login keys present on this device'} pem_private_key=self.app_storage.get('_keys').get('private') @@ -307,6 +356,29 @@ class Api(object): self.app.root.change_screen('login') return self._private_key + @property + def public_key_global(self): + if not hasattr(self,'_public_key_global'): + try: + pem=self.app.store_global.get('_keys').get('public',None) + self._public_key_global=load_public_key(pem.encode()) + return self._public_key_global + except ValueError as e: + self.log('!!',e) + return None + + @property + def private_key_global(self): + if not hasattr(self,'_private_key_global'): + try: + pem=self.app.store_global.get('_keys').get('private',None) + self._private_key_global=load_private_key(pem.encode()) + return self._private_key_global + except ValueError as e: + self.log('!!',e) + return None + + async def append_json(self,key,data): sofar=await self.get_json(key) if sofar is None: sofar = [] @@ -364,7 +436,7 @@ class Api(object): self.log('file_store!?',file_store) keys = ['/part/'+x for x in file_store['parts']] - pieces = await self.get(keys) + time,pieces,pub,sign = await self.get(keys) file_store['parts_data']=pieces return file_store diff --git a/p2p/crypto.py b/p2p/crypto.py index 6a01dd4..a61b71f 100644 --- a/p2p/crypto.py +++ b/p2p/crypto.py @@ -3,6 +3,7 @@ from cryptography.hazmat.primitives.asymmetric import rsa from cryptography.hazmat.primitives import serialization from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.asymmetric import padding +from cryptography.exceptions import InvalidSignature import os key_dir = os.path.join(os.path.expanduser('~'),'.keys','komrade') @@ -104,15 +105,20 @@ def sign_msg(message, private_key): ) def verify_msg(message, signature, public_key): - return public_key.verify( - signature, - message, - padding.PSS( - mgf=padding.MGF1(hashes.SHA256()), - salt_length=padding.PSS.MAX_LENGTH - ), - hashes.SHA256() - ) + try: + verified = public_key.verify( + signature, + message, + padding.PSS( + mgf=padding.MGF1(hashes.SHA256()), + salt_length=padding.PSS.MAX_LENGTH + ), + hashes.SHA256() + ) + return True + except InvalidSignature: + return False + return None @@ -135,4 +141,19 @@ def verify_msg(message, signature, public_key): # #print(encrypt_msg(b'hello',public_key)) -# print(verify_msg(msg+b'!!',signature,public_key)) \ No newline at end of file +# print(verify_msg(msg+b'!!',signature,public_key)) + + + +## ONLY NEEDS RUN ONCE! +def gen_global_keys(fn='.keys.global.json'): + from kivy.storage.jsonstore import JsonStore + + private_key,public_key=new_keys(save=False,password=None) + pem_private_key = save_private_key(private_key,password=None,return_instead=True) + pem_public_key = save_public_key(public_key,return_instead=True) + + store = JsonStore('./.keys.global.json') + + store.put('_keys',private=str(pem_private_key.decode()),public=str(pem_public_key.decode())) #(private_key,password=passkey) +