[PATCH] Add support for XKCD-style wordlist passwords

Adhityaa Chandrasekar pass at adtac.in
Tue Oct 30 06:44:22 CET 2018


>From 7732f29809e72aae54dca5f598a3f00e84b6b0e2 Mon Sep 17 00:00:00 2001
From: Adhityaa Chandrasekar <adtac at 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



On Tue, 30 Oct 2018, at 1:13 AM, Cong Ma wrote:
> On 30/10/2018 13:00, Adhityaa Chandrasekar wrote:
>> ---
>> 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
> Password-Store at lists.zx2c4.com
> https://lists.zx2c4.com/mailman/listinfo/password-store


More information about the Password-Store mailing list