diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 2e5db9c0b26786e1c94c716eb2169bad4ccf4e8b..0449525ceec96e1249e88663a94bc114194d70e6 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -4,7 +4,9 @@ Changelog
 -------
 * New hive node has been added (https://hived.emre.sh)
 * Add option to use a derived WIF from coldcard hardware wallet to derive a new account password
-* beempy keygen and beempy importaccount have now a new option import-coldcard
+* beempy passwordgen and beempy importaccount have now a new option import-coldcard
+* beempy passwordgen handles now password generation and import, whereas beempy keygen handles BIP39 related key generation.
+* refactoring and better unit testing
 
 0.24.19
 -------
diff --git a/beem/cli.py b/beem/cli.py
index c838fda781bf63fc82a39fbb304c8a5dde28df00..b2481e3dbb53ce978fb8332aa1fbf0a889c86ab0 100644
--- a/beem/cli.py
+++ b/beem/cli.py
@@ -7,8 +7,6 @@ from prettytable import PrettyTable
 from datetime import datetime, timedelta
 import calendar
 import pytz
-import secrets
-import string
 import time
 import hashlib
 import math
@@ -35,7 +33,7 @@ from beem.memo import Memo
 from beem.asset import Asset
 from beem.witness import Witness, WitnessesRankedByVote, WitnessesVotedByAccount
 from beem.blockchain import Blockchain
-from beem.utils import formatTimeString, construct_authorperm, derive_beneficiaries, derive_tags, seperate_yaml_dict_from_body, derive_permlink, make_patch
+from beem.utils import formatTimeString, construct_authorperm, derive_beneficiaries, derive_tags, seperate_yaml_dict_from_body, derive_permlink, make_patch, create_new_password, import_coldcard_wif, generate_password, import_pubkeys, import_custom_json
 from beem.vote import AccountVotes, ActiveVotes, Vote
 from beem import exceptions
 from beem.version import version as __version__
@@ -807,51 +805,19 @@ def delkey(confirm, pub):
 @click.option('--passphrase', '-p', help='Sets a BIP39 passphrase', is_flag=True, default=False)
 @click.option('--path', '-m', help='Sets a path for BIP39 key creations. When path is set, network, role, account_keys, account and sequence is not used')
 @click.option('--network', '-n', help='Network index, when using BIP39, 0 for steem and 13 for hive, (default is 13)', default=13)
-@click.option('--role', '-r', help='Defines the key role for BIP39 when a single key is generated (default = owner).', default="owner")
+@click.option('--role', '-r', help='Defines which key role should be created (default = owner).', default="owner")
 @click.option('--account-keys', '-k', help='Derives four BIP39 keys for each role', is_flag=True, default=False)
 @click.option('--sequence', '-s', help='Sequence key number, when using BIP39 (default is 0)', default=0)
-@click.option('--account', '-a', help='account name for password based key generation or sequence number for BIP39 key, default = 0')
-@click.option('--import-password', '-i', help='Imports a password and derives all four account keys', is_flag=True, default=False)
-@click.option('--import-coldcard', '-o', help='Text file with a BIP85 WIF generated by a coldcard. The imported WIF is used to derives all four account keys')
-@click.option('--create-password', '-c', help='Creates a new password and derives four account keys from it', is_flag=True, default=False)
-@click.option('--wif', '-w', help='Defines how many times the password is replaced by its WIF representation for password based keys (default = 0).', default=0)
+@click.option('--account', '-a', help='sequence number for BIP39 key, default = 0')
+@click.option('--wif', '-w', help='Defines how many times the password is replaced by its WIF representation for password based keys (default = 0).')
 @click.option('--export-pub', '-u', help='Exports the public account keys to a json file for account creation or keychange')
 @click.option('--export', '-e', help='The results are stored in a text file and will not be shown')
-def keygen(import_word_list, strength, passphrase, path, network, role, account_keys, sequence, account, import_password, import_coldcard, create_password, wif, export_pub, export):
-    """ Creates a new random BIP39 key or password based key and prints its derived private key and public key.
+def keygen(import_word_list, strength, passphrase, path, network, role, account_keys, sequence, account, wif, export_pub, export):
+    """ Creates a new random BIP39 key and prints its derived private key and public key.
         The generated key is not stored. Can also be used to create new keys for an account.
-        Can also be used to derive account keys from a password or BIP39 wordlist
+        Can also be used to derive account keys from a password or BIP39 wordlist.
     """
     stm = shared_blockchain_instance()
-    if not account and (import_password or create_password or import_coldcard):
-        account = stm.config["default_account"]
-    if import_password:
-        import_password = click.prompt("Enter password", confirmation_prompt=False, hide_input=True)
-    elif import_coldcard is not None:
-        next_var = ""
-        import_password = ""
-        path = ""
-        with open(import_coldcard) as fp: 
-            for line in fp:
-                if line.strip() == "":
-                    continue
-                if line.strip() == "WIF (privkey):":
-                    next_var = "wif"
-                    continue
-                elif "Path Used" in line.strip():
-                    next_var = "path"
-                    continue
-                if next_var == "wif":
-                    import_password = line.strip()
-                elif next_var == "path":
-                    path = line
-                next_var = ""        
-    elif create_password:
-        alphabet = string.ascii_letters + string.digits
-        while True:
-            import_password = ''.join(secrets.choice(alphabet) for i in range(32))
-            if (any(c.islower() for c in import_password) and any(c.isupper() for c in import_password) and any(c.isdigit() for c in import_password)):
-                break
     pub_json = {"owner": "", "active": "", "posting": "", "memo": ""}
 
     if not account_keys and len(role.split(",")) > 1:
@@ -859,34 +825,12 @@ def keygen(import_word_list, strength, passphrase, path, network, role, account_
         account_keys = True
     else:
         roles = ['owner', 'active', 'posting', 'memo']
+    if wif is not None:
+        wif = int(wif)
+    else:
+        wif = 0
 
-    if import_password or create_password or import_coldcard:
-        if wif > 0:
-            password = import_password
-            for _ in range(wif):
-                pk = PasswordKey("", password, role="")
-                password = str(pk.get_private())
-            password = 'P' + password
-        else:
-            password = import_password
-        t = PrettyTable(["Key", "Value"])
-        t_pub = PrettyTable(["Key", "Value"])
-        t.add_row(["Username", account])
-        t_pub.add_row(["Username", account])
-        if import_coldcard:
-            t_pub.add_row(["cold card path", path])
-        t.align = "l"
-        t_pub.align = "l"
-        for r in roles:
-            pk = PasswordKey(account, password, role=r)
-            t.add_row(["%s Private Key" % r, str(pk.get_private())])
-            t_pub.add_row(["%s Public Key" % r, format(pk.get_public(), "STM")])
-            pub_json[r] = format(pk.get_public(), "STM")
-        t.add_row(["Backup (Master) Password", password])
-        if wif > 0:
-            t.add_row(["WIF itersions", wif])
-            t.add_row(["Entered/created Password", import_password])
-    elif stm.use_ledger:
+    if stm.use_ledger:
         if stm.rpc is not None:
             stm.rpc.rpcconnect()
         ledgertx = stm.new_tx()
@@ -950,7 +894,7 @@ def keygen(import_word_list, strength, passphrase, path, network, role, account_
                     print(" ".join(word_array))
                 word_list = " ".join(word_array)
             if passphrase:
-                passphrase = import_password = click.prompt("Enter passphrase", confirmation_prompt=True, hide_input=True)
+                passphrase = click.prompt("Enter passphrase", confirmation_prompt=True, hide_input=True)
             else:
                 passphrase = ""
             mk = MnemonicKey(word_list=word_list, passphrase=passphrase, account_sequence=account, key_sequence=sequence)
@@ -965,7 +909,7 @@ def keygen(import_word_list, strength, passphrase, path, network, role, account_
             else:
                 mk.set_path_BIP48(network_index=network, role=role, account_sequence=account, key_sequence=sequence)
             if passphrase:
-                passphrase = import_password = click.prompt("Enter passphrase", confirmation_prompt=True, hide_input=True)
+                passphrase = click.prompt("Enter passphrase", confirmation_prompt=True, hide_input=True)
             else:
                 passphrase = ""
             word_list = mk.generate_mnemonic(passphrase=passphrase, strength=strength)
@@ -1010,6 +954,79 @@ def keygen(import_word_list, strength, passphrase, path, network, role, account_
         print(t)
 
 
+@cli.command()
+@click.option('--role', '-r', help='Defines which key role should be created. When owner is not set as role and an cold card wif is imported, the Master Password is not shown. (default = owner,active,posting,memo when creating account keys).', default="owner,active,posting,memo")
+@click.option('--account', '-a', help='account name for password based key generation')
+@click.option('--import-password', '-i', help='Imports a password and derives all four account keys', is_flag=True, default=False)
+@click.option('--import-coldcard', '-o', help='Text file with a BIP85 WIF generated by a coldcard. The imported WIF is used to derives all four account keys')
+@click.option('--wif', '-w', help='Defines how many times the password is replaced by its WIF representation for password based keys (default = 0 or 1 when importing a cold card wif).')
+@click.option('--export-pub', '-u', help='Exports the public account keys to a json file for account creation or keychange')
+@click.option('--export', '-e', help='The results are stored in a text file and will not be shown')
+def passwordgen(role, account, import_password, import_coldcard, wif, export_pub, export):
+    """ Creates a new password based key and prints its derived private key and public key.
+        The generated key is not stored. The password is used to create new keys for an account.
+    """
+    stm = shared_blockchain_instance()
+    if not account:
+        account = stm.config["default_account"]
+    if import_password:
+        import_password = click.prompt("Enter password", confirmation_prompt=False, hide_input=True)
+    elif import_coldcard is not None:
+        import_password, path = import_coldcard_wif(import_coldcard)
+    else:
+        import_password = create_new_password(length=32)
+    pub_json = {"owner": "", "active": "", "posting": "", "memo": ""}
+
+    if len(role.split(",")) > 1:
+        roles = role.split(",")
+    elif role in ['owner', 'active', 'posting', 'memo']:
+        roles = [role]
+    else:
+        roles = ['owner', 'active', 'posting', 'memo']
+    if wif is not None:
+        wif = int(wif)
+    elif import_coldcard:
+        wif = 1
+    else:
+        wif = 0
+
+    password = generate_password(import_password, wif)
+    t = PrettyTable(["Key", "Value"])
+    t_pub = PrettyTable(["Key", "Value"])
+    t.add_row(["Username", account])
+    t_pub.add_row(["Username", account])
+    if import_coldcard:
+        t_pub.add_row(["cold card path", path])
+    t.align = "l"
+    t_pub.align = "l"
+    for r in roles:
+        pk = PasswordKey(account, password, role=r)
+        t.add_row(["%s Private Key" % r, str(pk.get_private())])
+        t_pub.add_row(["%s Public Key" % r, format(pk.get_public(), "STM")])
+        pub_json[r] = format(pk.get_public(), "STM")
+    if "owner" in roles or import_coldcard is None:
+        t.add_row(["Backup (Master) Password", password])
+    if wif > 0:
+        t.add_row(["WIF itersions", wif])
+        if "owner" in roles or import_coldcard is None:
+            t.add_row(["Entered/created Password", import_password])
+
+    if export_pub and export_pub != "":
+        pub_json = json.dumps(pub_json, indent=4)
+        with open(export_pub, 'w') as fp:
+            fp.write(pub_json)
+        print("%s was sucessfully saved." % export_pub)
+    if export and export != "":
+        with open(export, 'w') as fp:
+            fp.write(str(t))
+            fp.write("\n")
+            fp.write(str(t_pub))
+        print("%s was sucessfully saved." % export)
+    else:
+        print(t_pub)
+        print(t)
+
+
 @cli.command()
 @click.argument('name')
 @click.option('--unsafe-import-token',
@@ -1973,18 +1990,7 @@ def changekeys(account, owner, active, posting, memo, import_pub, export):
     account = Account(account, blockchain_instance=stm)
 
     if import_pub and import_pub != "":
-        if not os.path.isfile(import_pub):
-            raise Exception("File %s does not exist!" % import_pub)
-        with open(import_pub) as fp:
-            pubkeys = fp.read()
-        if pubkeys.find('\0') > 0:
-            with open(import_pub, encoding='utf-16') as fp:
-                pubkeys = fp.read()
-        pubkeys = ast.literal_eval(pubkeys)
-        owner = pubkeys["owner"]
-        active = pubkeys["active"]
-        posting = pubkeys["posting"]
-        memo = pubkeys["memo"]
+        owner, active, posting, memo = import_pubkeys(import_pub)
 
     if owner is None and active is None and memo is None and posting is None:
         raise ValueError("All pubkeys are None or empty!")
@@ -2047,18 +2053,7 @@ def newaccount(accountname, account, owner, active, memo, posting, wif, create_c
         return
     acc = Account(account, blockchain_instance=stm)
     if import_pub and import_pub != "":
-        if not os.path.isfile(import_pub):
-            raise Exception("File %s does not exist!" % import_pub)
-        with open(import_pub) as fp:
-            pubkeys = fp.read()
-        if pubkeys.find('\0') > 0:
-            with open(import_pub, encoding='utf-16') as fp:
-                pubkeys = fp.read()
-        pubkeys = ast.literal_eval(pubkeys)
-        owner = pubkeys["owner"]
-        active = pubkeys["active"]
-        posting = pubkeys["posting"]
-        memo = pubkeys["memo"]
+        owner, active, posting, memo = import_pubkeys(import_pub)
         if create_claimed_account:
             tx = stm.create_claimed_account(accountname, creator=acc, owner_key=owner, active_key=active, memo_key=memo, posting_key=posting)
         else:
@@ -2068,14 +2063,7 @@ def newaccount(accountname, account, owner, active, memo, posting, wif, create_c
         if not import_password:
             print("You cannot chose an empty password")
             return
-        if wif > 0:
-            password = import_password
-            for _ in range(wif):
-                pk = PasswordKey("", password, role="")
-                password = str(pk.get_private())
-            password = 'P' + password
-        else:
-            password = import_password
+        password = generate_password(import_password, wif)
         if create_claimed_account:
             tx = stm.create_claimed_account(accountname, creator=acc, password=password)
         else:
@@ -2170,7 +2158,7 @@ def delprofile(variable, account, export):
 @click.argument('account', nargs=1, required=True)
 @click.option('--roles', '-r', help='Import specified keys (owner, active, posting, memo).', default=["active", "posting", "memo"])
 @click.option('--import-coldcard', '-i', help='Text file with a BIP85 WIF generated by a coldcard. The imported WIF is used as passphrase')
-@click.option('--wif', '-w', help='Defines how many times the password is replaced by its WIF representation for password based keys (default = 0).', default=0)
+@click.option('--wif', '-w', help='Defines how many times the password is replaced by its WIF representation for password based keys (default = 0 or 1 when importing a cold card wif).')
 def importaccount(account, roles, import_coldcard, wif):
     """Import an account using a passphrase"""
     from beemgraphenebase.account import PasswordKey
@@ -2187,27 +2175,15 @@ def importaccount(account, roles, import_coldcard, wif):
             print("You cannot chose an empty Passphrase")
             return
     else:
-        next_var = ""
-        password = ""
-        with open(import_coldcard) as fp: 
-            for line in fp:
-                if line.strip() == "":
-                    continue
-                if line.strip() == "WIF (privkey):":
-                    next_var = "wif"
-                    continue
-                elif "Path Used" in line.strip():
-                    next_var = "path"
-                    continue
-                if next_var == "wif":
-                    password = line.strip()
-                next_var = ""
+        password, path = import_coldcard_wif(import_coldcard)
+    if wif is not None:
+        wif = int(wif)
+    elif import_coldcard is not None:
+        wif = 1
+    else:
+        wif = 0
 
-    if wif > 0:
-        for _ in range(wif):
-            pk = PasswordKey("", password, role="")
-            password = str(pk.get_private())
-        password = 'P' + password
+    password = generate_password(password, wif)
 
     if "owner" in roles:
         owner_key = PasswordKey(account["name"], password, role="owner")
@@ -4680,35 +4656,9 @@ def customjson(jsonid, json_data, account, active, export):
         print("First argument must be the custom_json id")
     if json_data is None:
         print("Second argument must be the json_data, can be a string or a file name.")
-    if isinstance(json_data, tuple) and len(json_data) > 1:
-        data = {}
-        key = None
-        for j in json_data:
-            if key is None:
-                key = j
-            else:
-                data[key] = j
-                key = None
-        if key is not None:
-            print("Value is missing for key: %s" % key)
-            return
-    else:
-        try:
-            with open(json_data[0], 'r') as f:
-                data = json.load(f)
-        except:
-            print("%s is not a valid file or json field" % json_data)
-            return
-    for d in data:
-        if isinstance(data[d], str) and data[d][0] == "{" and data[d][-1] == "}":
-            field = {}
-            for keyvalue in data[d][1:-1].split(","):
-                key = keyvalue.split(":")[0].strip()
-                value = keyvalue.split(":")[1].strip()
-                if jsonid == "ssc-mainnet1" and key == "quantity":
-                    value = float(value)
-                field[key] = value
-            data[d] = field
+    data = import_custom_json(jsonid, json_data)
+    if data is None:
+        return
     stm = shared_blockchain_instance()
     if stm.rpc is not None:
         stm.rpc.rpcconnect()
diff --git a/beem/utils.py b/beem/utils.py
index af863475188842706265a914b63a329000a80473..c71762708ea9629a260992594d7dcc9bddb88dbf 100644
--- a/beem/utils.py
+++ b/beem/utils.py
@@ -8,6 +8,11 @@ import pytz
 import difflib
 from ruamel.yaml import YAML
 import difflib
+import secrets
+import string
+from beemgraphenebase.account import PasswordKey
+import ast
+import os
 
 timeFormat = "%Y-%m-%dT%H:%M:%S"
 # https://github.com/matiasb/python-unidiff/blob/master/unidiff/constants.py#L37
@@ -383,3 +388,97 @@ def load_dirty_json(dirty_json):
         dirty_json = re.sub(r, s, dirty_json)
     clean_json = json.loads(dirty_json)
     return clean_json    
+
+
+def create_new_password(length=32):
+    """Creates a random password containing alphanumeric chars with at least 1 number and 1 upper and lower char"""
+    alphabet = string.ascii_letters + string.digits
+    while True:
+        import_password = ''.join(secrets.choice(alphabet) for i in range(length))
+        if (any(c.islower() for c in import_password) and any(c.isupper() for c in import_password) and any(c.isdigit() for c in import_password)):
+            break
+    return import_password
+
+
+def import_coldcard_wif(filename):
+    """Reads a exported coldcard Wif text file and returns the WIF and used path"""
+    next_var = ""
+    import_password = ""
+    path = ""
+    with open(filename) as fp: 
+        for line in fp:
+            if line.strip() == "":
+                continue
+            if line.strip() == "WIF (privkey):":
+                next_var = "wif"
+                continue
+            elif "Path Used" in line.strip():
+                next_var = "path"
+                continue
+            if next_var == "wif":
+                import_password = line.strip()
+            elif next_var == "path":
+                path = line
+            next_var = ""
+    return import_password, path.lstrip().replace("\n", "")
+
+
+def generate_password(import_password, wif=1):
+    if wif > 0:
+        password = import_password
+        for _ in range(wif):
+            pk = PasswordKey("", password, role="")
+            password = str(pk.get_private())
+        password = 'P' + password
+    else:
+        password = import_password
+    return password
+
+
+def import_pubkeys(import_pub):
+    if not os.path.isfile(import_pub):
+        raise Exception("File %s does not exist!" % import_pub)
+    with open(import_pub) as fp:
+        pubkeys = fp.read()
+    if pubkeys.find('\0') > 0:
+        with open(import_pub, encoding='utf-16') as fp:
+            pubkeys = fp.read()
+    pubkeys = ast.literal_eval(pubkeys)
+    owner = pubkeys["owner"]
+    active = pubkeys["active"]
+    posting = pubkeys["posting"]
+    memo = pubkeys["memo"]
+    return owner, active, posting, memo
+
+
+def import_custom_json(jsonid, json_data):
+    data = {}
+    if isinstance(json_data, tuple) and len(json_data) > 1:
+        key = None
+        for j in json_data:
+            if key is None:
+                key = j
+            else:
+                data[key] = j
+                key = None
+        if key is not None:
+            print("Value is missing for key: %s" % key)
+            return None
+    else:
+        try:
+            with open(json_data[0], 'r') as f:
+                data = json.load(f)
+        except:
+            print("%s is not a valid file or json field" % json_data)
+            return None
+    for d in data:
+        if isinstance(data[d], str) and data[d][0] == "{" and data[d][-1] == "}":
+            field = {}
+            for keyvalue in data[d][1:-1].split(","):
+                key = keyvalue.split(":")[0].strip()
+                value = keyvalue.split(":")[1].strip()
+                if jsonid == "ssc-mainnet1" and key == "quantity":
+                    value = float(value)
+                field[key] = value
+            data[d] = field
+    return data
diff --git a/tests/beem/data/drv-wif-idx100.txt b/tests/beem/data/drv-wif-idx100.txt
new file mode 100644
index 0000000000000000000000000000000000000000..577c944136615e2c98a887982ea6015057fbf908
--- /dev/null
+++ b/tests/beem/data/drv-wif-idx100.txt
@@ -0,0 +1,8 @@
+WIF (privkey):
+L5K7x3Zs6jgY5jMovRzdgucWHmvuidyPj1f8ioCAzGjHMhjmL5EL
+
+Path Used (index=100):
+  m/83696968'/2'/100'
+
+Raw Entropy:
+f17b6e42ce2b40d385467a18f08a0159391cf113855903158a06f95a6d1e7697
diff --git a/tests/beem/data/pubkey.json b/tests/beem/data/pubkey.json
new file mode 100644
index 0000000000000000000000000000000000000000..a2e23807300aade39cce489567c01b6704d44f70
--- /dev/null
+++ b/tests/beem/data/pubkey.json
@@ -0,0 +1,6 @@
+{
+    "owner": "STM51mq6zWEz3NGRYL8uMpJAe9c1qzf4ufh2ha4QqWzizqVrPL9Nq",
+    "active": "STM6oVMzJJJgSu3hV1DZBcLdMUJYj3Cs6kGXf6WVLP3HhgLgNkA5J",
+    "posting": "STM8XJdv7T36XhKRmPaodt8tqoeMbNgLrsiyweNESvnKqZWQQekCQ",
+    "memo": "STM87KR1HKDoLiC3dv3goE99KDqEocBi3br8vcop6DgrCTwJcWexH"
+}
\ No newline at end of file
diff --git a/tests/beem/data/tmp.json b/tests/beem/data/tmp.json
new file mode 100644
index 0000000000000000000000000000000000000000..908d21f1df38bfd516e54b4053b2680828de312a
--- /dev/null
+++ b/tests/beem/data/tmp.json
@@ -0,0 +1,6 @@
+{
+    "owner": "STM7d8DzUzjs5jbSkBVNctRaZFGe991MhzzTrqMoTVvZJ5oyZN7Cj",
+    "active": "STM7oADsCds97GqyEDY4cQC66brVrg7XHuRa2MLvYbuGrdKnNoQa6",
+    "posting": "STM5fpGcVwvUFF55EzWQ35oJeERcWvt4M9dXwehdpYmKaFCCqihL7",
+    "memo": "STM6A7DywWvMZRokxAK5CpTo8XAPKbrMennAs4ntwRFq5nj2jR7nG"
+}
\ No newline at end of file
diff --git a/tests/beem/test_cli.py b/tests/beem/test_cli.py
index 2842b4e2047ed44a748f2f46f145fbea852f661b..6cc73db9e2bb789a485131321e3f0846f5facdde 100644
--- a/tests/beem/test_cli.py
+++ b/tests/beem/test_cli.py
@@ -1,6 +1,7 @@
 # -*- coding: utf-8 -*-
 import unittest
 import click
+import os
 from click.testing import CliRunner
 from pprint import pprint
 from beem import Steem, exceptions
@@ -10,6 +11,7 @@ from beemgraphenebase.account import PrivateKey
 from beem.cli import cli, balance
 from beem.instance import set_shared_steem_instance, shared_steem_instance
 from beembase.operationids import getOperationNameForId
+from beem.utils import import_pubkeys
 from .nodes import get_hive_nodes, get_steem_nodes
 
 wif = "5Jt2wTfhUt5GkZHV1HYVfkEaJ6XnY8D2iA4qjtK9nnGXAhThM3w"
@@ -147,6 +149,22 @@ class Testcases(unittest.TestCase):
         result = runner.invoke(cli, ['keygen'])
         self.assertEqual(result.exit_code, 0)
 
+    def test_passwordgen(self):
+        runner = CliRunner()
+        result = runner.invoke(cli, ['passwordgen'])
+        self.assertEqual(result.exit_code, 0)
+        data_dir = os.path.join(os.path.dirname(__file__), 'data')
+        file = os.path.join(data_dir, "drv-wif-idx100.txt")
+        file2 = os.path.join(data_dir, "wif_pub_temp.json")
+        result = runner.invoke(cli, ['passwordgen', '-a', 'test', '-o', file, '-u', file2, '-w', 1])
+        self.assertEqual(result.exit_code, 0)
+        owner, active, posting, memo = import_pubkeys(file2)
+        self.assertEqual(owner, "STM7d8DzUzjs5jbSkBVNctRaZFGe991MhzzTrqMoTVvZJ5oyZN7Cj")
+        self.assertEqual(active, "STM7oADsCds97GqyEDY4cQC66brVrg7XHuRa2MLvYbuGrdKnNoQa6")
+        self.assertEqual(posting, "STM5fpGcVwvUFF55EzWQ35oJeERcWvt4M9dXwehdpYmKaFCCqihL7")
+        self.assertEqual(memo, "STM6A7DywWvMZRokxAK5CpTo8XAPKbrMennAs4ntwRFq5nj2jR7nG")        
+        os.remove(file2)
+
     def test_set(self):
         runner = CliRunner()
         result = runner.invoke(cli, ['-o', 'set', 'set_default_vote_weight', '100'])
diff --git a/tests/beem/test_utils.py b/tests/beem/test_utils.py
index 2563f8a5ce96cefd2255738c847bfed6a61669d9..267bf00ed8d82ccf40e0798a18e5d8343367e697 100644
--- a/tests/beem/test_utils.py
+++ b/tests/beem/test_utils.py
@@ -1,6 +1,7 @@
 # -*- coding: utf-8 -*-
 import unittest
 from datetime import datetime, date, timedelta
+import os
 from beem.utils import (
     formatTimedelta,
     assets_from_string,
@@ -18,7 +19,11 @@ from beem.utils import (
     derive_beneficiaries,
     derive_tags,
     seperate_yaml_dict_from_body,
-    make_patch
+    make_patch,
+    create_new_password,
+    generate_password,
+    import_coldcard_wif,
+    import_pubkeys
 )
 
 
@@ -176,3 +181,36 @@ class Testcases(unittest.TestCase):
         self.assertEqual(par, {"par1": "data1", "par2": "data2", "par3": 3})
         self.assertEqual(body, " test ---")
 
+    def test_create_new_password(self):
+        new_password = create_new_password()
+        self.assertEqual(len(new_password), 32)
+        self.assertTrue(any(c.islower() for c in new_password))
+        self.assertTrue(any(c.isupper() for c in new_password))
+        self.assertTrue(any(c.isdigit() for c in new_password))
+
+        new_password2 = create_new_password()
+        self.assertFalse(new_password == new_password2)
+        new_password = create_new_password(length=16)
+        self.assertEqual(len(new_password), 16)
+
+    def test_generate_password(self):
+        new_password = generate_password("test", wif=0)
+        self.assertEqual(new_password, "test")
+        new_password = generate_password("test", wif=1)
+        self.assertAlmostEqual(new_password, "P5K2YUVmWfxbmvsNxCsfvArXdGXm7d5DC9pn4yD75k2UaSYgkXTh")
+
+    def test_import_coldcard_wif(self):
+        data_dir = os.path.join(os.path.dirname(__file__), 'data')
+        file = os.path.join(data_dir, "drv-wif-idx100.txt")
+        wif, path = import_coldcard_wif(file)
+        self.assertEqual(wif, "L5K7x3Zs6jgY5jMovRzdgucWHmvuidyPj1f8ioCAzGjHMhjmL5EL")
+        self.assertEqual(path, "m/83696968'/2'/100'")
+
+    def test_import_pubkeys(self):
+        data_dir = os.path.join(os.path.dirname(__file__), 'data')
+        file = os.path.join(data_dir, "pubkey.json")
+        owner, active, posting, memo = import_pubkeys(file)
+        self.assertEqual(owner, "STM7d8DzUzjs5jbSkBVNctRaZFGe991MhzzTrqMoTVvZJ5oyZN7Cj")
+        self.assertEqual(active, "STM7oADsCds97GqyEDY4cQC66brVrg7XHuRa2MLvYbuGrdKnNoQa6")
+        self.assertEqual(posting, "STM5fpGcVwvUFF55EzWQ35oJeERcWvt4M9dXwehdpYmKaFCCqihL7")
+        self.assertEqual(memo, "STM6A7DywWvMZRokxAK5CpTo8XAPKbrMennAs4ntwRFq5nj2jR7nG")