Discussion:
[PATCH] Add support for XKCD-style wordlist passwords
Adhityaa Chandrasekar
2018-10-30 05:00:36 UTC
Permalink
---
man/pass.1 | 17 ++++++++++-------
src/password-store.sh | 16 +++++++++++-----
2 files changed, 21 insertions(+), 12 deletions(-)

This is my first time contributing to pass as a long-time user. In this
patch, I'm adding support for XKCD-style passwords [1] composed of words
from a wordlist. Since there is no standardised location for a
dictionary of words, the user has to specify a path to a file with the
--wordlist argument.

I don't know much bash/zsh/fish completions, so I'm afraid someone else
will have to help with that.

[1] https://xkcd.com/936/

- Adhityaa

diff --git a/man/pass.1 b/man/pass.1
index 01a3fbe..72a83fc 100644
--- a/man/pass.1
+++ b/man/pass.1
@@ -122,15 +122,18 @@ ensure that temporary files are created in \fI/dev/shm\fP in order to avoid writ
difficult-to-erase disk sectors. If \fI/dev/shm\fP is not accessible, fallback to
the ordinary \fITMPDIR\fP location, and print a warning.
.TP
-\fBgenerate\fP [ \fI--no-symbols\fP, \fI-n\fP ] [ \fI--clip\fP, \fI-c\fP ] [ \fI--in-place\fP, \fI-i\fP | \fI--force\fP, \fI-f\fP ] \fIpass-name [pass-length]\fP
+\fBgenerate\fP [ \fI--no-symbols\fP, \fI-n\fP ] [ \fI--wordlist /path/to/wordlist\fP, \fI-w /path/to/wordlist\fP ][ \fI--clip\fP, \fI-c\fP ] [ \fI--in-place\fP, \fI-i\fP | \fI--force\fP, \fI-f\fP ] \fIpass-name [pass-length]\fP
Generate a new password using \fB/dev/urandom\fP of length \fIpass-length\fP
(or \fIPASSWORD_STORE_GENERATED_LENGTH\fP if unspecified) and insert into
-\fIpass-name\fP. If \fI--no-symbols\fP or \fI-n\fP is specified, do not use
-any non-alphanumeric characters in the generated password. The character sets used
-in generating passwords can be changed with the \fIPASSWORD_STORE_CHARACTER_SET\fP and
-\fIPASSWORD_STORE_CHARACTER_SET_NO_SYMBOLS\fP environment variables, described below.
-If \fI--clip\fP or \fI-c\fP is specified, do not print the password but instead copy
-it to the clipboard using
+\fIpass-name\fP. If \fI--no-symbols\fP or \fI-n\fP is specified, do not use any
+non-alphanumeric characters in the generated password. If \fI--wordlist\fP is
+specified, along with a file as argument containing a list of words to choose
+from, four words will be randomly chosen and used as password. The character
+sets used in generating passwords can be changed with the
+\fIPASSWORD_STORE_CHARACTER_SET\fP and
+\fIPASSWORD_STORE_CHARACTER_SET_NO_SYMBOLS\fP environment variables, described
+below. If \fI--clip\fP or \fI-c\fP is specified, do not print the password but
+instead copy it to the clipboard using
.BR xclip (1)
and then restore the clipboard after 45 (or \fIPASSWORD_STORE_CLIP_TIME\fP) seconds. If \fI--qrcode\fP
or \fI-q\fP is specified, do not print the password but instead display a QR code using
diff --git a/src/password-store.sh b/src/password-store.sh
index d89d455..2778c26 100755
--- a/src/password-store.sh
+++ b/src/password-store.sh
@@ -491,12 +491,13 @@ cmd_edit() {
}

cmd_generate() {
- local opts qrcode=0 clip=0 force=0 characters="$CHARACTER_SET" inplace=0 pass
- opts="$($GETOPT -o nqcif -l no-symbols,qrcode,clip,in-place,force -n "$PROGRAM" -- "$@")"
+ local opts qrcode=0 clip=0 force=0 characters="$CHARACTER_SET" wordlist=0 inplace=0 pass
+ opts="$($GETOPT -o nw:qcif -l no-symbols,wordlist:,qrcode,clip,in-place,force -n "$PROGRAM" -- "$@")"
local err=$?
eval set -- "$opts"
while true; do case $1 in
-n|--no-symbols) characters="$CHARACTER_SET_NO_SYMBOLS"; shift ;;
+ -w|--wordlist) wordlist=$2; shift; shift ;;
-q|--qrcode) qrcode=1; shift ;;
-c|--clip) clip=1; shift ;;
-f|--force) force=1; shift ;;
@@ -504,7 +505,7 @@ cmd_generate() {
--) shift; break ;;
esac done

