Skip to main content

Stateless Password Manager and Brain Wallet

Project description


What is novault

novault is a command-line utility and Python module for generating passwords and cryptocurrency wallets from a combination of a description and a master password. The description and master password are hashed, generating a pseudo-random seed which is then formatted as a password or wallet keys/address. By selecting a strong password as the master password it becomes practicaly impossible for an attacker who obtains one of your generated passwords or wallet keys to recover the master password, and recreate any of your other novault-generated passwords or wallets. novault provides in addition some convenience features for generating pseudo-random silly names and birth dates.

From a functionality point of view novault is very similar to a password manager or an electronic wallet, except that it doesn’t save your passwords and wallets in a file. It actually doesn’t store them anywhere - your brain is the database. You can re-create your passwords and wallets on the fly on fresh machines without any synching of a repository, by providing the description and master password.

The currencies currently supported by novault are Bitcoin (BTC) and Monero (XMR).

novault is available as a Python module for Linux, Windows, and OSX. Linux and Windows users can download a single binary (.exe file) which contains the entire functionality. In addition, novault exposes an API which can be used by developers to embed the novault functionality in other programs.

Announcements are available via the novault Twitter feed @_novault. Questions, suggestions, opinions and other stuff at /r/novault.

When to Use novault

I wrote novault because this is my preferred way of generally managing my passwords and wallets. With multi-device computing I simply find it more convenient to be able to access my passwords and wallets on any machine without having to sync a repository. This becomes particularly important when working with cryptocurrencies: The secure way to work with these currencies is to perform offline all processes that require the use of a private key; without novault I’d have to sync the list of wallets between the offline and online machines using a USB device, and that’s both a nuisance and a potential source of security vulnerabilities.

In some cases the use of novault is not only simpler but also more secure than a repository-based password manager or wallet. Access to these too requires a master password, but if you are coerced to disclose the master password your entire list of assets in the repository is revealed to the attackers. With novault after a coerced disclosure of the master password the attackers can try to regenerate assets that they already know about (they still do have to get the precise description to match with the master password), yet you have plausible deniability of the existance of any other assets.

An additional dimension of plausible deniabilty can be achieved with novault through master password federation, i.e., by using several master passwords for different purposes. When forced to disclose a master password you hedge your exposure only to those assets that use the password you disclosed, while being able to deny having any additional master passwords. With repository based solutions this usually won’t be possible because typically the attackers will see that you have multiple repositories, and will force you to disclose all your master passwords.


Pre-Built Executables

Download the binary file relevant to your machine.

Rename the downloaded file from novault-version-osname-hardware to novault.exe (on Windows) or novault (all other operating systems).

You can copy the executable to a USB drive and run it directly from there, or from any other directory, without any installation.

As a Python Module

This method enables you to use novault on any Python-supported Linux, Windows, or OSX platform even if a pre-built executable is not available for it. It also enables you to use the novault API. Install the novault module using pip:

$ pip install novault

To run novault as a CLI utility:

$ python -m novault <...cli options & arguments...>

Requires Python 3.4.

Under Linux novault requires either xsel or xclip in order to place the results in the clipboard; typically, at least one of them comes with the Linux distribution. If not then novault may try to fallback to PyQt4 or gtk (this is a pyperclip feature), however this fallback is not tested for novault. So, if you have neither xsel nor xclip usually you can install either with a package manager,.e.g. sudo apt-get install xclip. To install xsel from source:

$ wget
$ tar -xf xsel-1.2.0.tar.gz
$ cd xsel-1.2.0
$ ./configure
$ make
$ sudo make install

Build Your Own Executable

This is usefull if you want an executable for an architecture for which pre-built binary executables are not available yet.

Download the source package, unzip it, and move into the source directory. Install all dependencies:

$ python install

Install PyInstaller and build the executable:

$ pip install pyinstaller
$ pyinstaller novault.spec

The executable will be in the dist/ directory, check that it works correctly.

How to Use novault

Basic Usage

