Entertainment at it's peak. The news is by your side.

Show HN: A password manager that uses age for encryption


Build Status

Warning! kbs2 is beta-quality design! The use of kbs2 manner accepting that your secrets could additionally be
lost or compromised at any time!

kbs2 is a expose line utility for managing secrets.

Quick links:



Whenever you are working a Debian or Ubuntu distribution on AMD64, you can well additionally use the .deb packages
hooked as a lot as the most up-to-date originate. Right here’s the
counseled manner to put in kbs2 whenever it is best to now not rising it.

By manner of instance:

# change X.X.X with your model
$ wget
$ sudo dpkg -i kbs2_X.X.X_amd64.deb
# manufacture now not neglect to quiz kbs2's dependencies
$ sudo proper-web -f install

Other distributions would possibly be supported in the slay. Succor us by taking a ogle at the
start packaging factors!


Whenever you are a Linux user, you will need some X11 libraries. For Debian-essentially essentially based entirely distributions:

$ sudo proper install -y libxcb-shape0-dev libxcb-xfixes0-dev

kbs2 itself is most with out problems establish in by job of cargo:

After set up, kbs2 is entirely ready to be used. Seek the
Configuration allotment for some optionally accessible changes that you can well additionally

Quick originate manual

Initialize a brand new kbs2 configuration:

kbs2 init will automatically generate a configuration file and keypair, prompting you for
a “master” password.

Comprise a brand new (login) epic:

$ kbs2 new amazon
Username: jonf-bonzo
Password: [hidden]

List accessible recordsdata:

$ kbs2 list

Pull the password from a epic:

$ kbs2 pass -c amazon
# alternatively, pipeline it
$ kbs2 pass fb | pbcopy

Hold away a epic:

kbs2‘s subcommands are substantially extra featured than the above examples reward;
coast each with --wait on to take into myth a fleshy spot of supported choices.

CLI documentation

kbs2 init


initialize kbs2 with a brand new config and keypair

    kbs2 init [FLAGS]

    -f, --power                   overwrite the config and keyfile, if already reward
    -h, --wait on                    Prints wait on details
        --scared-now not-wrapped    manufacture now not wrap the keypair with a master password


Comprise a brand new config and keypair, prompting the user for a master password:

Comprise a brand new config and keypair with out a master password:

$ kbs2 init --scared-now not-wrapped

kbs2 liberate


unwrap the non-public key to be used

    kbs2 liberate

    -h, --wait on    Prints wait on details


Unwrap the non-public key, allowing future commands to coast with out the master password:

kbs2 lock


take hold of the unwrapped key, if any, from shared memory

    kbs2 lock

    -h, --wait on    Prints wait on details


Hold away the unwrapped private key from shared memory, requiring future commands to advised for
the master password:

kbs2 new


manufacture a brand new epic

    kbs2 new [FLAGS] [OPTIONS] 


Comprise a brand new login epic named foobar:

$ kbs2 new foobar
Username: hasdrubal
Password: [hidden]

Comprise a brand new environment epic named twitter-api, overwriting it if it already exists:

$ kbs2 new -f -okay environment twitter-api
Price: [hidden]

Comprise a brand new login epic named, generating the password with the default generator:

$ kbs2 new -g
Username: hasdrubal

Comprise a brand new login epic named e-mail, getting the fields in a terse format:

$ kbs2 new -t e-mail < <(echo -e "bill@microsoft.comx01hunter2")

kbs2 list


list records

    kbs2 list [FLAGS] [OPTIONS]

    -d, --details    print (non-field) details for each record
    -h, --help       Prints help information

    -k, --kind     list only records of this kind
                         [possible values: login, environment, unstructured]


List all records, one per line:

$ kbs2 list

List (non-sensitive) details for each record:

$ kbs2 list -d
  Kind: login
  Timestamp: 1590277900
  Kind: environment
  Timestamp: 1590277907
  Kind: login
  Timestamp: 1590277920
  Kind: login
  Timestamp: 1590277953

List only environment records:

$ kbs2 list -k environment

kbs2 rm


remove a record

    kbs2 rm 


Remove the foobar record:

kbs2 dump


dump a record

    kbs2 dump [FLAGS] 


Dump the twitter-api record:

$ kbs2 dump twitter-api
Label: twitter-api
  Kind: environment
  Variable: TWITTER_API
  Value: 92h2890fn83fb2378fbf283bf73fbxkfnso90

Dump the record in JSON format:

