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-06 14:45:40 +00:00
from abc import ABC , abstractmethod
2020-09-11 14:35:47 +00:00
# common external imports
from pythemis . skeygen import KEY_PAIR_TYPE , GenerateKeyPair
from pythemis . smessage import SMessage , ssign , sverify
from pythemis . skeygen import GenerateSymmetricKey
from pythemis . scell import SCellSeal
from pythemis . exception import ThemisError
2020-09-06 14:45:40 +00:00
2020-09-10 21:32:59 +00:00
class KomradeKey ( ABC , Logger ) :
2020-09-06 14:45:40 +00:00
@abstractmethod
def encrypt ( self , msg , * * kwargs ) : pass
@abstractmethod
def decrypt ( self , msg , * * kwargs ) : pass
@abstractmethod
def data ( self ) : pass
2020-09-10 14:58:54 +00:00
@property
2020-09-12 14:52:55 +00:00
def data_b64 ( self ) : return b64encode ( self . data ) if type ( self . data ) == bytes else self . data . data_b64
2020-09-10 14:58:54 +00:00
@property
2020-09-12 20:19:53 +00:00
def data_b64_s ( self ) :
2020-09-12 20:20:06 +00:00
return self . data_b64 . decode ( )
2020-09-12 20:19:53 +00:00
@property
2020-09-10 15:02:26 +00:00
def discreet ( self ) : return make_key_discreet ( self . data )
2020-09-11 14:35:47 +00:00
def __str__ ( self ) :
return repr ( self )
2020-09-06 13:07:27 +00:00
2020-09-06 14:45:40 +00:00
class KomradeSymmetricKey ( KomradeKey ) :
2020-09-06 13:07:27 +00:00
@property
def cell ( self ) :
if not hasattr ( self , ' _cell ' ) :
if hasattr ( self , ' passphrase ' ) and self . passphrase :
2020-09-12 15:33:12 +00:00
self . _cell = SCellSeal ( passphrase = hasher ( self . passphrase ) )
2020-09-06 13:07:27 +00:00
elif hasattr ( self , ' key ' ) and self . key :
2020-09-06 14:45:40 +00:00
self . _cell = SCellSeal ( key = self . key )
return self . _cell
def encrypt ( self , msg , * * kwargs ) :
2020-09-12 15:34:51 +00:00
if hasattr ( msg , ' data ' ) : msg = msg . data
2020-09-12 15:43:16 +00:00
# print('??? dec',msg,kwargs)
2020-09-12 15:34:08 +00:00
2020-09-06 14:45:40 +00:00
return self . cell . encrypt ( msg , * * kwargs )
def decrypt ( self , msg , * * kwargs ) :
2020-09-12 15:34:51 +00:00
if hasattr ( msg , ' data ' ) : msg = msg . data
2020-09-12 15:43:16 +00:00
# print('??? dec',msg,kwargs)
2020-09-12 15:34:08 +00:00
2020-09-12 15:29:17 +00:00
try :
return self . cell . decrypt ( msg , * * kwargs )
except TypeError :
return self . cell . decrypt ( msg . data , * * kwargs )
2020-09-10 21:32:59 +00:00
2020-09-11 14:35:47 +00:00
2020-09-10 21:32:59 +00:00
def getpass_status ( passphrase = None ) :
while not passphrase :
passphrase1 = getpass ( f ' @Keymaker: What is a *memorable* pass word or phrase? Do not write it down. \n @ { name } : ' )
passphrase2 = getpass ( f ' @Keymaker: Could you repeat that? ' )
if passphrase1 != passphrase2 :
self . status ( ' @Keymaker: Those passwords didn \' t match. Please try again. ' , clear = False , pause = False )
else :
return passphrase1
2020-09-12 07:55:23 +00:00
# get_pass_func = getpass_status if SHOW_STATUS else getpass
from getpass import getpass
2020-09-06 13:07:27 +00:00
2020-09-06 14:45:40 +00:00
class KomradeSymmetricKeyWithPassphrase ( KomradeSymmetricKey ) :
2020-09-12 14:32:03 +00:00
def hash ( self , x ) : return self . crypt_keys . hash ( x )
2020-09-08 07:20:42 +00:00
def __init__ ( self , passphrase = DEBUG_DEFAULT_PASSPHRASE , why = WHY_MSG ) :
2020-09-13 06:34:30 +00:00
if not passphrase :
# raise KomradeException
self . passphrase = getpass ( why )
else :
self . passphrase = passphrase
# if passphrase: self.passphrase=passphrase
2020-09-12 14:32:03 +00:00
2020-09-06 14:45:40 +00:00
@property
def data ( self ) : return KEY_TYPE_SYMMETRIC_WITH_PASSPHRASE . encode ( ' utf-8 ' )
2020-09-12 07:55:23 +00:00
def __repr__ ( self ) : return f ' [Symmetric Key] (generated by password) '
2020-09-06 13:07:27 +00:00
2020-09-06 14:45:40 +00:00
class KomradeSymmetricKeyWithoutPassphrase ( KomradeSymmetricKey ) :
2020-09-07 14:51:59 +00:00
def __init__ ( self , key = None ) :
self . key = GenerateSymmetricKey ( ) if not key else key
2020-09-06 14:45:40 +00:00
@property
def data ( self ) : return self . key
2020-09-12 07:55:23 +00:00
def __repr__ ( self ) : return f ' [Symmetric Key] \n ( { self . discreet } ) '
2020-09-06 14:45:40 +00:00
class KomradeAsymmetricKey ( KomradeKey ) :
2020-09-11 14:35:47 +00:00
def __init__ ( self , pubkey = None , privkey = None ) :
if not pubkey or not privkey :
keypair = GenerateKeyPair ( KEY_PAIR_TYPE . EC )
privkey = keypair . export_private_key ( )
pubkey = keypair . export_public_key ( )
2020-09-06 14:45:40 +00:00
self . pubkey = pubkey
2020-09-11 14:35:47 +00:00
self . privkey = privkey
self . privkey_obj = KomradeAsymmetricPrivateKey ( privkey , pubkey )
self . pubkey_obj = KomradeAsymmetricPublicKey ( pubkey , privkey )
2020-09-06 14:45:40 +00:00
def encrypt ( self , msg , pubkey = None , privkey = None ) :
2020-09-12 15:32:23 +00:00
if issubclass ( type ( msg ) , KomradeKey ) or issubclass ( type ( msg ) , KomradeEncryptedKey ) : msg = msg . data
2020-09-06 14:45:40 +00:00
pubkey = pubkey if pubkey else self . pubkey
privkey = privkey if privkey else self . privkey
return SMessage ( privkey , pubkey ) . wrap ( msg )
def decrypt ( self , msg , pubkey = None , privkey = None ) :
2020-09-12 15:32:23 +00:00
if issubclass ( type ( msg ) , KomradeKey ) or issubclass ( type ( msg ) , KomradeEncryptedKey ) : msg = msg . data
2020-09-06 14:45:40 +00:00
pubkey = pubkey if pubkey else self . pubkey
privkey = privkey if privkey else self . privkey
2020-09-12 15:32:23 +00:00
return SMessage ( privkey . data , pubkey . data ) . unwrap ( msg )
2020-09-06 14:45:40 +00:00
@property
def data ( self ) : return self . key
2020-09-10 14:35:54 +00:00
2020-09-06 14:45:40 +00:00
class KomradeAsymmetricPublicKey ( KomradeAsymmetricKey ) :
2020-09-10 21:32:59 +00:00
def __init__ ( self , pubkey , privkey = None ) :
self . pubkey = pubkey
self . privkey = privkey
2020-09-06 14:45:40 +00:00
@property
def key ( self ) : return self . pubkey
2020-09-10 14:58:54 +00:00
@property
def data ( self ) : return self . pubkey
2020-09-12 07:55:23 +00:00
def __repr__ ( self ) : return f ''' [Asymmetric Public Key] \n ( { self . data_b64 . decode ( ) } ) '''
2020-09-06 14:45:40 +00:00
class KomradeAsymmetricPrivateKey ( KomradeAsymmetricKey ) :
2020-09-10 21:32:59 +00:00
def __init__ ( self , privkey , pubkey = None ) :
self . pubkey = pubkey
self . privkey = privkey
2020-09-10 14:58:54 +00:00
@property
def data ( self ) : return self . privkey
2020-09-06 14:45:40 +00:00
@property
def key ( self ) : return self . privkey
2020-09-12 07:55:23 +00:00
def __repr__ ( self ) : return f ''' [Asymmetric Private Key] \n ( { self . discreet } ) '''
2020-09-06 13:07:27 +00:00
2020-09-13 07:59:46 +00:00
def make_key_discreet ( data , chance_unredacted = 0.25 ) :
2020-09-10 21:32:59 +00:00
import random
if not data : return ' ? '
if not isBase64 ( data ) : data = b64encode ( data )
key = data . decode ( )
2020-09-13 07:47:51 +00:00
return ' ' . join ( ( k if random . random ( ) < chance_unredacted else ' - ' ) for k in key )
# return ''.join((k if not i%6 or not i%3 else '-') for i,k in enumerate(key))
2020-09-13 07:46:04 +00:00
2020-09-10 21:32:59 +00:00
2020-09-13 07:59:46 +00:00
def make_key_discreet_str ( string , chance_unredacted = 0.25 ) :
2020-09-11 14:35:47 +00:00
import random
if not string : return ' ? '
2020-09-12 07:55:23 +00:00
return ' ' . join ( ( k if random . random ( ) < chance_unredacted else ' - ' ) for k in string )
2020-09-11 14:35:47 +00:00
2020-09-10 21:32:59 +00:00
def make_key_discreet1 ( data , len_start = 10 , len_end = 10 , ellipsis = ' . ' , show_len = True ) :
2020-09-10 15:01:33 +00:00
if not data : return ' ? '
if not isBase64 ( data ) : data = b64encode ( data )
data = data . decode ( )
2020-09-10 15:07:57 +00:00
amt_missing = len ( data ) - len_start - len_end
2020-09-10 15:08:57 +00:00
dstr = data [ : len_start ] + ( ellipsis * amt_missing )
2020-09-10 15:06:41 +00:00
if len_end : dstr + = data [ - len_end : ]
2020-09-10 15:07:57 +00:00
return f ' { dstr } ' #' (+{len(data)-len_start-len_end})'
2020-09-10 14:45:48 +00:00
2020-09-10 21:32:59 +00:00
class KomradeEncryptedKey ( Logger ) :
2020-09-10 14:45:48 +00:00
def __init__ ( self , data ) : self . data = data
2020-09-10 14:47:23 +00:00
@property
2020-09-10 14:58:54 +00:00
def data_b64 ( self ) : return b64encode ( self . data ) . decode ( )
2020-09-12 07:55:23 +00:00
def __repr__ ( self ) : return f ' [Encrypted Key] \n ( { self . discreet } ) '
2020-09-10 15:01:33 +00:00
@property
2020-09-10 15:02:26 +00:00
def discreet ( self ) : return make_key_discreet ( self . data )
2020-09-11 14:35:47 +00:00
def __str__ ( self ) :
return repr ( self )
2020-09-10 14:45:48 +00:00
class KomradeEncryptedAsymmetricPrivateKey ( KomradeEncryptedKey ) :
2020-09-12 07:55:23 +00:00
def __repr__ ( self ) : return f ' [Encrypted Asymmetric Private Key] \n ( { self . discreet } ) '
2020-09-10 14:45:48 +00:00
class KomradeEncryptedAsymmetricPublicKey ( KomradeEncryptedKey ) :
2020-09-12 07:55:23 +00:00
def __repr__ ( self ) : return f ' [Encrypted Asymmetric Public Key] \n ( { self . discreet } ) '
2020-09-10 14:45:48 +00:00
class KomradeEncryptedSymmetricKey ( KomradeEncryptedKey ) :
2020-09-12 07:55:23 +00:00
def __repr__ ( self ) : return f ' [Encrypted Symmetric Key] \n ( { self . discreet } ) '
2020-09-10 14:45:48 +00:00
2020-09-12 14:32:03 +00:00
KEYMAKER_DEFAULT_KEY_TYPES = {
' pubkey ' : KomradeAsymmetricPublicKey ,
' privkey ' : KomradeAsymmetricPrivateKey ,
' adminkey ' : KomradeSymmetricKeyWithoutPassphrase ,
2020-09-10 14:45:48 +00:00
2020-09-12 14:32:03 +00:00
' pubkey_decr ' : KomradeSymmetricKeyWithoutPassphrase ,
' privkey_decr ' : KomradeSymmetricKeyWithPassphrase ,
' adminkey_decr ' : KomradeSymmetricKeyWithPassphrase ,
' pubkey_decr_decr ' : KomradeSymmetricKeyWithoutPassphrase ,
' privkey_decr_decr ' : KomradeSymmetricKeyWithPassphrase ,
' adminkey_decr_decr ' : KomradeSymmetricKeyWithPassphrase ,
' pubkey_encr_decr ' : KomradeSymmetricKeyWithoutPassphrase ,
' privkey_encr_decr ' : KomradeSymmetricKeyWithPassphrase ,
' adminkey_encr_decr ' : KomradeSymmetricKeyWithPassphrase ,
2020-09-10 14:45:48 +00:00
2020-09-12 14:32:03 +00:00
# encrypted keys
' pubkey_encr ' : KomradeEncryptedAsymmetricPublicKey ,
' privkey_encr ' : KomradeEncryptedAsymmetricPrivateKey ,
' adminkey_encr ' : KomradeEncryptedSymmetricKey ,
' pubkey_encr_encr ' : KomradeEncryptedSymmetricKey ,
' privkey_encr_encr ' : KomradeEncryptedSymmetricKey ,
' adminkey_encr_encr ' : KomradeEncryptedSymmetricKey ,
' pubkey_decr_encr ' : KomradeEncryptedSymmetricKey ,
' privkey_decr_encr ' : KomradeEncryptedSymmetricKey ,
' adminkey_decr_encr ' : KomradeEncryptedSymmetricKey
}
2020-09-10 14:45:48 +00:00
2020-09-12 14:32:03 +00:00
def get_key_obj ( keyname , data , passphrase = None , key_types = KEYMAKER_DEFAULT_KEY_TYPES ) :
return key_types [ keyname ] ( data )
2020-09-10 14:45:48 +00:00
2020-09-04 15:37:12 +00:00
class Keymaker ( Logger ) :
2020-09-08 07:01:35 +00:00
def __init__ ( self ,
name = None ,
2020-09-08 07:20:42 +00:00
passphrase = DEBUG_DEFAULT_PASSPHRASE ,
2020-09-08 07:01:35 +00:00
uri_id = None ,
keychain = { } ,
2020-09-10 10:25:49 +00:00
path_crypt_keys = PATH_CRYPT_CA_KEYS ,
path_crypt_data = PATH_CRYPT_CA_DATA ) :
2020-09-08 07:01:35 +00:00
# set defaults
2020-09-05 14:09:31 +00:00
self . name = name
2020-09-08 08:13:35 +00:00
self . _uri_id = uri_id
2020-09-08 11:23:41 +00:00
self . _pubkey = None
2020-09-07 17:11:52 +00:00
self . _keychain = keychain
2020-09-05 14:09:31 +00:00
self . passphrase = passphrase
2020-09-06 09:48:01 +00:00
self . path_crypt_keys = path_crypt_keys
self . path_crypt_data = path_crypt_data
2020-09-05 14:09:31 +00:00
2020-09-09 14:38:37 +00:00
2020-09-12 20:19:53 +00:00
def find_pubkey ( self , name = None ) :
2020-09-12 21:30:37 +00:00
if not name : name = self . name
if ' pubkey ' in self . _keychain and self . _keychain [ ' pubkey ' ] :
return self . _keychain [ ' pubkey ' ]
res = self . crypt_keys . get ( name , prefix = ' /pubkey/ ' )
2020-09-12 21:43:37 +00:00
# self.log('result from crypt for name:',res)
2020-09-12 21:30:37 +00:00
# if res: return res
res = self . load_qr ( self . name )
# if res: return res
2020-09-09 14:38:37 +00:00
2020-09-12 21:30:37 +00:00
if not res : return
if type ( res ) == str : res = res . encode ( )
if isBase64 ( res ) : res = b64decode ( res )
return res
# self.log('I don\'t know my public key! Do I need to register?')
# raise KomradeException(f'I don\'t know my public key!\n{self}\n{self._keychain}')
# return res
def find_name ( self , pubkey_b64 ) :
2020-09-12 21:41:28 +00:00
q = pubkey_b64 . decode ( ) if type ( pubkey_b64 ) != str else pubkey_b64
2020-09-12 21:31:34 +00:00
print ( ' Q? ' , q )
res = self . crypt_keys . get ( q , prefix = ' /name/ ' )
2020-09-12 21:43:37 +00:00
# self.log('result from crypt for name:',res)
2020-09-12 21:30:37 +00:00
return res
2020-09-12 20:19:53 +00:00
2020-09-09 18:31:36 +00:00
@property
def keys ( self ) :
return sorted ( list ( self . keychain ( ) . keys ( ) ) )
@property
def top_keys ( self ) :
return [ k for k in self . keys if k . count ( ' _ ' ) == 0 ]
2020-09-08 11:23:41 +00:00
2020-09-12 14:32:03 +00:00
def load_keychain_from_bytes ( self , keychain ) :
for keyname , keyval in keychain . items ( ) :
keychain [ keyname ] = get_key_obj ( keyname , keyval )
return keychain
2020-09-12 20:19:53 +00:00
def find_pubkey_and_name ( self , name = None , pubkey = None ) :
2020-09-12 21:30:37 +00:00
if not pubkey : pubkey = self . _keychain . get ( ' pubkey ' )
2020-09-12 20:19:53 +00:00
if not name : name = self . name
if pubkey :
2020-09-12 21:40:29 +00:00
# print('??',pubkey)
2020-09-12 20:19:53 +00:00
if hasattr ( pubkey , ' data ' ) :
pubkey = pubkey . data_b64
else :
pubkey = b64encode ( pubkey ) if not isBase64 ( pubkey ) else pubkey
2020-09-12 21:32:12 +00:00
# if name and pubkey:
2020-09-12 20:19:53 +00:00
# make sure they match
2020-09-12 20:22:53 +00:00
#assert self.find_pubkey(name) == self.find_name(pubkey)
2020-09-12 21:32:12 +00:00
# if self.find_pubkey(name) != self.find_name:
# pass
2020-09-12 20:56:15 +00:00
# self.log(f'! {name} and {pubkey} do not match?')
2020-09-12 21:32:12 +00:00
if name and not pubkey :
2020-09-12 20:19:53 +00:00
pubkey = self . find_pubkey ( name )
elif pubkey and not name :
self . name = self . find_name ( pubkey )
2020-09-12 21:34:25 +00:00
# else:
# self.log('error! Neither name nor pubkey! Who am I?')
# return (None,None)
2020-09-12 20:19:53 +00:00
2020-09-12 21:36:19 +00:00
if pubkey :
2020-09-12 21:38:46 +00:00
# self.log('!?!?!?!?',type(pubkey),pubkey)
pubkey = b64decode ( pubkey ) if isBase64 ( pubkey ) else pubkey
2020-09-12 21:36:19 +00:00
pubkey = KomradeEncryptedAsymmetricPublicKey ( pubkey )
2020-09-12 20:19:53 +00:00
self . _keychain [ ' pubkey ' ] = pubkey
self . name = name
return ( name , pubkey )
2020-09-08 11:23:41 +00:00
def keychain ( self , look_for = KEYMAKER_DEFAULT_ALL_KEY_NAMES ) :
2020-09-09 14:38:37 +00:00
# load existing keychain
2020-09-12 20:19:53 +00:00
keys = self . _keychain
2020-09-09 14:38:37 +00:00
# make sure we have the pubkey
2020-09-12 20:21:25 +00:00
name , pubkey = self . find_pubkey_and_name ( )
2020-09-09 14:38:37 +00:00
# get uri
2020-09-12 21:33:49 +00:00
if pubkey :
2020-09-12 21:36:19 +00:00
uri = pubkey . data_b64
2020-09-12 21:33:49 +00:00
#uri = b64encode(pubkey) if type(pubkey)==bytes else b64encode(pubkey.encode())
# get from cache
for keyname in look_for :
2020-09-13 06:09:00 +00:00
# print(self.name,'looking for key:',keyname)
2020-09-12 21:33:49 +00:00
if keyname in keys and keys [ keyname ] : continue
key = self . crypt_keys . get ( uri , prefix = f ' / { keyname } / ' )
2020-09-13 06:09:00 +00:00
# print('found in crypt:',key,'for',keyname)
2020-09-13 06:08:11 +00:00
if key : keys [ keyname ] = get_key_obj ( keyname , key )
2020-09-08 15:14:48 +00:00
2020-09-08 11:23:41 +00:00
# try to assemble
2020-09-12 19:19:08 +00:00
keys = self . assemble ( self . assemble ( keys ) )
2020-09-09 14:38:37 +00:00
#store to existing set
self . _keychain = keys
#return
2020-09-08 11:23:41 +00:00
return keys
2020-09-11 14:35:47 +00:00
2020-09-09 14:38:37 +00:00
@property
def pubkey ( self ) : return self . keychain ( ) . get ( ' pubkey ' )
2020-09-08 11:23:41 +00:00
@property
2020-09-10 08:19:08 +00:00
def pubkey_b64 ( self ) : return b64encode ( self . pubkey ) #self.keychain().get('pubkey')
@property
2020-09-08 15:14:48 +00:00
def privkey ( self ) : return self . keychain ( ) . get ( ' privkey ' )
2020-09-08 11:23:41 +00:00
@property
2020-09-08 15:14:48 +00:00
def adminkey ( self ) : return self . keychain ( ) . get ( ' adminkey ' )
2020-09-09 17:34:19 +00:00
@property
def pubkey_encr ( self ) : return self . keychain ( ) . get ( ' pubkey_encr ' )
@property
def privkey_encr ( self ) : return self . keychain ( ) . get ( ' privkey_encr ' )
@property
def adminkey_encr ( self ) : return self . keychain ( ) . get ( ' adminkey_encr ' )
@property
def pubkey_decr ( self ) : return self . keychain ( ) . get ( ' pubkey_decr ' )
@property
def privkey_decr ( self ) : return self . keychain ( ) . get ( ' privkey_decr ' )
@property
def adminkey_decr ( self ) : return self . keychain ( ) . get ( ' adminkey_decr ' )
2020-09-08 11:23:41 +00:00
def load_qr ( self , name ) :
# try to load?
contact_fnfn = os . path . join ( PATH_QRCODES , name + ' .png ' )
2020-09-08 15:31:16 +00:00
if not os . path . exists ( contact_fnfn ) : return ' '
2020-09-08 11:23:41 +00:00
# with open(contact_fnfn,'rb') as f: dat=f.read()
from pyzbar . pyzbar import decode
from PIL import Image
2020-09-08 15:14:48 +00:00
res = decode ( Image . open ( contact_fnfn ) ) [ 0 ] . data
2020-09-08 11:23:41 +00:00
2020-09-08 15:14:48 +00:00
# self.log('QR??',res,b64decode(res))
return b64decode ( res )
2020-09-08 11:23:41 +00:00
2020-09-08 08:13:35 +00:00
@property
def uri_id ( self ) :
2020-09-08 15:14:48 +00:00
if not self . _uri_id :
2020-09-12 20:19:53 +00:00
pubkey = self . pubkey #find_pubkey()
2020-09-13 09:46:10 +00:00
self . _uri_id = pubkey . data_b64
2020-09-08 08:13:35 +00:00
return self . _uri_id
2020-09-05 14:09:31 +00:00
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:48:01 +00:00
self . _crypt_keys = Crypt ( fn = self . path_crypt_keys )
2020-09-04 12:46:22 +00:00
return self . _crypt_keys
2020-09-06 16:29:27 +00:00
@property
def crypt_keys_mem ( self ) :
if not hasattr ( self , ' _crypt_keys_mem ' ) :
self . _crypt_keys_mem = CryptMemory ( )
return self . _crypt_keys_mem
2020-09-04 12:46:22 +00:00
@property
def crypt_data ( self ) :
if not hasattr ( self , ' _crypt_data ' ) :
2020-09-06 09:48:01 +00:00
self . _crypt_data = Crypt ( fn = self . path_crypt_data )
2020-09-04 12:46:22 +00:00
return self . _crypt_data
2020-09-09 17:34:19 +00:00
def can_log_in ( self ) :
if not self . pubkey : return False
if not ( self . privkey or self . privkey_encr ) : return False
return True
2020-09-04 15:50:08 +00:00
### CREATING KEYS
2020-09-06 13:07:27 +00:00
def get_new_keys ( self ) :
raise KomradeException ( ' Every keymaker must make their own get_new_keys() ! ' )
2020-09-07 23:34:27 +00:00
2020-09-08 07:20:42 +00:00
def gen_keys_from_types ( self , key_types = KEYMAKER_DEFAULT_KEY_TYPES , passphrase = DEBUG_DEFAULT_PASSPHRASE ) :
2020-09-08 06:58:54 +00:00
"""
Get new asymmetric / symmetric keys , given a dictionary of constants describing their type
"""
2020-09-11 14:35:47 +00:00
# print('bbbbb')
2020-09-08 06:58:54 +00:00
2020-09-06 13:07:27 +00:00
asymmetric_pubkey = None
asymmetric_privkey = None
2020-09-06 17:25:03 +00:00
keychain = { }
2020-09-12 15:03:59 +00:00
2020-09-12 15:12:04 +00:00
self . log ( ' got key types: ' , dict_format ( key_types ) )
2020-09-12 14:32:03 +00:00
# gen keys requested
for key_name , key_class in key_types . items ( ) :
## asymmetric?
if issubclass ( key_class , KomradeAsymmetricKey ) :
if not asymmetric_privkey or asymmetric_pubkey :
asymmetric_keys = KomradeAsymmetricKey ( )
asymmetric_pubkey = asymmetric_keys . pubkey_obj
asymmetric_privkey = asymmetric_keys . privkey_obj
2020-09-12 15:11:12 +00:00
if key_class == KomradeAsymmetricPublicKey :
keychain [ key_name ] = asymmetric_pubkey
elif key_class == KomradeAsymmetricPrivateKey :
keychain [ key_name ] = asymmetric_privkey
elif key_class == KomradeSymmetricKeyWithPassphrase :
keychain [ key_name ] = KomradeSymmetricKeyWithPassphrase ( passphrase )
else :
2020-09-12 20:57:09 +00:00
# print('??',key_name,key_class)
2020-09-12 15:12:52 +00:00
keychain [ key_name ] = key_class ( None )
2020-09-11 14:35:47 +00:00
2020-09-12 15:10:34 +00:00
self . log ( ' keytypes -> keychain ' , dict_format ( keychain ) )
2020-09-06 14:45:40 +00:00
return keychain
2020-09-06 13:07:27 +00:00
2020-09-07 23:34:27 +00:00
2020-09-12 15:09:26 +00:00
2020-09-06 13:07:27 +00:00
2020-09-07 14:02:46 +00:00
2020-09-06 13:07:27 +00:00
def forge_new_keys ( self ,
2020-09-06 14:45:40 +00:00
name = None ,
2020-09-08 07:20:42 +00:00
passphrase = DEBUG_DEFAULT_PASSPHRASE ,
2020-09-08 09:17:09 +00:00
keys_to_save = KEYMAKER_DEFAULT_KEYS_TO_SAVE_ON_SERVER ,
keys_to_return = KEYMAKER_DEFAULT_KEYS_TO_SAVE_ON_CLIENT ,
2020-09-06 14:45:40 +00:00
keys_to_gen = KEYMAKER_DEFAULT_KEYS_TO_GEN ,
2020-09-11 14:35:47 +00:00
key_types = KEYMAKER_DEFAULT_KEY_TYPES ,
save_keychain = True ,
return_keychain = True ,
return_all_keys = False ) :
2020-09-10 09:31:32 +00:00
# setup
2020-09-06 14:45:40 +00:00
keys_to_gen = set ( keys_to_gen ) | set ( keys_to_save ) | set ( keys_to_return )
keys_to_gen = sorted ( list ( keys_to_gen ) , key = lambda x : x . count ( ' _ ' ) )
2020-09-12 15:22:55 +00:00
key_types = dict ( [ ( k , key_types [ k ] ) for k in keys_to_gen if k ] )
2020-09-10 09:31:32 +00:00
if not name : name = self . name
2020-09-11 14:35:47 +00:00
2020-09-10 21:32:59 +00:00
2020-09-10 09:31:32 +00:00
# show user what's happening
self . log ( f '''
Keymaker ( { self } ) is forging new keys for { name }
2020-09-12 14:33:11 +00:00
''' + (f '''
2020-09-11 14:35:47 +00:00
* I will save these keys in this crypt : { ' , ' . join ( keys_to_save ) }
''' if save_keychain else ' ' ) #+ # '''
# * I will also save this user's pubkey (as b64 URI) to:
# {self.get_path_qrcode(name=name)}
# ''' + (f'''
+ ( f '''
* I will return these keys to you : { ' , ' . join ( keys_to_return ) }
''' if return_keychain else ' ' )
+ f '''
* I will forge these keys for you : { ' , ' . join ( keys_to_gen ) }
* I will be using these key types to do so :
{ dict_format ( key_types , tab = 4 ) }
''' )
2020-09-10 21:32:59 +00:00
2020-09-10 09:31:32 +00:00
2020-09-06 14:45:40 +00:00
2020-09-10 10:46:48 +00:00
# gen decryptor keys!
2020-09-07 07:26:32 +00:00
keychain = self . gen_keys_from_types ( key_types , passphrase = passphrase )
2020-09-10 10:46:48 +00:00
# gen encrypted keys!
2020-09-12 15:44:39 +00:00
self . log ( ' I built this keychain v1! ' , dict_format ( keychain , tab = 2 ) )
2020-09-11 14:35:47 +00:00
2020-09-12 15:09:26 +00:00
keychain = self . disassemble ( keychain , passphrase = passphrase )
2020-09-12 15:20:31 +00:00
self . log ( ' I built this keychain! ' , dict_format ( keychain , tab = 2 ) )
2020-09-12 14:32:03 +00:00
self . status ( ' @Keymaker: I ended up building these keys: ' , keychain )
2020-09-08 09:14:42 +00:00
2020-09-11 14:35:47 +00:00
2020-09-07 08:13:08 +00:00
# save keys!
2020-09-11 14:35:47 +00:00
if save_keychain :
# get URI id to save under (except for pubkeys, accessible by name)
uri_id , keys_saved_d , keychain = self . save_keychain ( name , keychain , keys_to_save )
2020-09-12 14:54:48 +00:00
self . log ( f ' Trying to save these keys ( { keys_to_save } ), I saved this keychain: ' , dict_format ( keys_saved_d , tab = 2 ) , ' using the generated-from-pubkey URI ID ' , uri_id )
2020-09-07 08:13:08 +00:00
# return keys!
2020-09-11 14:35:47 +00:00
if return_all_keys :
return keychain
2020-09-10 09:31:32 +00:00
2020-09-11 14:35:47 +00:00
if return_keychain :
keys_returned = self . return_keychain ( keychain , keys_to_return )
2020-09-12 14:32:03 +00:00
self . log ( ' I am returning this keychain: ' , dict_format ( keys_returned , tab = 2 ) )
2020-09-11 14:35:47 +00:00
# return (uri_id,keys_returned)
return keys_returned
2020-09-10 21:32:59 +00:00
2020-09-11 14:35:47 +00:00
raise KomradeException ( ' What did you want me to do here? ' )
2020-09-07 08:13:08 +00:00
2020-09-07 23:34:27 +00:00
def return_keychain ( self , keychain , keys_to_return = None ) :
2020-09-07 08:13:08 +00:00
keychain_toreturn = { }
2020-09-08 07:18:07 +00:00
if not keys_to_return : keys_to_return = list ( keychain . keys ( ) )
2020-09-07 08:13:08 +00:00
for key in keys_to_return :
if key in keychain :
keychain_toreturn [ key ] = keychain [ key ]
return keychain_toreturn
2020-09-10 09:31:32 +00:00
def get_path_qrcode ( self , name = None , dir = None , ext = ' .png ' ) :
if not name : name = self . name
if not dir : dir = PATH_QRCODES
fnfn = os . path . join ( dir , name + ext )
return fnfn
2020-09-10 12:28:36 +00:00
@property
2020-09-10 12:52:07 +00:00
def qr ( self ) : return self . qr_str ( data = self . uri_id )
def qr_str ( self , data = None ) :
2020-09-11 14:35:47 +00:00
data = self . uri_id if not data else data
return get_qr_str ( data )
2020-09-10 12:24:06 +00:00
2020-09-10 09:31:32 +00:00
def save_uri_as_qrcode ( self , uri_id = None , name = None ) :
if not uri_id : uri_id = self . uri_id
2020-09-08 07:13:48 +00:00
if not uri_id and not self . uri_id : raise KomradeException ( ' Need URI id to save! ' )
2020-09-10 09:31:32 +00:00
if not name : name = self . name
2020-09-08 07:13:48 +00:00
# gen
import pyqrcode
2020-09-08 07:20:42 +00:00
qr = pyqrcode . create ( uri_id )
2020-09-10 09:31:32 +00:00
ofnfn = self . get_path_qrcode ( name = name )
2020-09-08 07:32:44 +00:00
qr . png ( ofnfn , scale = 5 )
2020-09-10 12:24:06 +00:00
2020-09-10 12:28:36 +00:00
self . _uri_id = uri_id
2020-09-10 12:30:20 +00:00
self . log ( f ''' Saved URI(=pubkey_b64) as a QR code: { ofnfn } { self . qr } ''' )
2020-09-13 09:46:10 +00:00
return ofnfn
2020-09-07 08:13:08 +00:00
2020-09-08 06:58:54 +00:00
def save_keychain ( self , name , keychain , keys_to_save = None , uri_id = None ) :
2020-09-07 23:34:27 +00:00
if not keys_to_save : keys_to_save = list ( keychain . keys ( ) )
2020-09-10 15:34:26 +00:00
if not uri_id and ' pubkey ' in keychain :
uri_id = b64encode ( keychain [ ' pubkey ' ] . data ) . decode ( ) #uri_id = get_random_id() + get_random_id()
2020-09-10 09:31:32 +00:00
# self.log(f'SAVING KEYCHAIN FOR {name} under URI {uri_id}')
2020-09-08 08:13:35 +00:00
self . _uri_id = uri_id
2020-09-06 14:45:40 +00:00
# filter for transfer
for k , v in keychain . items ( ) :
if issubclass ( type ( v ) , KomradeKey ) :
v = v . data
keychain [ k ] = v
2020-09-07 08:13:08 +00:00
2020-09-07 23:34:27 +00:00
# save keychain
keys_saved_d = { }
for keyname in keys_to_save :
2020-09-08 08:34:01 +00:00
if not ' _ ' in keyname and keyname != ' pubkey ' :
2020-09-11 14:35:47 +00:00
self . log ( ' there is no private property in a socialist network! all keys must be split between komrades ' , keyname )
2020-09-07 23:34:27 +00:00
if keyname in keychain :
2020-09-08 09:14:42 +00:00
# uri = uri_id
2020-09-09 17:52:54 +00:00
uri = uri_id if keyname != ' pubkey ' else name
2020-09-10 15:34:26 +00:00
if not uri : raise KomradeException ( ' invalid URI! {uri} ' )
2020-09-10 14:50:07 +00:00
val = keychain [ keyname ]
if issubclass ( type ( keychain [ keyname ] ) , KomradeKey ) or issubclass ( type ( keychain [ keyname ] ) , KomradeEncryptedKey ) :
val = val . data
self . crypt_keys . set ( uri , val , prefix = f ' / { keyname } / ' )
2020-09-07 23:34:27 +00:00
keys_saved_d [ keyname ] = keychain [ keyname ]
2020-09-07 08:13:08 +00:00
2020-09-09 15:35:38 +00:00
# save pubkey as QR
if not ' pubkey ' in keys_saved_d :
2020-09-10 11:02:41 +00:00
# self.log('did not save pubkey in crypt, storing as QR...')
2020-09-10 09:31:32 +00:00
self . save_uri_as_qrcode ( name = name , uri_id = uri_id )
# set to my keychain right away
self . _keychain = keychain
2020-09-09 15:35:38 +00:00
2020-09-08 07:16:22 +00:00
return ( uri_id , keys_saved_d , keychain )
2020-09-06 18:02:18 +00:00
2020-09-12 15:09:26 +00:00
def assemble ( self , keychain , passphrase = None , key_types = KEYMAKER_DEFAULT_KEY_TYPES , decrypt = True ) :
2020-09-12 14:32:03 +00:00
encr_keys = [ k for k in keychain . keys ( ) if k . endswith ( ' _encr ' ) ]
for encr_key_name in encr_keys :
decr_key_name = encr_key_name [ : - 5 ] + ' _decr '
unencr_key_name = encr_key_name [ : - 5 ]
2020-09-12 15:20:31 +00:00
# self.log(encr_key_name,decr_key_name,unencr_key_name)
if decrypt and unencr_key_name in keychain : continue
2020-09-12 14:32:03 +00:00
if not decr_key_name in keychain :
2020-09-13 06:25:31 +00:00
keychain [ decr_key_name ] = KomradeSymmetricKeyWithPassphrase ( passphrase = passphrase if passphrase else self . passphrase )
2020-09-12 19:22:26 +00:00
else :
continue
2020-09-12 14:32:03 +00:00
decr_key = keychain . get ( decr_key_name )
2020-09-13 07:08:07 +00:00
# self.log('?',decr_key,decr_key_name,encr_key_name,keychain[encr_key_name])
2020-09-12 16:45:21 +00:00
try :
if decrypt :
encr_key = keychain . get ( encr_key_name )
2020-09-13 07:08:15 +00:00
# self.log(f'about to decrypt {encr_key} with {decr_key}')
2020-09-12 16:45:21 +00:00
unencr_key = decr_key . decrypt ( encr_key . data )
2020-09-12 18:18:37 +00:00
keychain [ unencr_key_name ] = get_key_obj ( unencr_key_name , unencr_key )
2020-09-12 16:45:21 +00:00
else :
2020-09-13 07:08:15 +00:00
# unencr_key = keychain.get(unencr_key_name)
2020-09-13 06:46:53 +00:00
self . log ( f ' about to encrypt { unencr_key } with { decr_key } ' )
2020-09-12 16:45:21 +00:00
encr_key = decr_key . encrypt ( unencr_key . data )
2020-09-12 18:18:37 +00:00
keychain [ encr_key_name ] = get_key_obj ( encr_key_name , encr_key )
2020-09-13 06:46:53 +00:00
except ThemisError as e :
self . log ( ' error!! ' , decrypt , decr_key , encr_key , decr_key_name , encr_key_name )
2020-09-12 16:45:21 +00:00
pass
2020-09-12 15:09:26 +00:00
2020-09-12 14:32:03 +00:00
return keychain
2020-09-06 14:45:40 +00:00
2020-09-12 15:09:26 +00:00
def disassemble ( self , keychain , * * kwargs ) :
return self . assemble ( keychain , decrypt = False , * * kwargs )
2020-09-06 14:45:40 +00:00
if __name__ == ' __main__ ' :
keymaker = Keymaker ( ' marx69 ' )
keychain = keymaker . forge_new_keys ( )
print ( keychain )