From 4bc2bf5db51c1fdd027998af6ed0bfc15b1e102e Mon Sep 17 00:00:00 2001 From: Kevin Froman Date: Mon, 14 Sep 2020 11:54:14 +0000 Subject: [PATCH] removed deterministic keys due to poor hashing --- run-onionr-node.py | 82 +++++++++++++++++++++-------- src/onionrcommands/pubkeymanager.py | 37 +++---------- src/onionrcrypto/generate.py | 4 +- 3 files changed, 69 insertions(+), 54 deletions(-) diff --git a/run-onionr-node.py b/run-onionr-node.py index b08550db..13f615ab 100755 --- a/run-onionr-node.py +++ b/run-onionr-node.py @@ -4,7 +4,7 @@ import argparse import os from threading import Thread from time import sleep -from subprocess import PIPE +from subprocess import DEVNULL import ujson from psutil import Popen @@ -12,6 +12,7 @@ from psutil import Process import psutil import sys +import curses script_dir = os.path.dirname(os.path.realpath(__file__)) sys.path.append(script_dir + '/src/') @@ -21,34 +22,66 @@ from etc import onionrvalues sub_script = script_dir + '/' + onionrvalues.SCRIPT_NAME + def show_info(p: Process): + def pbar(window): + window.addstr(8, 10, "Onionr statistics") + window.addstr(9, 10, "-" * 17) + curses.curs_set(0) + while True: + threads = p.num_threads() + open_files = len(p.open_files()) + cpu_percent = p.cpu_percent() + block_count = len(blockmetadb.get_block_list()) + for proc in p.children(recursive=True): + threads += proc.num_threads() + cpu_percent += proc.cpu_percent() + try: + open_files += len(proc.open_files()) + except psutil.AccessDenied: + pass + cpu_percent = cpu_percent * 100 + window.addstr(11, 10, f"Threads: {threads}") + window.addstr(10, 10, f"Open files: {open_files}") + window.addstr(12, 10, f"CPU: {cpu_percent}%") + window.addstr(13, 10, f"Blocks: {block_count}") + window.refresh() + sleep(0.5) + sleep(15) + curses.wrapper(pbar) while True: - threads = p.num_threads() - open_files = len(p.open_files()) - for proc in p.children(recursive=True): - threads += proc.num_threads() - try: - open_files += len(proc.open_files()) - except psutil.AccessDenied: - pass - print(f'Approximate thread count: {threads}') - print(f'Approximate open files: {open_files}') sleep(1) parser = argparse.ArgumentParser() parser.add_argument( - "--skip-onboarding", help="Skip Onionr onboarding", - type=bool, default=False) + "--show-stats", help="Display curses output of Onionr stats", + type=int, default=0) parser.add_argument( - '--open-ui', help='Open onionr web ui after started' , - type=bool, default=True) + "--skip-onboarding", help="Skip Onionr onboarding", + type=int, default=0) +parser.add_argument( + "--security-level", help="Set Onionr security level", + type=int, default=0) +parser.add_argument( + '--open-ui', help='Open onionr web ui after started', + type=int, default=1) +parser.add_argument( + '--random-localhost-ip', help='bind to random localhost IP for extra security', + type=int, default=1) +parser.add_argument( + '--use-tor', help='Use Tor transport', + type=int, default=1) +parser.add_argument( + '--private-key', help='Use existing private key', + type=int, default=1) args = parser.parse_args() -p = Popen([sub_script, 'version']) +p = Popen([sub_script, 'version'], stdout=DEVNULL) p.wait() from filepaths import config_file +from coredb import blockmetadb @@ -58,18 +91,25 @@ with open(config_file, 'r') as cf: if args.skip_onboarding: config['onboarding']['done'] = True print('Disabling onboarding') - +if not args.random_localhost_ip: + print('Disabling randomized localhost') + config['general']['random_bind_ip'] = False +if not args.use_tor: + config['transports']['tor'] = False +config['general']['display_header'] = False +config['general']['security_level'] = args.security_level with open(config_file, 'w') as cf: cf.write(ujson.dumps(config)) if args.open_ui: - p = Popen([sub_script, 'start']) + p = Popen([sub_script, 'start'], stdout=DEVNULL) sleep(2) - Popen([sub_script, 'openhome']) + Popen([sub_script, 'openhome'], stdout=DEVNULL) else: - p = Popen([sub_script, 'start'], stdout=PIPE) + p = Popen([sub_script, 'start'], stdout=DEVNULL) p = p.children()[0] -Thread(target=show_info, args=[p], daemon=True).start() +if args.show_stats: + Thread(target=show_info, args=[p], daemon=True).start() p.wait() diff --git a/src/onionrcommands/pubkeymanager.py b/src/onionrcommands/pubkeymanager.py index a99e55a5..cd072874 100755 --- a/src/onionrcommands/pubkeymanager.py +++ b/src/onionrcommands/pubkeymanager.py @@ -38,6 +38,7 @@ DETERMINISTIC_REQUIREMENT = onionrvalues.PASSWORD_LENGTH def add_ID(): """Command to create a new user ID key pair.""" key_manager = keymanager.KeyManager() + pw = "" try: sys.argv[2] # pylint: disable=W0104 if not sys.argv[2].lower() == 'true': @@ -45,36 +46,8 @@ def add_ID(): except (IndexError, ValueError): newID = key_manager.addKey()[0] else: - logger.warn( - 'Deterministic keys require random and long passphrases.', - terminal=True) - logger.warn( - 'If a good passphrase is not used, your key can be easily stolen.', - terminal=True) - logger.warn( - 'You should use a series of hard to guess words, ' + - 'see this for reference: https://www.xkcd.com/936/', - terminal=True) - try: - pass1 = getpass.getpass( - prompt='Enter at least %s characters: ' % - (DETERMINISTIC_REQUIREMENT,)) - pass2 = getpass.getpass(prompt='Confirm entry: ') - except KeyboardInterrupt: - sys.exit(42) - if onionrcrypto.cryptoutils.safe_compare(pass1, pass2): - try: - logger.info( - 'Generating deterministic key. This can take a while.', - terminal=True) - newID, privKey = onionrcrypto.generate_deterministic(pass1) - except onionrexceptions.PasswordStrengthError: - logger.error('Passphrase must use at least %s characters.' % ( - DETERMINISTIC_REQUIREMENT,), terminal=True) - sys.exit(1) - else: - logger.error('Passwords do not match.', terminal=True) - sys.exit(1) + pw = "-".join(niceware.generate_passphrase(32)) + newID, privKey = onionrcrypto.generate_deterministic(pw) try: key_manager.addKey(pubKey=newID, privKey=privKey) @@ -83,8 +56,10 @@ def add_ID(): 'That ID is already available, you can change to it ' + 'with the change-id command.', terminal=True) return + if pw: + print("Phrase to restore ID:", pw) logger.info('Added ID: %s' % - (bytesconverter.bytes_to_str(newID),), terminal=True) + (bytesconverter.bytes_to_str(newID.replace('=', '')),), terminal=True) add_ID.onionr_help = "If the first argument is true, " # type: ignore diff --git a/src/onionrcrypto/generate.py b/src/onionrcrypto/generate.py index 7fab9c16..5b6c1e4b 100644 --- a/src/onionrcrypto/generate.py +++ b/src/onionrcrypto/generate.py @@ -9,7 +9,7 @@ def generate_pub_key(): return (public_key.decode(), private_key.encode(encoder=nacl.encoding.Base32Encoder()).decode()) def generate_deterministic(passphrase, bypassCheck=False): - '''Generate a Ed25519 public key pair from a password''' + '''Generate a Ed25519 public key pair from a phase, not intended for human-generated key''' passStrength = onionrvalues.PASSWORD_LENGTH passphrase = bytesconverter.str_to_bytes(passphrase) # Convert to bytes if not already # Validate passphrase length @@ -18,7 +18,7 @@ def generate_deterministic(passphrase, bypassCheck=False): raise onionrexceptions.PasswordStrengthError("Passphase must be at least %s characters" % (passStrength,)) # KDF values kdf = nacl.pwhash.argon2id.kdf - salt = b"U81Q7llrQcdTP0Ux" # Does not need to be unique or secret, but must be 16 bytes + salt = b"U81Q7llrQcdTP0Ux" # Does not need to be secret, but must be 16 bytes ops = nacl.pwhash.argon2id.OPSLIMIT_SENSITIVE mem = nacl.pwhash.argon2id.MEMLIMIT_SENSITIVE