$ kbs2 dump -j | json_pp
   "timestamp" :  1590363392,
   "label" :  "",
   "body" :  {
      "fields" :  {
         "username" :  "hasdrubal",
         "password" :  "hunter2"
      "kind" :  "Login"

kbs2 pass


get the password in a login record

    kbs2 pass [FLAGS] 


Get the password for the record:

$ kbs2 pass

Copy the password for the record into the clipboard:

kbs2 env


get an environment record

    kbs2 env [FLAGS] 


Get an environment record in export-able form:

$ kbs2 env twitter-api
export TWITTER_API=92h2890fn83fb2378fbf283bf73fbxkfnso90

Get just the value in an environment record:

$ kbs2 env -v twitter-api

kbs2 edit


modify a record with a text editor

    kbs2 edit [FLAGS] 


Open the email record for editing:

Open the email record for editing with a custom $EDITOR:

$ EDITOR=vim kbs2 edit email

kbs2 generate


generate secret values using a generator

    kbs2 generate [generator]

        the generator to use [default: default]

    -h, --help    Prints help information


Generate a secret using the default generator:

$ kbs2 generate

Generate a secret using a generator named pwgen:

$ kbs2 generate pwgen


kbs2 stores its configuration in /kbs2/kbs2.conf, where is determined
by your host system. On Linux, for example, it’s ~/.config.

kbs2.conf is TOML-formatted, and might look something like this after a clean start with kbs2 init:

public-key = "age1elujxyndwy0n9j2e2elmk9ns8vtltg69q620dr0sz4nu5fgj95xsl2peea"
keyfile = "/home/william/.config/kbs2/key"
store = "/home/william/.local/share/kbs2"

clipboard-duration = 10
clear-after = true
x11-clipboard = "Clipboard"

public-key (default: generated by kbs2 init)

The public-key setting records the public half of the age keypair used by kbs2.

kbs2 init pre-populates this setting; users should not modify it unless also modifying
the keyfile setting (e.g., to point to a pre-existing age keypair).

keyfile (default: generated by kbs2 init)

The keyfile setting records the path to the private half of the age keypair used by kbs2.

kbs2 init pre-populates this setting; users should not modify it unless also modifying
the public-key setting (e.g., to point to a pre-existing age keypair).

wrapped (default: true)

The wrapped settings records whether keyfile is a “wrapped” private key, i.e. whether
the private key itself is encrypted with a master password.

By default, kbs2 init asks the user for a master password and creates a wrapped key.
See the kbs2 init documentation for more information.

store (default: /kbs2)

The store setting records the path to the secret store, i.e. where records are kept.

Users may modify this setting to store their records in custom directory.

pre-hook (default: None)

The pre-hook setting can be used to run a command before (almost) every kbs2 invocation.

Read the Hooks documentation for more details.

post-hook (default: None)

The post-hook setting can be used to run a command after (almost) every kbs2 invocation.

There are currently four cases when the configured post-hook will not run:

  • kbs2 (i.e., no subcommand)
  • kbs2 init
  • kbs2 unlock
  • kbs2 lock

All other subcommands, including custom subcommands, will cause the configured post-hook to run.

Read the Hooks documentation for more details.

reentrant-hooks (default: false)

The reentrant-hooks setting controls whether hooks are run multiple times when a hook itself
runs kbs2. By default, hooks are run only for the initial kbs2 invocation.

Read the Reentrancy section of the Hooks documentation for more details. (default: false)

The setting determines whether or not uses the default generator
when the user supplies an empty input for a sensitive field (e.g., a password).

By default, supplying an empty field causes kbs2 to re-prompt for that field. For example:

$ kbs2 new top-secret-login
Username: foobar
Password: [empty]

with generate-on-empty = true:

$ kbs2 new top-secret-login
Username: foobar
Password: [empty]

$ kbs2 dump top-secret-login
Label: top-secret-login
  Kind: login
  Username: foobar
  Password: 17tlza7b_4}f(m6)

This can be used as a lazy default for when the user forgets to pass --generate to kbs2 new. (default: None)

The setting is like the global pre-hook setting, except that it runs
immediately before record creation during kbs2 new (and only kbs2 new). (default: None)

The setting is like the global post-hook setting, except that it runs
immediately after record creation during kbs2 new (and only kbs2 new).

The setting passes a single argument to its hook, which is the label
of the record that was just created. For example, the following:

post-hook = "~/.config/kbs2/hooks/"
# ~/.config/kbs2/hooks/

>&2 echo "[+] created ${1}"

would produce:

$ kbs2 new foo
Username: bar
Password: [hidden]
[+] created foo

commands.pass.clipboard-length (default: 10)

The commands.pass.clipboard-length atmosphere determines the length, in seconds, for persisting
a password saved in the clipboard by job of kbs2 pass -c.

commands.pass.sure-after (default: upright)

The commands.pass.sure-after atmosphere determines whether or now not the clipboard is cleared at
all after kbs2 pass -c.

Setting this to wrong overrides any length configured in commands.pass.clipboard-length.

commands.pass.x11-clipboard (default: "Clipboard")

The commands.pass.x11-clipboard atmosphere determines which clipboard is used on X11.

Pleasant choices are "Clipboard" and "Main".

commands.pass.pre-hook (default: None)

The expose.pass.pre-hook atmosphere is just like the worldwide pre-hook atmosphere, as a change of that it runs
straight earlier than epic entry for the duration of kbs2 pass (and supreme kbs2 pass). (default: None)

The atmosphere is just like the worldwide post-hook atmosphere, as a change of that it runs
straight after epic entry for the duration of kbs2 pass (and supreme kbs2 pass).

expose.pass.sure-hook (default: None)

The expose.pass.sure-hook is like utterly different expose.pass hooks, as a change of that it supreme runs
after the password has been cleared from the clipboard.

commands.edit.editor (default: None)

The commands.edit.editor atmosphere controls which editor is used when opening a file with
kbs2 edit. This atmosphere takes precedence over the $EDITOR environment variable, which is
used as a fallback.

This atmosphere is allowed to possess flags. For instance, the next would be fracture up correctly:

editor = "subl -w" (default: None)

The atmosphere is just like the worldwide post-hook atmosphere, as a change of that it runs
straight after epic bettering for the duration of kbs2 edit (and supreme kbs2 edit). (default: None)

The atmosphere is just like the worldwide post-hook atmosphere, as a change of that it runs
straight after epic elimination for the duration of kbs2 rm (and supreme kbs2 rm).


kbs2 helps generators for producing sensitive values, allowing users to automatically
generate passwords and environment variables.

Generators reach in two flavors: “expose” generators and “inner” generators. Both are
configured as entries in [[generators]].

The next configures two generators: a “expose” generator named “pwgen” that executes
pwgen to web a brand new secret, and an “inner” generator named “hexonly” that generates
a secret from the configured alphabet and length.

name = "pwgen"
expose = "pwgen 16 1"

name = "hexonly"
alphabet = "0123456789abcdef"
length = 16

These generators could additionally be used with kbs2 new:

# Sight: the user is now not brought about for a password
$ kbs2 new -gG hexonly
Username: catlover2000


Beyond the configuration above, kbs2 offers several avenues for personalization.

Customized commands

kbs2 helps git-sort subcommands, allowing you to with out problems write your beget.

For instance, working the next:

$ kbs2 frobulate --xyz

will aim kbs2 to coast kbs2-frobulate --xyz. Customized commands are allowed to be taught from and
write to the config file below the [commands.] hierarchy.

When coast by job of kbs2, customized commands receive the next environment variables:

  • KBS2_CONFIG_DIR: The path to the configuration itemizing that kbs2 itself became loaded with.
    Subcommands can use this path to be taught the brand new configuration file or any utterly different squawk material saved
    in the configuration itemizing.
  • KBS2_STORE: The path to the important thing store.
  • KBS2_SUBCOMMAND: Frequently spot to 1. This could additionally be used to resolve whether a subcommand became coast
    by job of kbs2 (e.g. kbs2 foo) versus straight (e.g. kbs2-foo).

The contrib/ext-cmds itemizing accommodates several precious external commands.


kbs2 exposes hook-factors for the duration of the lifecycle of an invocation, allowing users to
inject extra functionality or compose their very beget bookkeeping.

The hook API

All hooks, whether pre- or post-, have the next behavior:

  • Hooks terminate now not inherit stdin or stdout from the parent kbs2 course of
  • Hooks terminate inherit stderr from the parent course of, and could additionally merely use it to print one thing
    they please
  • Hooks repeatedly coast from the store itemizing
  • Hooks are coast with KBS2_HOOK=1 of their environment and with KBS2_CONFIG_DIR spot to the
    configuration itemizing that the long-established kbs2 expose became loaded with
  • An error exit from a hook (or failure to complete) causes your complete kbs2 expose to fail

Hooks could additionally merely introduce extra behavior, see you later as it does now not struggle with the above.
Any extra hook behavior is documented below that hook’s configuration atmosphere.


kbs2‘s hooks are non-reentrant by default.

To fancy what that manner, think in regards to the next hook setup:

pre-hook = "~/.config/kbs2/hooks/"
# ~/.config/kbs2/hooks/

kbs2 some-utterly different-expose

after which:

In this atmosphere, most users would quiz to be coast exactly as soon as: on kbs2 list.

Then as soon as more, naively, it ought to complete twice: as soon as for kbs2 list, and as soon as more for
kbs2 some-utterly different-expose. In utterly different phrases, naively, hooks would reenter themselves every time
they use kbs2 internally.

Most users get this complicated and would steal into consideration it an obstacle to hook writing, so kbs2
does now not terminate this by default. Then as soon as more, could additionally merely aloof you wish for reentrant hooks, you have two

  • You have to to well additionally spot reentrant-hooks to upright in the configuration. This could originate all hooks
    reentrant — it be all or nothing, deliberately.
  • You have to to well additionally unset or otherwise delete the KBS2_HOOK environment variable in your hook
    earlier than working kbs2 internally. Which capability you can manipulate which hooks aim reentrancy.
    Beware: KBS2_HOOK is an implementation detail! Unset it at your beget threat!

Why one other password manager?

No moral reason. Seek the historical previous allotment.

Technical exiguous print

Menace mannequin

kbs2‘s threat mannequin is corresponding to that of most password and secret managers. In train:

  • kbs2 does now not attempt to defend in opposition to the root user or arbitrary code accomplished by the
    new user.
  • kbs2 tries to manual sure of operations that can consequence in secret discipline cloth (i.e. the non-public key
    and the decrypted contents of recordsdata) being saved or cached on disk, however does now not attempt to
    reward the customers of secret discipline cloth from doing so.
  • kbs2, by default, makes an attempt to terminate offline private key extraction by encrypting the non-public
    key at relaxation with a master password. kbs2 does now not attempt to terminate the user from mishandling
    their master password.


kbs2 does now not put into effect any cryptography by itself — it makes use of supreme the cryptographic
primitives provided by an age implementation. In train,
kbs2 makes use of the rage implementation of age.

The particulars of kbs2‘s cryptographic utilization are as follows:

  • Every kbs2 configuration file specifies a symmetric keypair. The overall public key is
    saved in the public-key configuration atmosphere, while the non-public key is saved in the file
    referenced by the keyfile atmosphere.
  • By default, kbs2 “wraps” (i.e. encrypts) the non-public key with a master password. This makes
    offline key extraction attacks extra irritating (though now not impossible) and makes the implications
    of wrapped private key disclosure less severe. Customers could additionally merely steal to use a non-wrapped key by
    passing --scared-now not-wrapped to kbs2 init.

Key unwrapping and persistence

As talked about below Menace Model and Cryptography, kbs2 makes use of
a wrapped private key by default.

With none persistence, wrapped key utilization would be gradual: the user would ought to re-enter
their master password on each kbs2 circulate, defeating the level of getting a secret manager.

To steer sure of this, kbs2 establishes persistence of the unwrapped key with a POSIX shared memory
object (particularly, an object named /_kbs2_uk_{truncated-SHA256-of-your-keyfile-path}). This
is performed after first use or explicitly with kbs2 liberate. The unwrapped key could additionally be de-endured
either by rebooting the machine or by working kbs2 lock.

Unlike like ssh-agent and gpg-agent, kbs2‘s shared memory object is now not tied to a user’s
session. This way that logging out and logging wait on in does now not require the user to re-enter
their master password until they have got otherwise configured their machine to coast kbs2 lock
earlier than the tip of their session.


Hacking on kbs2 in all equity straightforward. To compose a entirely functional sort replica,
marvelous use cargo compose in the repository root:

$ cargo compose
$ ./target/debug/kbs2 --wait on

Of reward: some functionality in the age crate has pathological performance in debug builds.
In train, decryption and key unwrapping are identified to be particularly slack.

To steer sure of this, use a originate compose:

$ cargo compose --originate
$ ./target/originate/kbs2 --wait on


kbs2 makes use of log and env_logger for logging. You have to to well additionally previous RUST_LOG=debug in your environment
to permit debug logging:

$ RUST_LOG=debug ./target/originate/kbs2 list -okay login

Seek the env_logger documentation for added attainable RUST_LOG values.

Historical previous

TL;DR: kbs2 is short for “KBSecret 2″.

In 2017, I wrote KBSecret as a fashioned aim secret manager for the Keybase ecosystem.

KBSecret became written in Ruby and piggybacked off of Keybase + KBFS for encryption, storage,
and synchronization. It became additionally extremely flexible, allowing user-defined epic kinds, secret
sharing between users and teams, and tons of convenient and passable CLI tools for
integration into my sort ecosystem.

Unfortunately, KBSecret became additionally extremely slack: it became written in
obnoxiously metaprogrammed Ruby,
relied heavily on re-entrant CLIs, and became extra capped by the latency and raw performance of KBFS

Having a slack secret manager became elegant for my gains, however I
now now not belief that Keybase (and KBFS) will continue
to receive the work they require. I additionally now now not have the time to serve KBSecret’s (slowly)
deteriorating codebase.

kbs2 is my attempt to breed the appropriate aspects of KBSecret in a sooner language. Besides the
name and a few excessive-level carry out choices, it shares nothing in celebrated with the long-established KBSecret.
It is supreme named kbs2 on myth of I’m used to typing “kbs” in my terminal.

Read More

Leave A Reply

Your email address will not be published.