novault is a command line utility. When invoked it will ask for a description and password, and place the result in the clipboard. For example, the password of an email account could be generated as follows:

$ novault
Enter description:
Enter password:
Verify password:
Result placed in clipboard.

You will now be able to paste the result from the clipboard into the relevant application or web page. The generated password’s entropy is 128 bits, has 24 characters, and is guaranteed to have at least one digit, lowercase letter, uppercase letter, and “special” character.

In the rest of this document we will use two novault options to make the examples more readable: With the -c option novault will accept the password in clear text, echo it, and won’t ask for verification; With the -d option the result will be displayed rather than placed in the clipboard. The above example will then look like this:

$ novault -cd
Enter description:
Enter password: %^mY-ma5T3r-PAsSw0rd~~)!'

It is highly recommended not to use the -c and -d options unless you are sure you’re in complete privacy from prying eyes and cameras.


To produce a wallet invoke novault with the -w option. The -w option accepts as argument the currency for which to produce a wallet, and by default will generate the wallet’s address. if the currency is ommited then the wallet defaults to a Bitcoin wallet. Here are two examples:

$ novault -cd -w btc
Enter description: my shop
Enter password: %^mY-ma5T3r-PAsSw0rd~~)!'

$ novault -cd -w xmr
Enter description: my shop
Enter password: %^mY-ma5T3r-PAsSw0rd~~)!'

At some point you will likely need the private keys of the wallet. novalut allows you to specify in the command line which information to generate about the wallet and at what order. For Bitcoin you can specify address and key and for Monero you can specify address, spend, and view. Here are the above two examples, this time showing the private keys followed by the address:

$ novault -cd -w btc key address
Enter description: my shop
Enter password: %^mY-ma5T3r-PAsSw0rd~~)!'
L3ZpKbwm1NNHQcMrtfBZYCEnBjLR7FCQAU759v9YREtBog4HMVM3 13qmztfEvTQLNPcQWuxNJeaQHseW57seYi

$ novault -cd -w xmr spend view address
Enter description: my shop
Enter password: %^mY-ma5T3r-PAsSw0rd~~)!'
2f6756de5442aa82e0755b93dfcdca7380cdf52995d20740c6b589ba37ddaf06 5d3528c622b60aec74e97b34f8f08fb47de083cb81247086813afaaf1444740d 42rMGPw2Mt6CBWC5wWdPE6hnj1rFoz9kUALvw26ynNTKRwEYjStpVBzdGKpi79X2QdXeh1TRcFKgEKVMe7xPpFKAKc4N44B

Silly Names

Web sites often have a practice of requiring users to provide answers to “security” questions, such as your place of birth and mother’s maiden name. If you provide these web sites with your true answers these answers become practically public, often available to thousands of web site employees and subcontractors, and therefore breach your privacy and security. With novault’s -n option you can generate unique silly names to use as answers to these questions. The silly names are kinda pronounceable, just in case you need to communicate them by voice, e.g. when speaking with a customer service representative. For example:

$ novault -cd -n
Enter description: first pet myaccount
Enter password: %^mY-ma5T3r-PAsSw0rd~~)!'

$ novault -cd -n
Enter description: mother maiden name myaccount
Enter password: %^mY-ma5T3r-PAsSw0rd~~)!'

Birth Date Generator

Web sites often ask you for your date of birth under the pretence of “security”. However, giving away your real birth date compromises your privacy and security, and should be avoided except when there is no other choice (e.g., when dealing with regulated financial institutions). With novaults’s -b option you can generate in a reproducible way a different date of birth for each web site or service:

$ novault -cd -b
Enter description: myaccount
Enter password: %^mY-ma5T3r-PAsSw0rd~~)!'

The generated date will be in the range between 1950-01-01 and 1994-11-09.

Non-Interactive Use

Sometimes you may need to use novault non-interactively, e.g., when invoked from a shell script. In such case you can use the -D option to provide the description and the -M option to provide the master password. For example, get the password of an email account:

$ novault -d -D -M "%^mY-ma5T3r-PAsSw0rd~~)!'"

Another example, get the spend key of a Monero wallet:

$ novault -dw xmr -D "online store" -M "%^mY-ma5T3r-PAsSw0rd~~)!'" spend

The Seed (advanced topic)

All the values generated by novault are representations of a pseudo-random seed that results from the hashing of the description and master password. Sometimes it may be useful for you to get not just the final result but also the seed, for example in case there is another representation you want to derive from it. Adding the seed to the result is possible by adding the seed argument to the command line. Here are three examples that use the same description and master password to generate different representations with their seed:

$ novault -cd seed password
Enter description: test
Enter password: %^mY-ma5T3r-PAsSw0rd~~)!'
bb5bfa6140933377ded52b93c73f573e yIcBUK$A0ef-qO.kCU6$3Is-

$ novault -cdw btc seed address
Enter description: test
Enter password: %^mY-ma5T3r-PAsSw0rd~~)!'
bb5bfa6140933377ded52b93c73f573ec26fe973c5d8c4fc8fc54eaec144369e 156KN9GoSZmXvZVNQFdbZ88d8GwSiYRz5w

$ novault -cdw xmr seed address
Enter description: test
Enter password: %^mY-ma5T3r-PAsSw0rd~~)!'
bb5bfa6140933377ded52b93c73f573ec26fe973c5d8c4fc8fc54eaec144369e 44cstf51YYJEuR1v9MRZAXam7XYA8wRdCSFbJNDtoEG16TuULaerSXoXx2JGex9Hbd6fcaLn9qVkL2Xw7PpN6jAR9kVKmZP

As you can see all three examples produce the same seed (except that the password seed is just 128 bit versus the wallets’ 256 bits). If you want to generate just a seed then you can use the -s option and provide it with the number of bytes to produce (defaults to 16):

$ novault -cd -s 32
Enter description: test
Enter password: %^mY-ma5T3r-PAsSw0rd~~)!'

Once having a seed, this seed can be used to generate results without providing a description and master password. To provide a specific seed to novault use the -S option:

$ novault -cd -S bb5bfa6140933377ded52b93c73f573e

novault can also generate a random seed for you by specifying the -R option. The random seed is actually a random value generated by the operating system with an additional randomization layer in the form of novault’s hashing:

$ novault -cd -R -s 32

The -R option is also useful in case you want to produce a random password, just note that this password cannot be reproduced unless you somehow back it up:

$ novault -cd -R

CLI Reference

usage: novault [-h] [-w [{btc,xmr}]] [-s [S]] [-n] [-b] [-D D] [-M M] [-S S] [-R] [-c] [-d]

Stateless password manager and brain wallet

positional arguments:
                        What information to return

optional arguments:
  -h, --help            show this help message and exit
  -w [{btc,xmr}]        Generate wallet (default: btc)
  -s [S]                Generate raw seed only with given number of bytes (default: 16)
  -n                    Generate a silly name
  -b                    Generate a birth date
  -D D                  Description
  -M M                  Master password
  -S S                  Use this seed instead of description/master
  -R                    Use a random seed, don't ask for inputs
  -c                    Input master password as clear text
  -d                    Display result instead of copy to clipboard


To access novault’s functionality programatically, install the module (e.g. using pip as described in the Installation chapter) and include an import novault statement in your code.

novault exports one constant, novault.COINS with the list of coins it supports:

>>> import novault
>>> novault.COINS
('btc', 'xmr')

The novault module exports the following functions.


A general wrapper of all actions. An action is a function that accepts a seed and returns a representation; if the seed is not provided the function returns the number of bytes that should be in seeds accepted by the action. An action returns a dictionary with all values it generated, where the key None points to the value that should be displayed by default.

novault.novault( action, description, master )

action - novault.password, novault.btc, novault.xmr, novault.sillyname or novault.birthdate.

description - The description to use in generating the seed.

master - The master password to use in generating the seed.

Returns the result returned by the action.


