54

I would like to compute the bcrypt hash of my password.

Is there an open source command line tool that would do that ?

I would use this hash in the Syncthing configuration file (even if I know from here that I can reset the password by editing the config file to remove the user and password in the gui section, then restart Syncthing).

4 Answers 4

73

You can (ab)use htpasswd from apache-utils package, provided you have version 2.4 or higher.

htpasswd -bnBC 10 "" password | tr -d ':\n'

-b takes the password from the second command argument
-n prints the hash to stdout instead of writing it to a file
-B instructs to use bcrypt
-C 10 sets the bcrypt cost to 10

The bare htpasswd command outputs in format <name>:<hash> followed by two newlines. Hence the empty string for name and tr stripping the colon and newlines.

The command outputs bcrypt with $2y$ prefix, which may be problem for some uses, but can easily be fixed by another sed since the OpenBSD variant using $2a$ is compatible with the fixed crypt_blowfish variant using $2y$.

htpasswd -bnBC 10 "" password | tr -d ':\n' | sed 's/$2y/$2a/'

Link to htpasswd man page: https://httpd.apache.org/docs/2.4/programs/htpasswd.html
Details about bcrypt variants: https://stackoverflow.com/a/36225192/6732096

5
  • This version has a problem with the BCrypt implementation of Java Spring Security. The password to hash must be terminated with a null character. Spring Security seems to do it correctly. I think htpasswd is not doing this correctly.
    – k_o_
    Apr 12, 2018 at 0:49
  • @k_o_: Can you be more specific on "has a problem"? All bcrypt implementations use the null-character terminator. Some, like py-bcrypt have even additional checks to ensure that null-character isn't a part of password. You can check the Apache implementation on GitHub. I'm using htpasswd with the additional sed to populate database records for multiple Spring applications without problems (that's actually how I come to the answer). Apr 12, 2018 at 5:29
  • I was assuming that leaving out the null character was a problem of htpasswd to explain the different encodings between Spring and htpasswd. The output from bcrypt using the other answer's Python approach was producing the same results like in Spring, but htpasswd was not. Maybe also my htpasswd version is quite old, I think the binary was not updated since 2 years.
    – k_o_
    Apr 12, 2018 at 21:13
  • There is yet another problem with Spring Security and BCrypt hashes generated with htpasswd. Spring Security (at least, certain versions) requires salt revision to be 'a' (so that the hashed password start with '$2a$'), but for me htpasswd generated revision 'y' ('$2y$....') and I was not able to find a way to specify the revision via command line. I then just abandoned htpasswd and generated the password using Spring Security code. Jul 29, 2020 at 8:07
  • The tr can be replaced with sed -E '/^:/s/:(.*)$/\1/p;d' (at least, on linux) to avoid stripping the one newline you might want to keep.
    – phs
    Feb 2, 2021 at 20:58
13

You can use a Python library. On my Fedora system I did:

sudo dnf search bcrypt

(the sudo is just to avoid wasting space for a user dnf cache) and from the result can see there is a Python2 and Python3 package:

py-bcrypt.x86_64 : Python bindings for OpenBSD's Blowfish password hashing code
python3-py-bcrypt.x86_64 : Python 3 bindings for OpenBSD's Blowfish password hashing code

Install the Python2 version and list the files in the package:

sudo dnf install py-bcrypt.x86_64
rpm -ql py-bcrypt.x86_64

This shows there is a file /usr/lib64/python2.7/site-packages/bcrypt/__init__.py so I can get the documentation with

pydoc bcrypt

This shows me enough to write the following command which will hash the string "password":

$ python -c 'import bcrypt; print(bcrypt.hashpw("password", bcrypt.gensalt(log_rounds=10)))'
$2a$10$vWFRZgbOx6RKOKYxCTtyWuMJM60E90Vdm/.0nj.X/o3dYUxvQ/2Dm

For later versions of bcrypt use rounds= instead of log_rounds=.

2
  • 2
    +1. FTR you don't need sudo to run dnf search, it works fine as a standard user. Sep 6, 2016 at 7:22
  • 1
    As of April 2018 the parameter log_rounds seems to have changed to rounds making it python -c 'import bcrypt; print(bcrypt.hashpw("password", bcrypt.gensalt(rounds=10)))'.
    – HorstKevin
    Apr 11, 2018 at 8:42
5

This is relevant for FreeBSD, since htpasswd isn't available without installing apache. Building on @meuh's answer, here's how to use Python3 in FreeBSD to get a bcrypt hash of a password - for example, for basic auth in a traefik jail.

Note the following assumes a jail. Be careful with pip if this is the base OS. Adjust for version of Python3 depending on FreeBSD version and current Python3 versions available on it.

pkg install py37-pip
pip install bcrypt

And run, again adjusting for Python 3 version:

python3.7 -c 'import bcrypt; print(bcrypt.hashpw(b"PASSWORD", bcrypt.gensalt(rounds=15)).decode("ascii"))'

@Stuart Cardall rightly points out that this lands your password in history. "Left to the reader" to take this Python3 snippet and expand by a prompt for username and password, so that this information doesn't end up in ps or history.

3

Additional to @Disassembler's answer:

  • it's not a good idea to pass passwords in from the command line (as the password could be viewable with ps)
  • 15 is a good balance for complexity / password generation speed

Wrapper script for htpasswd & bcrypt:

#!/bin/sh

## bcrypt passwd generator ##
#############################
CMD=$(which htpasswd 2>/dev/null)
OPTS="-nBC 15"
USERNAME=$1

usage() {
        local script=$(basename $0)
        cat <<EOF
$script: Generate Bcrypt Hashed Passwords using htpasswd

Usage: $script username
EOF
        exit 1
}

check_config() {
    if [ -z $CMD ]; then
        printf "Exiting: htpasswd is missing.\n"
        exit 1
    fi

    if [ -z "$USERNAME" ]; then
            usage
    fi
}

check_config $USERNAME
printf "Generating Bcrypt hash for username: $USERNAME\n\n"
$CMD $OPTS $USERNAME
exit $?
4
  • 2
    And unless you start the command line with a space, the password will go to your shell history (an file that is probably not encrypted). May 15, 2018 at 13:32
  • @GabrielDevillers yup, same here. I added "-i" to OPTS and "" to the 2nd-to-last line.
    – towi
    Nov 21, 2018 at 14:09
  • for BASH & mySQL history for the root user it's a good idea to create a symbolic link to /dev/null. Nov 21, 2018 at 15:57
  • 2
    Regarding @GabrielDevillers's comment, perhaps worth mentioning that adding a space to the start doesn't always hide an item from shell history -- depends on the shell and settings.
    – tremby
    Jul 28, 2019 at 5:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.