- [[ $err -ne 0 || ( $# -ne 2 && $# -ne 1 ) || ( $force -eq 1 && $inplace -eq 1 ) || ( $qrcode -eq 1 && $clip -eq 1 ) ]] && die "Usage: $PROGRAM $COMMAND [--no-symbols,-n] [--clip,-c] [--qrcode,-q] [--in-place,-i | --force,-f] pass-name [pass-length]"
+ [[ $err -ne 0 || ( $# -ne 2 && $# -ne 1 ) || ( $force -eq 1 && $inplace -eq 1 ) || ( $qrcode -eq 1 && $clip -eq 1 ) ]] && die "Usage: $PROGRAM $COMMAND [--no-symbols,-n] [--wordlist,-w /path/to/wordlist] [--clip,-c] [--qrcode,-q] [--in-place,-i | --force,-f] pass-name [pass-length]"
local path="$1"
local length="${2:-$GENERATED_LENGTH}"
check_sneaky_paths "$path"
@@ -517,8 +518,13 @@ cmd_generate() {

[[ $inplace -eq 0 && $force -eq 0 && -e $passfile ]] && yesno "An entry already exists for $path. Overwrite it?"

- read -r -n $length pass < <(LC_ALL=C tr -dc "$characters" < /dev/urandom)
- [[ ${#pass} -eq $length ]] || die "Could not generate password from /dev/urandom."
+ if [[ "$wordlist" != "" ]]; then
+ pass=$(shuf -n 4 "$wordlist" | paste -sd "-" -)
+ else
+ read -r -n $length pass < <(LC_ALL=C tr -dc "$characters" < /dev/urandom)
+ [[ ${#pass} -eq $length ]] || die "Could not generate password from /dev/urandom."
+ fi
+
if [[ $inplace -eq 0 ]]; then
echo "$pass" | $GPG -e "${GPG_RECIPIENT_ARGS[@]}" -o "$passfile" "${GPG_OPTS[@]}" || die "Password encryption aborted."
else
--
2.19.1
Brad Knowles
2018-10-30 05:10:24 UTC
Permalink
Post by Adhityaa Chandrasekar
+ if [[ "$wordlist" != "" ]]; then
+ pass=$(shuf -n 4 "$wordlist" | paste -sd "-" -)
+ else
While I think the concept is a good one, I don't think we should be depending on the user having "shuf" installed on their machine. I don't have it on mine, and I've installed a whole boatload of extra stuff that most people don't have.

I'm also not sure about "paste", although I do happen to have a program by that name on my machine.

IMO, you're better off sticking to more standard *nix utilities.
--
Brad Knowles <***@shub-internet.org>

Please forgive any typos. I'm fighting a failing keyboard on my laptop, in addition to having a broken finger.
Adhityaa Chandrasekar
2018-10-30 05:50:48 UTC
Permalink
From bb2a4e5664b2580ed1acbe973d4f86d550b529f1 Mon Sep 17 00:00:00 2001
From: Adhityaa Chandrasekar <***@adtac.in>
Date: Mon, 29 Oct 2018 19:10:23 -0400
Subject: [PATCH v3] Add support for XKCD-style wordlist passwords

Oops, attempting to read line 0 with sed will result in an error, so
line_num must be greater than or equal to 1. Fixed that.

(Man, I suck at mailing list patches.)

---
man/pass.1            | 17 ++++++++++-------
src/password-store.sh | 22 +++++++++++++++++-----
2 files changed, 27 insertions(+), 12 deletions(-)

diff --git a/man/pass.1 b/man/pass.1
index 01a3fbe..72a83fc 100644
--- a/man/pass.1
+++ b/man/pass.1
@@ -122,15 +122,18 @@ ensure that temporary files are created in \fI/dev/shm\fP in order to avoid writ
difficult-to-erase disk sectors. If \fI/dev/shm\fP is not accessible, fallback to
the ordinary \fITMPDIR\fP location, and print a warning.
.TP
-\fBgenerate\fP [ \fI--no-symbols\fP, \fI-n\fP ] [ \fI--clip\fP, \fI-c\fP ] [ \fI--in-place\fP, \fI-i\fP | \fI--force\fP, \fI-f\fP ] \fIpass-name [pass-length]\fP
+\fBgenerate\fP [ \fI--no-symbols\fP, \fI-n\fP ] [ \fI--wordlist /path/to/wordlist\fP, \fI-w /path/to/wordlist\fP ][ \fI--clip\fP, \fI-c\fP ] [ \fI--in-place\fP, \fI-i\fP | \fI--force\fP, \fI-f\fP ] \fIpass-name [pass-length]\fP
Generate a new password using \fB/dev/urandom\fP of length \fIpass-length\fP
(or \fIPASSWORD_STORE_GENERATED_LENGTH\fP if unspecified) and insert into
-\fIpass-name\fP. If \fI--no-symbols\fP or \fI-n\fP is specified, do not use
-any non-alphanumeric characters in the generated password. The character sets used
-in generating passwords can be changed with the \fIPASSWORD_STORE_CHARACTER_SET\fP and
-\fIPASSWORD_STORE_CHARACTER_SET_NO_SYMBOLS\fP environment variables, described below.
-If \fI--clip\fP or \fI-c\fP is specified, do not print the password but instead copy
-it to the clipboard using
+\fIpass-name\fP. If \fI--no-symbols\fP or \fI-n\fP is specified, do not use any
+non-alphanumeric characters in the generated password. If \fI--wordlist\fP is
+specified, along with a file as argument containing a list of words to choose
+from, four words will be randomly chosen and used as password. The character
+sets used in generating passwords can be changed with the
+\fIPASSWORD_STORE_CHARACTER_SET\fP and
+\fIPASSWORD_STORE_CHARACTER_SET_NO_SYMBOLS\fP environment variables, described
+below.  If \fI--clip\fP or \fI-c\fP is specified, do not print the password but
+instead copy it to the clipboard using
.BR xclip (1)
and then restore the clipboard after 45 (or \fIPASSWORD_STORE_CLIP_TIME\fP) seconds. If \fI--qrcode\fP
or \fI-q\fP is specified, do not print the password but instead display a QR code using
diff --git a/src/password-store.sh b/src/password-store.sh
index d89d455..d8bf9e4 100755
--- a/src/password-store.sh
+++ b/src/password-store.sh
@@ -491,12 +491,13 @@ cmd_edit() {
}

cmd_generate() {
- local opts qrcode=0 clip=0 force=0 characters="$CHARACTER_SET" inplace=0 pass
- opts="$($GETOPT -o nqcif -l no-symbols,qrcode,clip,in-place,force -n "$PROGRAM" -- "$@")"
+ local opts qrcode=0 clip=0 force=0 characters="$CHARACTER_SET" wordlist=0 inplace=0 pass
+ opts="$($GETOPT -o nw:qcif -l no-symbols,wordlist:,qrcode,clip,in-place,force -n "$PROGRAM" -- "$@")"
local err=$?
eval set -- "$opts"
while true; do case $1 in
-n|--no-symbols) characters="$CHARACTER_SET_NO_SYMBOLS"; shift ;;
+ -w|--wordlist) wordlist=$2; shift; shift ;;
-q|--qrcode) qrcode=1; shift ;;
-c|--clip) clip=1; shift ;;
-f|--force) force=1; shift ;;
@@ -504,7 +505,7 @@ cmd_generate() {
--) shift; break ;;
esac done

- [[ $err -ne 0 || ( $# -ne 2 && $# -ne 1 ) || ( $force -eq 1 && $inplace -eq 1 ) || ( $qrcode -eq 1 && $clip -eq 1 ) ]] && die "Usage: $PROGRAM $COMMAND [--no-symbols,-n] [--clip,-c] [--qrcode,-q] [--in-place,-i | --force,-f] pass-name [pass-length]"
+ [[ $err -ne 0 || ( $# -ne 2 && $# -ne 1 ) || ( $force -eq 1 && $inplace -eq 1 ) || ( $qrcode -eq 1 && $clip -eq 1 ) ]] && die "Usage: $PROGRAM $COMMAND [--no-symbols,-n] [--wordlist,-w /path/to/wordlist] [--clip,-c] [--qrcode,-q] [--in-place,-i | --force,-f] pass-name [pass-length]"
local path="$1"
local length="${2:-$GENERATED_LENGTH}"
check_sneaky_paths "$path"
@@ -517,8 +518,19 @@ cmd_generate() {

[[ $inplace -eq 0 && $force -eq 0 && -e $passfile ]] && yesno "An entry already exists for $path. Overwrite it?"

- read -r -n $length pass < <(LC_ALL=C tr -dc "$characters" < /dev/urandom)
- [[ ${#pass} -eq $length ]] || die "Could not generate password from /dev/urandom."
+ if [[ "$wordlist" != "" ]]; then
+ num_lines=$(wc -l "$wordlist" | cut -d ' ' -f 1)
+ pass=""
+ for i in $(seq 1 4); do
+ line_num=$((1 + ($RANDOM << 16 + $RANDOM) % $num_lines))
+ pass=$(sed "${line_num}q;d" "$wordlist" | grep -o "[a-z]" | tr -d "\n")-$pass
+ done
+ pass=${pass:0:-1}
+ else
+ read -r -n $length pass < <(LC_ALL=C tr -dc "$characters" < /dev/urandom)
+ [[ ${#pass} -eq $length ]] || die "Could not generate password from /dev/urandom."
+ fi
+
if [[ $inplace -eq 0 ]]; then
echo "$pass" | $GPG -e "${GPG_RECIPIENT_ARGS[@]}" -o "$passfile" "${GPG_OPTS[@]}" || die "Password encryption aborted."
else
--
2.19.1
Post by Adhityaa Chandrasekar
+ if [[ "$wordlist" != "" ]]; then
+ pass=$(shuf -n 4 "$wordlist" | paste -sd "-" -)
+ else
While I think the concept is a good one, I don't think we should be depending on the user having "shuf" installed on their machine.  I don't have it on mine, and I've installed a whole boatload of extra stuff that most people don't have.
I'm also not sure about "paste", although I do happen to have a program by that name on my machine.
IMO, you're better off sticking to more standard *nix utilities.
--
Please forgive any typos.  I'm fighting a failing keyboard on my laptop, in addition to having a broken finger.
Cong Ma
2018-10-30 05:13:24 UTC
Permalink
Post by Adhityaa Chandrasekar
---
man/pass.1 | 17 ++++++++++-------
src/password-store.sh | 16 +++++++++++-----
2 files changed, 21 insertions(+), 12 deletions(-)
This is my first time contributing to pass as a long-time user. In this
patch, I'm adding support for XKCD-style passwords [1] composed of words
from a wordlist. Since there is no standardised location for a
dictionary of words, the user has to specify a path to a file with the
--wordlist argument.
I don't know much bash/zsh/fish completions, so I'm afraid someone else
will have to help with that.
[1] https://xkcd.com/936/
- Adhityaa
Hello Adhityaa,

You might be interested in a diceware-style password generator based on
pass: https://github.com/congma/pass-genphrase

I wrote this a while ago and opted for the EFF long word list
(https://www.eff.org/deeplinks/2016/07/new-wordlists-random-passphrases)
as the source of words.

Cheers,
Cong.
Adhityaa Chandrasekar
2018-10-30 05:44:22 UTC
Permalink
From 7732f29809e72aae54dca5f598a3f00e84b6b0e2 Mon Sep 17 00:00:00 2001
From: Adhityaa Chandrasekar <***@adtac.in>
Date: Mon, 29 Oct 2018 19:10:23 -0400
Subject: [PATCH v2] Add support for XKCD-style wordlist passwords


Thanks for the comments, Brad. I've removed shuf and paste and I've
replaced them with wc, seq, sed, grep, and tr, all of which must be in
any standard *nix installation (the last three are used all over the
script anyway).

I'm not sure what the etiquette for sending v2 is, but I've included the
entire email below.

---
man/pass.1 | 17 ++++++++++-------
src/password-store.sh | 22 +++++++++++++++++-----
2 files changed, 27 insertions(+), 12 deletions(-)

diff --git a/man/pass.1 b/man/pass.1
index 01a3fbe..72a83fc 100644
--- a/man/pass.1
+++ b/man/pass.1
@@ -122,15 +122,18 @@ ensure that temporary files are created in \fI/dev/shm\fP in order to avoid writ
difficult-to-erase disk sectors. If \fI/dev/shm\fP is not accessible, fallback to
the ordinary \fITMPDIR\fP location, and print a warning.
.TP
-\fBgenerate\fP [ \fI--no-symbols\fP, \fI-n\fP ] [ \fI--clip\fP, \fI-c\fP ] [ \fI--in-place\fP, \fI-i\fP | \fI--force\fP, \fI-f\fP ] \fIpass-name [pass-length]\fP
+\fBgenerate\fP [ \fI--no-symbols\fP, \fI-n\fP ] [ \fI--wordlist /path/to/wordlist\fP, \fI-w /path/to/wordlist\fP ][ \fI--clip\fP, \fI-c\fP ] [ \fI--in-place\fP, \fI-i\fP | \fI--force\fP, \fI-f\fP ] \fIpass-name [pass-length]\fP
Generate a new password using \fB/dev/urandom\fP of length \fIpass-length\fP
(or \fIPASSWORD_STORE_GENERATED_LENGTH\fP if unspecified) and insert into
-\fIpass-name\fP. If \fI--no-symbols\fP or \fI-n\fP is specified, do not use
-any non-alphanumeric characters in the generated password. The character sets used
-in generating passwords can be changed with the \fIPASSWORD_STORE_CHARACTER_SET\fP and
-\fIPASSWORD_STORE_CHARACTER_SET_NO_SYMBOLS\fP environment variables, described below.
-If \fI--clip\fP or \fI-c\fP is specified, do not print the password but instead copy
-it to the clipboard using
+\fIpass-name\fP. If \fI--no-symbols\fP or \fI-n\fP is specified, do not use any
+non-alphanumeric characters in the generated password. If \fI--wordlist\fP is
+specified, along with a file as argument containing a list of words to choose
+from, four words will be randomly chosen and used as password. The character
+sets used in generating passwords can be changed with the
+\fIPASSWORD_STORE_CHARACTER_SET\fP and
+\fIPASSWORD_STORE_CHARACTER_SET_NO_SYMBOLS\fP environment variables, described
+below. If \fI--clip\fP or \fI-c\fP is specified, do not print the password but
+instead copy it to the clipboard using
.BR xclip (1)
and then restore the clipboard after 45 (or \fIPASSWORD_STORE_CLIP_TIME\fP) seconds. If \fI--qrcode\fP
or \fI-q\fP is specified, do not print the password but instead display a QR code using
diff --git a/src/password-store.sh b/src/password-store.sh
index d89d455..61928ab 100755
--- a/src/password-store.sh
+++ b/src/password-store.sh
@@ -491,12 +491,13 @@ cmd_edit() {
}

cmd_generate() {
- local opts qrcode=0 clip=0 force=0 characters="$CHARACTER_SET" inplace=0 pass
- opts="$($GETOPT -o nqcif -l no-symbols,qrcode,clip,in-place,force -n "$PROGRAM" -- "$@")"
+ local opts qrcode=0 clip=0 force=0 characters="$CHARACTER_SET" wordlist=0 inplace=0 pass
+ opts="$($GETOPT -o nw:qcif -l no-symbols,wordlist:,qrcode,clip,in-place,force -n "$PROGRAM" -- "$@")"
local err=$?
eval set -- "$opts"
while true; do case $1 in
-n|--no-symbols) characters="$CHARACTER_SET_NO_SYMBOLS"; shift ;;
+ -w|--wordlist) wordlist=$2; shift; shift ;;
-q|--qrcode) qrcode=1; shift ;;
-c|--clip) clip=1; shift ;;
-f|--force) force=1; shift ;;
@@ -504,7 +505,7 @@ cmd_generate() {
--) shift; break ;;
esac done

- [[ $err -ne 0 || ( $# -ne 2 && $# -ne 1 ) || ( $force -eq 1 && $inplace -eq 1 ) || ( $qrcode -eq 1 && $clip -eq 1 ) ]] && die "Usage: $PROGRAM $COMMAND [--no-symbols,-n] [--clip,-c] [--qrcode,-q] [--in-place,-i | --force,-f] pass-name [pass-length]"
+ [[ $err -ne 0 || ( $# -ne 2 && $# -ne 1 ) || ( $force -eq 1 && $inplace -eq 1 ) || ( $qrcode -eq 1 && $clip -eq 1 ) ]] && die "Usage: $PROGRAM $COMMAND [--no-symbols,-n] [--wordlist,-w /path/to/wordlist] [--clip,-c] [--qrcode,-q] [--in-place,-i | --force,-f] pass-name [pass-length]"
local path="$1"
local length="${2:-$GENERATED_LENGTH}"
check_sneaky_paths "$path"
@@ -517,8 +518,19 @@ cmd_generate() {

[[ $inplace -eq 0 && $force -eq 0 && -e $passfile ]] && yesno "An entry already exists for $path. Overwrite it?"

- read -r -n $length pass < <(LC_ALL=C tr -dc "$characters" < /dev/urandom)
- [[ ${#pass} -eq $length ]] || die "Could not generate password from /dev/urandom."
+ if [[ "$wordlist" != "" ]]; then
+ num_lines=$(wc -l "$wordlist" | cut -d ' ' -f 1)
+ pass=""
+ for i in $(seq 1 4); do
+ line_num=$((($RANDOM << 16 + $RANDOM) % $num_lines))
+ pass=$(sed "${line_num}q;d" "$wordlist" | grep -o "[a-z]" | tr -d "\n")-$pass
+ done
+ pass=${pass:0:-1}
+ else
+ read -r -n $length pass < <(LC_ALL=C tr -dc "$characters" < /dev/urandom)
+ [[ ${#pass} -eq $length ]] || die "Could not generate password from /dev/urandom."
+ fi
+
if [[ $inplace -eq 0 ]]; then
echo "$pass" | $GPG -e "${GPG_RECIPIENT_ARGS[@]}" -o "$passfile" "${GPG_OPTS[@]}" || die "Password encryption aborted."
else
--
2.19.1
Post by Cong Ma
---
man/pass.1            | 17 ++++++++++-------
src/password-store.sh | 16 +++++++++++-----
2 files changed, 21 insertions(+), 12 deletions(-)
This is my first time contributing to pass as a long-time user. In this
patch, I'm adding support for XKCD-style passwords [1] composed of words
from a wordlist. Since there is no standardised location for a
dictionary of words, the user has to specify a path to a file with the
--wordlist argument.
I don't know much bash/zsh/fish completions, so I'm afraid someone else
will have to help with that.
[1] https://xkcd.com/936/
Hello Adhityaa,
You might be interested in a diceware-style password generator based on
pass: https://github.com/congma/pass-genphrase
I wrote this a while ago and opted for the EFF long word list
(https://www.eff.org/deeplinks/2016/07/new-wordlists-random-passphrases)
as the source of words.
Cheers,
Cong.
_________________________________________________
Password-Store mailing list
https://lists.zx2c4.com/mailman/listinfo/password-store
Lenz Weber
2018-10-30 07:25:54 UTC
Permalink
Hi,

I want to bring up the question:

Is this something that pass needs? Or, more crass: should it offer this
feature or should it be considered harmful?

The point of pass, or any password manager, is not having to remember or
even know your password.

The default character set of pass has 31+26+26+10 = 93 characters, the
alphanumeric has at least 62.

Assuming a 6-word diceware password (approx. 30 characters) has 7776^6 ~
10^23 combinations, a password created with the default password set of
the same length has 10^59 combinations, or 10^53 for the alphanumeric
character set.

Assuming the use cases stated above (not having to ever remember your
password), using a diceware password just for a "nice looking" password
would sacrifice entropy somewhere between 10^30 and 10^36, bringing it
down to the complexity of a 12-character password with the default
character set.

I do not think this should be encouraged in any way.

Of course, there is nothing speaking against saving a diceware password
that has been generated elsewhere in pass - as a fallback, in case one
forgets it.

But this is an edge use case, not a core use case and the stance on edge
use cases has always been that there
* are other unix tools for it
* can always be a pass extension to offer it for those users that want
it in pass

What are other people's opinions on this?

Regards,
Lenz
Post by Adhityaa Chandrasekar
---
man/pass.1 | 17 ++++++++++-------
src/password-store.sh | 16 +++++++++++-----
2 files changed, 21 insertions(+), 12 deletions(-)
This is my first time contributing to pass as a long-time user. In this
patch, I'm adding support for XKCD-style passwords [1] composed of words
from a wordlist. Since there is no standardised location for a
dictionary of words, the user has to specify a path to a file with the
--wordlist argument.
I don't know much bash/zsh/fish completions, so I'm afraid someone else
will have to help with that.
[1] https://xkcd.com/936/
- Adhityaa
diff --git a/man/pass.1 b/man/pass.1
index 01a3fbe..72a83fc 100644
--- a/man/pass.1
+++ b/man/pass.1
@@ -122,15 +122,18 @@ ensure that temporary files are created in \fI/dev/shm\fP in order to avoid writ
difficult-to-erase disk sectors. If \fI/dev/shm\fP is not accessible, fallback to
the ordinary \fITMPDIR\fP location, and print a warning.
.TP
-\fBgenerate\fP [ \fI--no-symbols\fP, \fI-n\fP ] [ \fI--clip\fP, \fI-c\fP ] [ \fI--in-place\fP, \fI-i\fP | \fI--force\fP, \fI-f\fP ] \fIpass-name [pass-length]\fP
+\fBgenerate\fP [ \fI--no-symbols\fP, \fI-n\fP ] [ \fI--wordlist /path/to/wordlist\fP, \fI-w /path/to/wordlist\fP ][ \fI--clip\fP, \fI-c\fP ] [ \fI--in-place\fP, \fI-i\fP | \fI--force\fP, \fI-f\fP ] \fIpass-name [pass-length]\fP
Generate a new password using \fB/dev/urandom\fP of length \fIpass-length\fP
(or \fIPASSWORD_STORE_GENERATED_LENGTH\fP if unspecified) and insert into
-\fIpass-name\fP. If \fI--no-symbols\fP or \fI-n\fP is specified, do not use
-any non-alphanumeric characters in the generated password. The character sets used
-in generating passwords can be changed with the \fIPASSWORD_STORE_CHARACTER_SET\fP and
-\fIPASSWORD_STORE_CHARACTER_SET_NO_SYMBOLS\fP environment variables, described below.
-If \fI--clip\fP or \fI-c\fP is specified, do not print the password but instead copy
-it to the clipboard using
+\fIpass-name\fP. If \fI--no-symbols\fP or \fI-n\fP is specified, do not use any
+non-alphanumeric characters in the generated password. If \fI--wordlist\fP is
+specified, along with a file as argument containing a list of words to choose
+from, four words will be randomly chosen and used as password. The character
+sets used in generating passwords can be changed with the
+\fIPASSWORD_STORE_CHARACTER_SET\fP and
+\fIPASSWORD_STORE_CHARACTER_SET_NO_SYMBOLS\fP environment variables, described
+below. If \fI--clip\fP or \fI-c\fP is specified, do not print the password but
+instead copy it to the clipboard using
.BR xclip (1)
and then restore the clipboard after 45 (or \fIPASSWORD_STORE_CLIP_TIME\fP) seconds. If \fI--qrcode\fP
or \fI-q\fP is specified, do not print the password but instead display a QR code using
diff --git a/src/password-store.sh b/src/password-store.sh
index d89d455..2778c26 100755
--- a/src/password-store.sh
+++ b/src/password-store.sh
@@ -491,12 +491,13 @@ cmd_edit() {
}
cmd_generate() {
- local opts qrcode=0 clip=0 force=0 characters="$CHARACTER_SET" inplace=0 pass
+ local opts qrcode=0 clip=0 force=0 characters="$CHARACTER_SET" wordlist=0 inplace=0 pass
local err=$?
eval set -- "$opts"
while true; do case $1 in
-n|--no-symbols) characters="$CHARACTER_SET_NO_SYMBOLS"; shift ;;
+ -w|--wordlist) wordlist=$2; shift; shift ;;
-q|--qrcode) qrcode=1; shift ;;
-c|--clip) clip=1; shift ;;
-f|--force) force=1; shift ;;
@@ -504,7 +505,7 @@ cmd_generate() {
--) shift; break ;;
esac done
- [[ $err -ne 0 || ( $# -ne 2 && $# -ne 1 ) || ( $force -eq 1 && $inplace -eq 1 ) || ( $qrcode -eq 1 && $clip -eq 1 ) ]] && die "Usage: $PROGRAM $COMMAND [--no-symbols,-n] [--clip,-c] [--qrcode,-q] [--in-place,-i | --force,-f] pass-name [pass-length]"
+ [[ $err -ne 0 || ( $# -ne 2 && $# -ne 1 ) || ( $force -eq 1 && $inplace -eq 1 ) || ( $qrcode -eq 1 && $clip -eq 1 ) ]] && die "Usage: $PROGRAM $COMMAND [--no-symbols,-n] [--wordlist,-w /path/to/wordlist] [--clip,-c] [--qrcode,-q] [--in-place,-i | --force,-f] pass-name [pass-length]"
local path="$1"
local length="${2:-$GENERATED_LENGTH}"
check_sneaky_paths "$path"
@@ -517,8 +518,13 @@ cmd_generate() {
[[ $inplace -eq 0 && $force -eq 0 && -e $passfile ]] && yesno "An entry already exists for $path. Overwrite it?"
- read -r -n $length pass < <(LC_ALL=C tr -dc "$characters" < /dev/urandom)
- [[ ${#pass} -eq $length ]] || die "Could not generate password from /dev/urandom."
+ if [[ "$wordlist" != "" ]]; then
+ pass=$(shuf -n 4 "$wordlist" | paste -sd "-" -)
+ else
+ read -r -n $length pass < <(LC_ALL=C tr -dc "$characters" < /dev/urandom)
+ [[ ${#pass} -eq $length ]] || die "Could not generate password from /dev/urandom."
+ fi
+
if [[ $inplace -eq 0 ]]; then
else
Cong Ma
2018-10-30 08:04:02 UTC
Permalink
Post by Lenz Weber
Of course, there is nothing speaking against saving a diceware password
that has been generated elsewhere in pass - as a fallback, in case one
forgets it.
But this is an edge use case, not a core use case and the stance on edge
use cases has always been that there
* are other unix tools for it
* can always be a pass extension to offer it for those users that want
it in pass
What are other people's opinions on this?
In my opinion, there is indeed a mismatch between Diceware-style,
memorable passphrases and the typical usage case of `pass', as you've
commented on. That's why I would like to take the extension approach
instead of a modification to the core command `pass generate'.

Cheers,
Cong.
Matthieu Weber
2018-10-30 08:11:49 UTC
Permalink
Post by Lenz Weber
Is this something that pass needs? Or, more crass: should it offer this
feature or should it be considered harmful?
Not necessarily harmful, but useless within the context of a password
manager.
Post by Lenz Weber
The point of pass, or any password manager, is not having to remember or
even know your password.
So you can generate short, complicated passwords that still have enough
entropy. Those don't have to be short, but what's the benefit of
generating a long password?
Post by Lenz Weber
What are other people's opinions on this?
My (more or less informed) side opinion about the necessary entropy:
what matters is the average time it takes an attacker to guess the
password. This depends very much on how it is stored (especially the
hashing method). If you are sure that the hashing method is going to
slow down the attacker considerably, then the password's entropy can be
quite low, and the lower entropy of a diceware password is not a
problem. Of course, high entropy does not hurt if it comes at no extra
cost and you don't have to input the password manually.

Matthieu
--
(~._.~) Matthieu Weber - ***@free.fr (~._.~)
( ? ) http://weber.fi.eu.org/ ( ? )
()- -() public key id : 0x85CB340EFCD5E0B3 ()- -()
(_)-(_) "Humor ist, wenn man trotzdem lacht (Otto J. Bierbaum)" (_)-(_)
Tobias Girstmair
2018-10-30 08:26:11 UTC
Permalink
I think there is a place for rememberable passwords in a password
manager, for example credentials for logging into a graphical session
(where you can't (easily) use a password manager).

I do think that this is better made an extension than implemented into
pass itself though. This would allow greater freedom in choosing
dependencies and including wordlist(s).
Kjetil Torgrim Homme
2018-10-30 09:33:36 UTC
Permalink
Post by Lenz Weber
Is this something that pass needs? Or, more crass: should it offer this
feature or should it be considered harmful?
The point of pass, or any password manager, is not having to remember or
even know your password.
yes, but sometimes you need to enter this password by hand. I use horse
battery passwords when I might need to enter the password on a mobile
phone or on a console in a chilly data centre in the middle of the
night. both of these will often have problems with strange characters
or keyboard layouts (is "&" on Shift 6 or Shift 7? since there is often
no echo, there is no way to be sure!)

btw, here's the bash function I use to generate such pass phrases when
needed:

horse ()
{
local lang="${1-no}" words=${2-4};
aspell -d $lang dump master | grep --directories=skip --colour=auto
-v "['A-Z]" | tr -d \" | shuf -n $words | xargs echo;
}

(I remove words with capital letters to stick to common nouns.)

two examples:
"bensinkort stjerneforma sysselsettingsvirkningen selvforvaltningen"
"sikkerhetsmangelen nordstrandspillerens trommemaskiner tilleggsuttalelsene"

Norwegian words are quite long...

$ aspell -d no dump master | grep -v "['A-Z]" | wc
489533 489533 6966844

average length of 13 characters. this doesn't really help entropy,
though. 489533 distinct words give 18.9 bits of entropy each, so the
above pass phrases (of four words) have 75 bits, or 5.74e+22. still not
a huge amount, but the attacker would have to know that this is the
method I use to make pass phrases to successfully reduce his search space.

(I do add a little more entropy to my passphrases with techniques I will
not reveal here ;-)
--
Kjetil T. Homme
Redpill Linpro - Changing the game
Matthieu Weber
2018-10-30 11:10:55 UTC
Permalink
Post by Kjetil Torgrim Homme
Post by Lenz Weber
Is this something that pass needs? Or, more crass: should it offer this
feature or should it be considered harmful?
The point of pass, or any password manager, is not having to remember or
even know your password.
yes, but sometimes you need to enter this password by hand. I use horse
battery passwords when I might need to enter the password on a mobile
phone or on a console in a chilly data centre in the middle of the
night. both of these will often have problems with strange characters
or keyboard layouts (is "&" on Shift 6 or Shift 7? since there is often
no echo, there is no way to be sure!)
So you want passwords that are easy to type: generate passwords that are
made entirely of lowercase letters, all you need is 40% more characters
to have the same entropy as a password made of alphanumerics+symbols
i.e., 11 characters instead of 8. They will be easy enough to type even
on exotic keyboards, and can be generated using only tools that pass
uses already. All you need is to add to “pass generate” an option to
reduce $CHARACTER_SET to [:lower:].
Post by Kjetil Torgrim Homme
average length of 13 characters. this doesn't really help entropy,
though. 489533 distinct words give 18.9 bits of entropy each, so the
above pass phrases (of four words) have 75 bits, or 5.74e+22. still not
a huge amount, but the attacker would have to know that this is the
method I use to make pass phrases to successfully reduce his search space.
You can get 75 bits of entropy with 16 lowercase letters or 14
mixed-case letters. That is surely easier to type than your example.

Matthieu
--
(~._.~) Matthieu Weber - ***@free.fr (~._.~)
( ? ) http://weber.fi.eu.org/ ( ? )
()- -() public key id : 0x85CB340EFCD5E0B3 ()- -()
(_)-(_) "Humor ist, wenn man trotzdem lacht (Otto J. Bierbaum)" (_)-(_)
Kjetil Torgrim Homme
2018-10-30 19:01:11 UTC
Permalink
Post by Matthieu Weber
Post by Kjetil Torgrim Homme
yes, but sometimes you need to enter this password by hand. I use horse
battery passwords when I might need to enter the password on a mobile
phone or on a console in a chilly data centre in the middle of the
night. both of these will often have problems with strange characters
or keyboard layouts (is "&" on Shift 6 or Shift 7? since there is often
no echo, there is no way to be sure!)
So you want passwords that are easy to type: generate passwords that are
made entirely of lowercase letters, all you need is 40% more characters
to have the same entropy as a password made of alphanumerics+symbols
i.e., 11 characters instead of 8. They will be easy enough to type even
on exotic keyboards, and can be generated using only tools that pass
uses already. All you need is to add to “pass generate” an option to
reduce $CHARACTER_SET to [:lower:].
it is not easy to type wahseepienoofac on a mobile phone, IMHO. but
adding periods (not hyphens! the key moves around) will help - not for
entropy, but to make it easier to read and track how far I've gotten:

wah.see.pie.noo.fac

(I just realised I am lucky that I never have qwertz or azerty in my
environment... that would reduce the number of available letters to 21,
ertuiop/sdfghjkl/xcvbnm, by my count. digits, comma and period brings
the total to 33.)
Post by Matthieu Weber
Post by Kjetil Torgrim Homme
average length of 13 characters. this doesn't really help entropy,
though. 489533 distinct words give 18.9 bits of entropy each, so the
above pass phrases (of four words) have 75 bits, or 5.74e+22. still not
a huge amount, but the attacker would have to know that this is the
method I use to make pass phrases to successfully reduce his search space.
You can get 75 bits of entropy with 16 lowercase letters or 14
mixed-case letters. That is surely easier to type than your example.
it really depends on your keyboard and brain :-)
--
Kjetil T. Homme
Redpill Linpro - Changing the game
Matthieu Weber
2018-10-31 08:38:16 UTC
Permalink
Post by Kjetil Torgrim Homme
Post by Matthieu Weber
Post by Kjetil Torgrim Homme
yes, but sometimes you need to enter this password by hand. I use horse
battery passwords when I might need to enter the password on a mobile
phone or on a console in a chilly data centre in the middle of the
night. both of these will often have problems with strange characters
or keyboard layouts (is "&" on Shift 6 or Shift 7? since there is often
no echo, there is no way to be sure!)
So you want passwords that are easy to type: generate passwords that are
made entirely of lowercase letters, all you need is 40% more characters
to have the same entropy as a password made of alphanumerics+symbols
i.e., 11 characters instead of 8. They will be easy enough to type even
on exotic keyboards, and can be generated using only tools that pass
uses already. All you need is to add to “pass generate” an option to
reduce $CHARACTER_SET to [:lower:].
it is not easy to type wahseepienoofac on a mobile phone, IMHO. but
adding periods (not hyphens! the key moves around) will help - not for
wah.see.pie.noo.fac
What about whitespace instead of periods? The period may be located on
an awkward key on some keyboard layout, but (I hope) the spacebar is
universal.
Post by Kjetil Torgrim Homme
(I just realised I am lucky that I never have qwertz or azerty in my
environment... that would reduce the number of available letters to 21,
ertuiop/sdfghjkl/xcvbnm, by my count. digits, comma and period brings
the total to 33.)
If you consider that you cannot trust the letters printed on the
keyboard's keys to know how to type a given character, then you are
totally screwed if someone is using dvorak, colemak, bépo, neo, das
 you
won't be able to have a single usable character for your passphrases :(
Post by Kjetil Torgrim Homme
Post by Matthieu Weber
Post by Kjetil Torgrim Homme
average length of 13 characters. this doesn't really help entropy,
though. 489533 distinct words give 18.9 bits of entropy each, so the
above pass phrases (of four words) have 75 bits, or 5.74e+22. still not
a huge amount, but the attacker would have to know that this is the
method I use to make pass phrases to successfully reduce his search space.
You can get 75 bits of entropy with 16 lowercase letters or 14
mixed-case letters. That is surely easier to type than your example.
it really depends on your keyboard and brain :-)
True. But then again, if you trust the way the password is hashed on the
remote system, you can allow for a much shorter password, as the hashing
algorithm will slow down an attacker to the equivalent of a dozen bits
of entropy.

Matthieu
--
(~._.~) Matthieu Weber - ***@free.fr (~._.~)
( ? ) http://weber.fi.eu.org/ ( ? )
()- -() public key id : 0x85CB340EFCD5E0B3 ()- -()
(_)-(_) "Humor ist, wenn man trotzdem lacht (Otto J. Bierbaum)" (_)-(_)
Brad Knowles
2018-10-30 13:46:20 UTC
Permalink
Post by Kjetil Torgrim Homme
Norwegian words are quite long...
$ aspell -d no dump master | grep -v "['A-Z]" | wc
489533 489533 6966844
average length of 13 characters. this doesn't really help entropy,
though. 489533 distinct words give 18.9 bits of entropy each, so the
above pass phrases (of four words) have 75 bits, or 5.74e+22. still not
a huge amount, but the attacker would have to know that this is the
method I use to make pass phrases to successfully reduce his search space.
One key aspect of diceware/xkcd-style pass-strings is that the words that compose the string are themselves easy to remember and easy to distinguish from each other. That's why the dictionaries are relatively small -- 10,000 well-chosen words for your dictionary is much better than 489,000 words that comprise the entire dictionary but many of which are much lower quality words.

Going from 8k words to 16k words only increases your entropy per word by one bit (2^13 vs. 2^14), but it is likely to make many of the additional words harder to remember, harder to pronounce and type, and harder to distinguish.

For English-language words, this is why the EFF significantly improved the situation with their "long word list". It still satisfies all the goals of a diceware/xkcd-type wordlist, but the words are longer (and significantly longer on average), while still being easy to remember, easy to type and pronounce, and easy to distinguish.


You compensate for low entropy per word by making pass-strings that are much longer.

How much longer you make them is up to you, but if you want a pass string with 128 bits of entropy, then you could create a pass-string that is ten words long (128/13 ~= 9.84615384615384615384).

At which point, yeah -- you might want to store those in a password manager.


But you always -- always -- always ... assume that the attacker knows the mechanism(s) by which your passwords/passphrases/pass-strings are generated and will attack them in the most efficient manner possible.


I do support -- and use -- diceware/xkcd-style passwords for certain functions, but I don't know that I'd make it a core functionality of this program.
--
Brad Knowles <***@shub-internet.org>

Please forgive any typos. I'm fighting a failing keyboard on my laptop, in addition to having a broken finger.
Loading...