>>> novault.novault( novault.password, b'test', b'mypassword' )
{'password': 'bHY^GLsEu!Io3q#CWbA|zfO,', None: 'bHY^GLsEu!Io3q#CWbA|zfO,'}
>>> novault.novault( novault.btc, b'test', b'mypassword' )
{None: '1Lb4NGg4kJMm82qqoL7AdbahLZXF7YHG9z', 'address': '1Lb4NGg4kJMm82qqoL7AdbahLZXF7YHG9z', 'key': 'Ky31n6uHG6X5pkEeELK9DvsEwBBw7GYxYjNdSiAae3tNUYqsv5Ra'}


The seed generation function.

novault.mk_seed( description, master, length )

description - The description to use in generating the seed.

master - The master password to use in generating the seed.

length - The number of bytes to generate.

Returns the generated seed.


>>> from binascii import hexlify
>>> hexlify(novault.mk_seed( b'test', b'mypassword', 32 ))


Generates a password representation from a 16 byte seed.

novault.password( seed = None )

seed - The seed used for generating the password.

Returns a dictionary with the key password.


>>> from binascii import unhexlify
>>> novault.password(unhexlify(b'362c09fea88d6f6c9d8028d976265cc9'))
{'password': 'bHY^GLsEu!Io3q#CWbA|zfO,', None: 'bHY^GLsEu!Io3q#CWbA|zfO,'}


Generates a Bitcoin wallet representation from a 32 byte seed.

novault.btc( seed = None )

seed - The seed used for generating the password.

Returns a dictionary with the keys address and key.


>>> novault.btc(unhexlify(b'362c09fea88d6f6c9d8028d976265cc9324ac2795e12626b00c65729a5cd7325'))
{None: '1Lb4NGg4kJMm82qqoL7AdbahLZXF7YHG9z', 'address': '1Lb4NGg4kJMm82qqoL7AdbahLZXF7YHG9z', 'key': 'Ky31n6uHG6X5pkEeELK9DvsEwBBw7GYxYjNdSiAae3tNUYqsv5Ra'}


Generates a Monero wallet representation from a 32 byte seed.

novault.xmr( seed = None )

seed - The seed used for generating the password.

Returns a dictionary with the keys address, spend and view.


>>> novault.xmr(unhexlify(b'362c09fea88d6f6c9d8028d976265cc9324ac2795e12626b00c65729a5cd7325'))
{'view': 'b1c1f02b4782c57b00a918b9232c3f00850f2f204e02fed18c5f60ca7e50ee0a', None: '48SC75jKUDriiHiRsBW5bENxWef37T6yCRVrBNPrCy5JQ5epdHT2epkiJ3FeH4438BBa5C8juFNuLgcSpeRZX2hg4zCmrhD', 'address': '48SC75jKUDriiHiRsBW5bENxWef37T6yCRVrBNPrCy5JQ5epdHT2epkiJ3FeH4438BBa5C8juFNuLgcSpeRZX2hg4zCmrhD', 'spend': '5c841d4474c74abcf0463993b9329e9f324ac2795e12626b00c65729a5cd7305'}


Generates a silly name representation from a 4 byte seed.

novault.sillyname( seed = None )

seed - The seed used for generating the silly name.

Returns a dictionary with the key name.


>>> novault.sillyname(unhexlify(b'362c09fe'))
{None: 'sweaupjeethr', 'name': 'sweaupjeethr'}


Generates a birth date representation from a 2 byte seed.

novault.birthdate( seed = None )

seed - The seed used for generating the birth date.

Returns a dictionary with the key date.


>>> novault.birthdate(unhexlify(b'362c'))
{'date': '1980-12-27', None: '1980-12-27'}

Frequently Asked Questions

There are other stateless password managers and brain wallets around, why develop yet another one?

