abraxas

collaborative password utility

Author:Kale and Ken Kundert <abraxas@nurdletech.com>
Date:2016-08-14
Version:1.8
Manual section:5

DESCRIPTION

Abraxas requires two files to operate. The master password file and the accounts file. You may optionally add a third file that gives the dictionary used when creating pass phrases.

Master Password File

The master password file is named ‘~/.config/abraxas/master.gpg’. It is encrypted with the GPG ID that you specified when you ran ‘abraxas –init’. It is a Python file that contains a collection of variables. To be able to edit it conveniently it is recommended that you add the gnupg plugin to vim (download it from http://www.vim.org/scripts/script.php?script_id=3645 and copy it into ~/.vim/plugin).

dict_hash

This is a hash of the file that contains the words used when generating pass phrases. You should not change this value. It is used to warn you if somehow your words file is changed or corrupted, which would corrupt your pass phrases.

secrets_hash

This is a hash of the file that contains the code used when generating the hash and converting it to a password or pass phrase. It is used to warn you that the secrets code has changed, presumably when the program itself was updated. If this occurs you should verify that the passwords it generates are the same. If not, you should not use the updated version of the program. If they are the same, you should update the secrets_hash. Do this by moving the existing master.gpg file out of the way, generating a new one with abraxas –init, copying the new secrets_hash to the original file, and then moving it back to its original location of ~/.config/abraxas/master.gpg.

charsets_hash

This is a hash of the file that contains the alphabets and the exclude function that you can use when creating alphabets for your character-based passwords. It is used to warn you that the character sets code has changed, presumably when the program itself was updated. If this occurs you should verify that the passwords it generates are the same. If not, you should not use the updated version of the program. If they are the same, you should update the charsets_hash. Do this by moving the existing master.gpg file out of the way, generating a new one with abraxas –init, copying the new charsets_hash to the original file, and then moving it back to its original location of ~/.config/abraxas/master.gpg.

accounts

This is the name of the accounts file. The name may be given with or without an encryption suffix (.gpg or .asc). If given with an encryption suffix, the file must be encrypted. If given without a suffix, the file may still be encrypted (in which case the file itself should have a encryption suffix) but need not be.

passwords

This is a dictionary that gives your master passwords. Each entry is a pair of the password ID and then password itself. For example:

passwords = {
    'default': """l8i6-v?>GCTQK"oz3yzZg5Ne=&,.!*Q$2ddEaZbESwnl<4*BRi1D887XQ!W4/&}e""",
    'derrick and peter': "hush puppie",
    'derrick and debbie': "lounge lizard",
}

As shown, your account comes preloaded with a very long and very random default password.

Generally you will never have to type these passwords again, so there is little reason not to make them long and very random. There are no limits on the length of the passwords or the characters they may contain, so you can go wild. For example, using your default master password you could use Abraxas to generate new master passwords:

$ abraxas -T =extreme 'derrick and peter'
PASSWORD: [Y$*{QCf"?yvDc'{4v?4r.iA0b3brHY z40;lZIs~bjj<DpDz&wK!XCWq=,gb}-|

You can then use that string as a master password. Notice that this string contains quote characters, meaning that you will have to embed it in triple quotes to avoid trouble:

passwords = {
    'default': """l8i6-v?>GCTQK"oz3yzZg5Ne=&,.!*Q$2ddEaZbESwnl<4*BRi1D887XQ!W4/&}e""",
    'derrick and peter': """[Y$*{QCf"?yvDc'{4v?4r.iA0b3brHY z40;lZIs~bjj<DpDz&wK!XCWq=,gb}-|""",
    'derrick and debbie': "lounge lizard",
}

Of course it is not necessary to go to these extremes. Your password must just not be guessable. One reason not to go to such extremes is if you need to share a master password with a friend while talking over the phone. In this case, using the =master template to generate a simple but long pass phase is much preferred:

$ abraxas -T =master "derrick and debbie"
PASSWORD: impulse nostril double irony conflate rookie posting blind

Then your passwords entry becomes:

passwords = {
    'default': """l8i6-v?>GCTQK"oz3yzZg5Ne=&,.!*Q$2ddEaZbESwnl<4*BRi1D887XQ!W4/&}e""",
    'derrick and peter': """[Y$*{QCf"?yvDc'{4v?4r.iA0b3brHY z40;lZIs~bjj<DpDz&wK!XCWq=,gb}-|""",
    'derrick and debbie': """impulse nostril double irony conflate rookie posting blind""",
}

This approach of using the default password to generate new master passwords, each of which has a very predictable name, can make it possible for you to reconstruct your master password file if you happen to lose it. To do so, you will need to keep a copy of the default password in a safe place (along with your master GPG keys in a safe deposit box, for example). Of course, you really should save both the master password and accounts file in a safe place because they contain additional information that is used to generate your passwords (account names, versions, security questions, etc.). You should be aware that these tend to change with time and so your saved files can quickly go out of date. However, if your follow a practice of using very systematic naming strategies for master passwords, accounts, versions, and the like, you can dramatically increase the chances of being able to retrieve your passwords from an old master password and accounts file.

You are free to name your master passwords in any manner that pleases you. One reasonable approach is to name them after the people that use them. Thus in the example above, Derrick has one key he uses his default key for for his own accounts and two others for accounts he shares with Debbie and Peter. When it comes time to abandon a master password, simply add ‘(deprecated <date>)’ to the end of the master password name, where <date> is replaced with the date that the password was deprecated. When doing so, be sure to also change the name used in the accounts file so that the existing passwords do not change. That way you do not have to update all of your passwords at once. Rather, you update the high value ones immediately and migrate the others as you get time.

Using this approach your master password file might look like this:

passwords = {
    'default': """l8i6-v?>GCTQK"oz3yzZg5Ne=&,.!*Q$2ddEaZbESwnl<4*BRi1D887XQ!W4/&}e""",
    'derrick and peter (deprecated 120301)':
        """[Y$*{QCf"?yvDc'{4v?4r.iA0b3brHY z40;lZIs~bjj<DpDz&wK!XCWq=,gb}-|""",
    'derrick and peter': """h#KLT@f0IN(srTs$CBqRvMowBfiCT26q\yox(]w!PSlj_|ZMuDZ|{P0Jo4:aa4M"""
    'derrick and debbie': """impulse nostril double irony conflate rookie posting blind""",
}

Generally one uses the default password for the personal passwords, and only creates new shared master passwords. In this case, one member of the group uses their master password to generate a the shared password for the group. And of course, you should strive to keep your master passwords completely secure. Never disclose a master password to anyone else unless you plan to share that particular master password with them to generate shared passwords.

default_password

The ID of the default master password:

default_password = "default"

This password will be used when an account does not explicitly specify a master password. It is recommended you set the default master password once and after that never change it, because if you do, the passwords that rely on it will also change. You are given a very secure default password when your master password file is initially created for you. It is recommended that you never change it.

Using a value of None for default_password disables the default password, forcing you to always specify a master password. If the master password is not given in the accounts file, it will be requested when Abraxas is run, which allows you to use a master password that is not stored in the master password file. This provides the ultimate in security for stealth accounts in that even if someone guessed the name of your stealth account and had access to your private GPG key, perhaps because you were compelled to give it to them, they still could not regenerate the pass phrase for your stealth account because it requires a master password that only you know but can plausibly deny having.

password_overrides

A dictionary that contains passwords for specific accounts. These passwords will be produced rather than the generated passwords. For example:

password_overrides = {
    'yahoo': 'lollipop',
    'nytimes': 'excelsior',
}

Password overrides are generally used in two situations. First is when a password is provided to you (you have no or limited ability to choose it). Second is for the accounts you have not yet migrated to the new passwords generated by Abraxas.

additional_master_password_files

A list of additional master password files. This is helpful in cases where you want to have a separate file for passwords shared with others. The additional master password files must also be encrypted. If they are truly shared, then you will want to encrypt them using multiple recipients.

An additional master password file is also a Python file, and the only things that are used by Abraxas in this file are the dictionaries named passwords and password_overrides.

You can specify a single master password file using a string, and multiple master password files as a list of strings. Here is how to specify a single additional master password file:

additional_master_password_files = "business/master.gpg"

Here is how you specify multiple additional master password files:

additional_master_password_files = [
    "business/master.gpg",
    "charity/master.gpg"
]

Accounts File

The accounts file is by default ‘~/.config/abraxas/accounts’, but could also end with either a ‘.gpg’ or ‘.asc’ extension if it is encrypted. It starts out importing some character sets. You are free to modify these but there is generally no reason to. They are there to help you create alphabets for your passwords. A function exclude() is also defined, which allows you to create an alphabet by removing characters from the preexisting ones. You can add characters simply summing them.

The accounts file is a Python file that contains variables that are used by the password program. When created it will lead off with some useful imports. The dedent function is used to strip off leading white space from multiline remarks. The passwords.charsets import provides a collection of useful character sets:

LOWERCASE = "abcdefghijklmnopqrstuvwxyz"
UPPERCASE = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
LETTERS = LOWERCASE + UPPERCASE
DIGITS = "0123456789"
ALPHANUMERIC = LETTERS + DIGITS
HEXDIGITS = "0123456789abcdef"
PUNCTUATION = """!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~"""
WHITESPACE = " \t"
PRINTABLE = ALPHANUMERIC + PUNCTUATION + WHITESPACE
DISTINGUISHABLE = exclude(ALPHANUMERIC, 'Il1O0\\t')

Finally, the exclude function is used to remove characters from a character set.

The following attributes are read and used by the password program if they exist in an accounts file.

log_file

Specifies the location of the log file. If not given, it defaults to ‘~/.config/abraxas/log’. An absolute path should be used to specify the file. If a ‘.gpg’ or ‘.asc’ suffix is given on this file, it will be encrypted using your public key. Without encryption, this file leaks account names.

archive_file

Specifies the location of the archive file. If not given, it defaults to ‘~/.config/abraxas/archive.gpg’. An absolute path should be used to specify the file. The file should end with a .gpg extension.

gpg_id

The GPG ID of the user (it is used to encrypt the archive file). It would either by the email address associated with the ID, or the eight digit hexadecimal GPG key ID if you have multiple keys associated with the same email address.

accounts

A dictionary where each entry represents either an account or a template. By convention, templates have an ID that starts with ‘=’.

Templates are used to limit the information you need to give in an account. You just create or use a template that has the desired base information. Then when creating an account, you can refer to the template and only specify the fields that need to be unique for that account. The template for an account can be another account or a template. In this way templates are just accounts that are not associated with any particular account in the real world. For example:

accounts = {
    "=words": {  # typically used for Linux pass phrases
        'type': 'words',
        'num-words': 4,
        'autotype': "{password}{return}",
    },
    "gmail": {
        'template': "=words",
        'username': "derrickAsh",
        'url': "https://accounts.google.com",
        'master': 'derrick',
        'window': [
            'Google Accounts*',
            'Gmail*',
        ],
        'autotype': "{username}{tab}{password}{return}",
    },
    ...
}

In this example ‘=words’ is specified as the template for ‘gmail’ (it is a purely optional convention to add a leading = to account names that are intended to be used only as templates). Thus any field specified in ‘=words’ that is not specified in ‘gmail’ is inherited by ‘gmail’. Any field specified in ‘gmail’ overrides the field with the same name from ‘=words’ when using ‘gmail’. This process of inheritance can chain through any number of templates or accounts. For example, you can create another account, say ‘gmail-work’ that uses ‘gmail’ as a template but overrides the ‘username’.

The ID associated with an account is used in the process of generating the secrets for the account. For this reason you should choose IDs that are unambiguous and unlikely to change. The resulting IDs may be long and hard to type. You can use the aliases entry to specify shorter names that can be used as an alternative to the primary account ID. For example, when creating your gmail account, it is a good idea to add your username to the account ID, because in the future you might create additional gmail accounts. So, gmail-username would be a good account name. Then you should add a short name like gmail as an alias to the one you use the most. If at some point you migrate to a new gmail account for your day-to-day use, you can move the gmail alias to this new account without changing the generated password.

additional_accounts

A list of additional account files. This is helpful in cases where you want to have a separate file for accounts shared with someone else. In this way you can share the details of the shared accounts file without exposing your personal accounts. The additional account files may also be encrypted. If they are truly shared, then you will want to encrypt them using multiple recipients.

An additional accounts file is also a Python file, and the only thing that is used by Abraxas in this file is a dictionary named accounts. It is generally a good idea to start from a copy of the original accounts file and simply delete unnecessary definitions (log_file, archive_file and gpg_id) and the non-shared accounts. In this way, you still can use the character sets that are defined at the top of the file.

You can specify a single account file using a string, and multiple account files as a list of strings. Here is how to specify a single additional account file:

additional_accounts = "business/accounts"

Here is how you specify multiple additional account files:

additional_accounts = ["business/accounts", "charity/accounts"]

Accounts Fields

Each dictionary in accounts may contain a number of fields that are described next. When first created the accounts dictionary comes with some useful templates and an example account entry that is commented out. Feel free to modify the templates and delete the example account.

template

A string containing the ID of the template for this account (explained above).

master

A string containing the ID of the master password for this account. It is recommended that each account explicitly declare its master password (perhaps through a template). That way existing passwords do not change if you were to change your default master password.

version

The version is a string and its contents are arbitrary, however when its contents change so to does the generated password. So it can be as simple as a number or it could be a date or whatever you like. But it is good if you pick a convention and stick with it so that if you somehow lose your accounts file you still have some hope of recovering your passwords.

Some websites put odd restrictions on the generated passwords, such as it must contain a digit and a symbol or it imposes a limit on the maximum number of repeated characters. Some of these restrictions can be satisfied by adding a prefix or a suffix, but for others, like the repeated character limit, there is no built in support in Abraxas to always satisfy them. In this case you can simply bump the version until you get a password that meets their requirements.

password-type

The type of password to generate. Should be either ‘words’ (default) to generate pass phrases or ‘chars’ to generate passwords.

num-words

The number of words to use in the pass phrase when ‘type’ is ‘words’ (default is 4).

separator

A string that is used as the inter-word separator when ‘type’ is ‘words’. If not given, a space is used.

num-chars

The number of characters to use in the passwords when ‘type’ is ‘chars’ (default is 12).

alphabet

A string containing the characters to use when creating a password when ‘type’ is ‘chars’. The default alphabet consists of the standard upper and lower case letters along with the digits.

prefix

A string whose contents are added to the beginning of a password or passphrase.

suffix

A string whose contents are added to the end of a password or passphrase.

aliases

List of names that can be used as aliases for this account. This feature is often used to specify a shorter and easier to type name for the account.

The secrets are generated based on the primary account name (the key for dictionary that describes the account). As such, that name should be chosen so that it is unambiguous and you will never be tempted to change it. That often results in a name that is too long to type easily. This entry allows you to specify one or more names that can be used as aliases for the primary account name. For example, you might want to choose a name like “gmail-derrickAsh” as the primary name of your gmail account and “gmail” as an alias. This would allow you to later create another gmail account and make it your primary gmail account simply by moving the “gmail” alias the new account.

When sharing your accounts you may not wish to share your aliases. For example, if both you and your partner have accounts at Chase you may want to both use the alias Chase to refer to two different accounts. You can arrange this by using some Python code as follows:

from getpass import getuser

accounts = {
    'chase-amy': {
        'aliases': ['chase'] if getuser() == 'amy' else []
        ...
    },
    'chase-laura': {
        'aliases': ['chase'] if getuser() == 'laura' else []
        ...
    },
}
username

A string containing the username for the account.

account

Either an account identifier for the account or a list containing multiple account identifier. Account identifiers must be given as strings.

email

A string containing the email address associated with the account.

url

A string containing the web address of the account or a list of strings each containing a web address.

If a list of URLs are provided, the first will be used with the --browser and --default-browser command line arguments. In this case, the browser will be started and directed to display the first address. All the addresses are used in account discovery. If a URL component is discovered in a title bar, it will be compared against all of the URLs given in the list looking for a match. The URLs may be glob strings to generalize the matching. Given that the first URL can be sent to the browser it is best not to use globbing in the first URL.

When a URL is used in account discovery, the presence of the communication protocol is significant. If the URL starts with ‘https://‘, then Abraxas insists on the use of an encrypted link. If the link is not encrypted, the account will not be selected as a match and a warning will be issued (this is a relatively common way of tricking you into disclosing your password). Even if the URL does not start with ‘https://‘, Abraxas will also require a encrypted link if PREFER_HTTPS is set to True in password/prefs.py unless the URL starts with ‘http://‘.

remarks

A string containing any relevant remarks about the account. You can create a multiline remark as follows:

'remarks': dedent("""
    Wireless network settings:
        SSID: ourhouse
        Network security: WPA2 Personal
""")
security questions

A list of strings containing the security questions they force you to answer. The string does not need to contain the question verbatim, a shortened version that is sufficient for you to identify which of the questions you need to provide the answer to is enough. For example, a typical list of security questions might be:

'security questions': [
    "first teacher's name",
    "name of elementary school",
],

When initially giving the answers to these questions, you will have to select the questions you will answer, enter them into the accounts file, then get the answers by running Abraxas, and then copying the answers into the web page for your account. In this way, your answers will be quite unpredictable, even to those that know you well.

The answers to the security questions will change if you change your security questions. Even the smallest change will result in a completely different answer. Once you have given the answers to your account provider you must not change the question at all unless you are willing to go through the trouble of updating the answers.

window

This may be either a glob string or a list of glob strings that match the title of the web page used to enter the username/password for the account. This is used to determine which account should be used if no account name is given on the command line.

This enables you to set up a hot key, such as Alt-P, to run ‘abraxas –autotype’, which will identify which account to use from the active window title and then use the autotype field to log you in.

When using commands from a shell the title of the window is generally unaffected by the command that is running. However, you can write a simple script that first sets the window title and then runs the command. Here is an example of such a script for mutt:

#!/bin/sh
xdotool getactivewindow set_window --name "Mutt"
mutt

Alternatively, you can switch to Lilyterm, which is a Linux terminal emulator that I can recommend and that plays particularly nicely with Abraxas. It copies the command being run to the window title so it can be used to determine which account to use.

Generally the window feature works well with web browsers, though some sites neglect to put identifying information in the title bar of their login page. This can be addressed in Firefox and Thunderbird by installing the ‘Hostname in Titlebar’ add on. In Chrome, use ‘Url in Title’. They add the URL to the title bar, making it available to be matched with a window glob string. This add on also adds the protocol to the title as well. That allows you to key the password in such a way that it will not autotype unless the connection is encrypted (the protocol is https).

In its default configuration, Abraxas recognizes the components in a ‘Hostname in Titlebar’ title. Those components, which include the title, the hostname, and the communication protocol (http or https), and compare those to the corresponding entries in each account. The title is compared to the window entries and the hostname and protocol are compared against the url. If no match is made with these components, then the raw title is compared against the window entries.

When sharing your accounts with a partner you may not wish to share your window settings. For example, if both you and your partner have accounts at Chase and you both want to have the window title on the Chase web page to trigger your own account. You can arrange this by using some Python code as follows:

from getpass import getuser

accounts = {
    'chase-amy': {
        'window': ['CHASE Bank*'] if getuser() == 'amy' else []
    },
    'chase-laura': {
        'window': ['CHASE Bank*'] if getuser() == 'laura' else []
    },
}

You might also find that you need different passwords on different machines. For example, you may have root access on several machines, each of which has a different root password. You can handle this as follows:

from socket import gethostname
accounts = {
    'root-mars': {
        'template': '=words',
        'window': ['su'] if gethostname() == 'mars' else []
    },
    'root-venus': {
        'template': '=words',
        'window': ['su'] if gethostname() == 'venus' else []
    },
}
autotype

A string containing a script that controls autotyping (when the -t or –autotype command line option is specified). The script consists of characters that will be emitted verbatim and codes that specify actions to take. Primarily the action is to replace the code with a character, a field from the account, or a secret. But the sleep action can be used to cause a pause in the typing. The following actions are supported:

{username} Replaced with the username for the account.
{account} Replaced with the account number for the account.
{url} Replaced with the URL for the account.
{email} Replaced with the email address for the account.
{remarks} Replaced with the remarks for the account.
{password} Replaced with the password for the account.
{question N} Replaced with security question N (N is an integer).
{answer N} Replaced with the answer to security question N (N is an integer).
{sleep S} Typing is paused for S seconds (S a real number)
{tab} Replaced with a tab.
{return} Replaced with newline.

The default autotype script is “{username}{tab}{password}{return}”

Other Fields

The value of all other fields will be printed when the user requests all information about the account.

Words File

The words file is ‘~/.config/abraxas/words’. The use of this file is optional. Abraxas has its own words that it uses if you do not provide a file yourself. It should contain a large number of words (thousands), one word per line. The more words your file contains, the more secure your pass phrases are, however anymore than 65,536 are not used.

Do not change this file once you have started creating passwords, and be sure to back it up. Any change to this file will cause the generated pass phrases to change, which means you will not be able to use Abraxas to login to existing accounts that use pass phrases.

EXAMPLE

Master Password File

Here is a representative master password file (~/.config/abraxas/master.gpg):

dict_hash = "d9aa1c08e08d6cacdf82819eeb5832429eadb95a"
secrets_hash = "db7ce3fc4a9392187d0a8df7c80b0cdfd7b1bc22"
passwords = {
    'derrick and peter': "e9a7a4246a6a95f179cd4579e6f9cb69",
    'derrick and debbie': "60b56e021118ca2a261f405e15ac0165",
    'default': """[Y$*{QCf"?yvDc'{4v?4r.iA0b3brHY z40;lZIs~bjj<DpDz&wK!XCWq=,gb}-|""",
}
default_password = 'default'
password_overrides = {
    'yahoo': 'lollipop',
    'nytimes': 'excelsior',
}

Accounts File

Here is a representative accounts file (~/.config/abraxas/accounts) with the boilerplate code generated by Abraxas itself stripped off for brevity:

# Give the desired location of the file
logfile = '~/.config/abraxas/log'

# Account Information
accounts = {
    # Templates
    "=words": {  # typically used for Linux pass phrases
        'type': 'words',
        'num-words': 4,
        'autotype': "{password}{return}",
    },
    "=chars": {  # typically used for web passwords
        'type': 'chars',
        'num-chars': 12,
        'alphabet': ALPHANUMERIC + PUNCTUATION,
        'autotype': "{username}{tab}{password}{return}",
    },

    # Accounts
    "login": {
        'template': "=words",
        'window': [
            'su',
            'su *',
        ]
    },
    "mail": {
        'template': "login",
        'window': 'Mutt *',
    },
    "ssh": {
        'template': "login",
        'version': 'ssh',
        'window': 'tcsh: *',
    },
    "bank": {
        'template': "=chars",
        'username': "derrickash",
        'email': "derrickAsh@gmail.com",
        'url': "https://hpcu.com",
        'account': "1987-357836",
        'window': [
            'HP Credit Union*',
            'Hewlett-Packard Credit Union*',
        ],
        'autotype': "{account}{tab}{password}{return}",
    },
    "gmail": {
        'template': "=words",
        'username': "derrickAsh",
        'email': "derrick.ash@yahoo.com",
        'url': "https://accounts.google.com",
        'security questions': [
            "first teacher's name",
            "name of elementary school",
        ],
        'window': [
            'Google Accounts*',
            'Gmail*',
        ],
        'autotype': "{username}{tab}{password}{return}",
    },
    "yahoo": {
        'template': "=chars",
        'username': "derrickAsh",
        'email': "derrickAsh@gmail.com",
        'url': "https://login.yahoo.com",
        'window': 'Sign into Yahoo!*',
    },
    "nytimes": {
        'template': "=chars",
        'username': "derrickAsh",
        'email': "derrickAsh@gmail.com",
        'url': "https://myaccount.nytimes.com/auth/login",
        'window': '*The New York Times*',
    },
    "consumer-reports": {
        'template': "=chars",
        'master': 'derrick and debbie',
        'username': "DandD",
        'url': "https://ec.consumerreports.org/ec/myaccount/login.htm",
        'window': 'My account login*',
    },
}

CONFIGURATION

The file passwords/prefs.py in the source code contains various configuration settings that can be set to change the behavior of Abraxas. You should be careful when changing these. Some settings can be changed with little concern, but others match the implementation and changing them my require changes to the underlying code.

SEE ALSO

abraxas(1), abraxas(3)