Each of the existing solutions that I could find had drawbacks that rendered them unsuitable for my needs, in particular:

  • I won’t use browser-based solutions as the browser cannot be trusted IMHO with the master password. Note that opening the Network monitor on the Developer Console of a web browser doesn’t guarantee to display all the communication between the browser and the network, particularly if the tool being used is installed as an add-on. For example, a naive (?) bug such as sending form data to a search suggestions server would expose the master password to the entire internet without ever showing on the console.

  • Many of the existing solutions use sub-par hashing techniques. Others’ hashing is over-verbose and require e.g. entering a name.

  • Many of the existing solutions display their result in clear text. This is not acceptable in many environments where the user is susceptible to prying eyes and security cameras. Results should, by default, be placed in the clipboard.

  • I find it more convenient to use a single manager for passwords and currecny wallets. After all, the logic is pretty similar, so why fuss with many different tools?

What is the difference between novault and HD wallets?

HD wallets are similar to novault in the sense that a single tool can generate many wallets. However, HD - standing for Hierarchical Deterministic - means that all wallets are somehow related, typically in order to generate one-time addresses that can be easily recreated using a single seed. novault on the other hand can generate many addresses that are not neccessarilly related, each with its own description. novault can, however, be used to simulate HD hierarchies by using a description that contains a serial number. This is somewhat similar to Type 1 HD.

Can I use as master password a list of mnemonics?

Yes, the master password is not checked against a maximum length and can contain the space character. The novault master password should be precise though, unlike some mnemonic implementations that allow mnemonics to be shortened to the first three characters.

Can I enter a description and/or master password in non-latin characters?

Yes, you can use any characters in the description and master password. Take care though, when using non-Latin-1 characters, that the shell’s code page settings can influence the representation of the string. The same printed string entered under different code pages can yield different binary strings. To avoid such problems you can either adhere to Latin-1 characters or make sure you always invoke novault with the same code page; since novault internally converts the strings to UTF-8 it is best advised to use a UTF-8 generating code page whenever using non-Latin-1 characters.

What hashing algorithm is used to derive the seed from the description and master password?

novault uses two rounds of scrypt. The first round uses two different-salted concatenations of the description and master password to generate a 256-bit value which will be used as the salt for the second round. The second round uses a key generated by a third salted concatenation of the description and master password and the salt generated in the first round. The result of the second round is used as the novault seed. The Python code is as follows:

def mk_seed( description, master, length ):
    '''Generate pseudorandom seed of desired length from description & master password'''
    S0, S1, S2 = b'%<6>0Mk$ziGdz@:z-O-', b'Jea`_uH6.ji4R$VM1ZB', b'C!#1P4zJLB2O=no06[1'
    return pyscrypt_hash(
        description + S0 + master,
        pyscrypt_hash( description + S1 + master, master + S2 + description, 1024, 1, 1, 32 ),
        1024, 1, 1, length )

The calls to scrypt use a low difficulty in order to make the algorithm usable on weaker platforms such as mobile devices and SBCs.

Can you add support for additional currencies?

Yes, post in /r/novault or get in touch at

Can you add pre-built executables for an additional platform?

In order to generate an executable for a platform one must have such a machine (this is a PyInstaller limitation), and for security reasons I don’t accept binary contributions. Therefore the choice of available platforms depends on what I currently have. If you wish to buy me an additional platform then please post in /r/novault or get in touch at


novault is provided under the MIT License. Beyond Python and its standard libraries novault makes use and depends on the following 3rd party packages, and bundles them in the pre-built binary executables:

ecdsa, licensed under the MIT License.

pyperclip, licensed under the BSD License.

pyscrypt, licensed under the MIT License.

Contributing to novault

Please help make novault better by reporting any bugs or other issues you encounter.

If you find novault useful your donation will be most appreciated:

btc - 1FE4CtY3qvxu3Yw1yWngTFKe7btXwaU2XZ

xmr - 44tLk21kgrQBMAuk41j8LURHxvo96sJfRhXR3ksJALwh1rWs2YJK6uPCKbgwPpJcwefdKnZ766QeYbaDCmQ2rV7uBnVXRiz

PayPal - press here

Project details

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution (23.4 kB view hashes)

Uploaded source

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page