gen-password: various improvements for string and dictionary
strings password: - add shuffle - add European characters - fix hiragana support - add mandatory characters in generated password dictionary: - check for dictionary file in different directories
This commit is contained in:
@@ -27,7 +27,7 @@
|
|||||||
# mac
|
# mac
|
||||||
# A "xx-xx-xx-xx-xx-xx" type address, where 'x' are hexadecimal digits
|
# A "xx-xx-xx-xx-xx-xx" type address, where 'x' are hexadecimal digits
|
||||||
# (ranges 0-9 and a-h).
|
# (ranges 0-9 and a-h).
|
||||||
# Length is the number of "bytes" (groups od 2 hehexademal digits), and
|
# Length is the number of "bytes" (groups of 2 hexadecimal digits), and
|
||||||
# defaults to 6. The default ":" delimiter can be changed with "-s"
|
# defaults to 6. The default ":" delimiter can be changed with "-s"
|
||||||
# option.
|
# option.
|
||||||
# This is the default option.
|
# This is the default option.
|
||||||
@@ -51,8 +51,10 @@
|
|||||||
# if separator is set to null-string (--separator=0).
|
# if separator is set to null-string (--separator=0).
|
||||||
# Mac: use capital hexadecimal digits.
|
# Mac: use capital hexadecimal digits.
|
||||||
#
|
#
|
||||||
# -d, --dictionary=file
|
# -d, --dictionary=FILE
|
||||||
# Use file as wordlist file. Default is
|
# Use FILE as wordlist file. Default is eff_large_wordlist.txt.
|
||||||
|
# FILE will be searched in these directories : root, current directory,
|
||||||
|
# and /usr/local/share/br-tools/gen-password directory.
|
||||||
#
|
#
|
||||||
# -g, --gui
|
# -g, --gui
|
||||||
# Will use a GUI (yad based) to propose the password. This GUI
|
# Will use a GUI (yad based) to propose the password. This GUI
|
||||||
@@ -73,16 +75,20 @@
|
|||||||
# Print messages on what is being done.
|
# Print messages on what is being done.
|
||||||
#
|
#
|
||||||
# -x, --extended=RANGE
|
# -x, --extended=RANGE
|
||||||
# Specify the ranges of string type. Default is "a1", as lower case
|
# Specify the ranges of string type. Default is "a:1:a1", as lower case
|
||||||
# alphabetic characters (a-z) and digits (0-9). RANGE is a string
|
# alphabetic characters (a-z) and digits (0-9), with at least one letter
|
||||||
# composed of:
|
# and one digit. RANGE is a string composed of:
|
||||||
# are:
|
|
||||||
# a: lower case alphabetic characters (a-z)
|
# a: lower case alphabetic characters (a-z)
|
||||||
# A: upper case alphabetic characters (A-Z)
|
# A: upper case alphabetic characters (A-Z)
|
||||||
|
# e: extra European characters (e.g. À, É, é, Ï, ï, Ø, ø...)
|
||||||
# 1: digits (0-9)
|
# 1: digits (0-9)
|
||||||
# x: extended characters set 1: #$%&@^`~.,:;{[()]}
|
# x: extended characters set 1: #$%&@^`~.,:;{[()]}
|
||||||
# y: extended characters set 2: "'\/|_-<>*+!?=
|
# y: extended characters set 2: "'\/|_-<>*+!?=
|
||||||
# k: japanese katakana: TODO
|
# k: japanese hiragana: あいうえおかき...
|
||||||
|
# When a RANGED character is followed by ':' exactly one character of
|
||||||
|
# this range will appear in generated password: If we want two or more
|
||||||
|
# digits, the syntax would be '-x1:1:1'.
|
||||||
|
#
|
||||||
#
|
#
|
||||||
# EXAMPLES
|
# EXAMPLES
|
||||||
# TODO
|
# TODO
|
||||||
@@ -105,13 +111,18 @@ SCRIPT="$0" # full path to script
|
|||||||
CMDNAME=${0##*/} # script name
|
CMDNAME=${0##*/} # script name
|
||||||
SHELLVERSION=$(( BASH_VERSINFO[0] * 10 + BASH_VERSINFO[1] ))
|
SHELLVERSION=$(( BASH_VERSINFO[0] * 10 + BASH_VERSINFO[1] ))
|
||||||
|
|
||||||
|
export LC_CTYPE="C.UTF-8" # to handle non ascii chars
|
||||||
|
|
||||||
# character sets
|
# character sets
|
||||||
declare pw_a="abcdefghijklmnopqrstuvwxyz"
|
declare -A pw_charsets=(
|
||||||
declare pw_A="ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
[a]="abcdefghijklmnopqrstuvwxyz"
|
||||||
declare pw_1="0123456789"
|
[A]="ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||||
declare pw_x='#$%&@^`~.,:;{[()]}'\\
|
[1]="0123456789"
|
||||||
declare pw_y=\''"\/|_-<>*+!?='
|
[e]="âêîôûáéíóúàèìòùäëïöüãõñçøÂÊÎÔÛÁÉÍÓÚÀÈÌÒÙÄËÏÖÜÃÕÑÇØ¡¿"
|
||||||
declare pw_k="あいうえおかきくけこさしすせそたちつてとなにぬねのはひふへほまみむめもやゆよらりるれろわをん"
|
[x]='#$%&@^`~.,:;{[()]}'\\
|
||||||
|
[y]=\''"\/|_-<>*+!?='
|
||||||
|
[k]="あいうえおかきくけこさしすせそたちつてとなにぬねのはひふへほまみむめもやゆよらりるれろわをん"
|
||||||
|
)
|
||||||
|
|
||||||
# default type, length, separator
|
# default type, length, separator
|
||||||
declare pw_type="mac"
|
declare pw_type="mac"
|
||||||
@@ -122,12 +133,14 @@ declare pw_dict=""
|
|||||||
declare pw_copy=""
|
declare pw_copy=""
|
||||||
declare pw_gui=""
|
declare pw_gui=""
|
||||||
declare pw_verbose=""
|
declare pw_verbose=""
|
||||||
declare pw_charset="$pw_a$pw_A$pw_1"
|
declare pw_charset="a:A:1:aA1"
|
||||||
|
|
||||||
declare -A pw_commands=()
|
declare -A pw_commands=()
|
||||||
declare -a pw_command=()
|
declare -a pw_command=()
|
||||||
|
|
||||||
usage() {
|
usage() {
|
||||||
printf "usage: %s [-s CHAR][-d DICT][-x CHARSET][-Ccgmv] [TYPE] [LENGTH]\n" "$CMDNAME"
|
printf "usage: %s [-s CHAR][-d DICT][-x CHARSET][-Ccgmv] [TYPE] [LENGTH]\n" "$CMDNAME"
|
||||||
|
printf "Use '%s --man' for more help\n" "$CMDNAME"
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,6 +183,34 @@ log() {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# check_dict() - check for foctionary file
|
||||||
|
# $1: the dictionary filename (variable reference).
|
||||||
|
#
|
||||||
|
# @return: 0 on success, $1 will contain full path to dictionary.
|
||||||
|
# @return: 1 if not found
|
||||||
|
check_dict() {
|
||||||
|
local -n dict="$1"
|
||||||
|
local tmp_dir tmp_dict
|
||||||
|
|
||||||
|
if [[ -n "$dict" ]]; then
|
||||||
|
for tmp_dir in / ./ /usr/local/share/br-tools/gen-password/; do
|
||||||
|
tmp_dict="$tmp_dir$dict"
|
||||||
|
log -n "checking for %s dictionary... " "$tmp_dict"
|
||||||
|
if [[ -f "$tmp_dict" ]]; then
|
||||||
|
log "found."
|
||||||
|
dict="$tmp_dict"
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
log "not found."
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
printf "cannot find '%s' dictionary file\n" "$dict"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
# srandom() - use RANDOM to simulate SRANDOM
|
# srandom() - use RANDOM to simulate SRANDOM
|
||||||
# $1: Reference of variable to hold result
|
# $1: Reference of variable to hold result
|
||||||
#
|
#
|
||||||
@@ -201,6 +242,27 @@ rnd() {
|
|||||||
printf "%d" "$(( ret % mod ))"
|
printf "%d" "$(( ret % mod ))"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# shuffle() - shuffle a string
|
||||||
|
# $1: The string to shuffle
|
||||||
|
#
|
||||||
|
# The string is shuffled using the Fisher–Yates shuffle method :
|
||||||
|
# https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle
|
||||||
|
#
|
||||||
|
# @return: 0, output the shuffled string to stdout.
|
||||||
|
shuffle() {
|
||||||
|
local _str="$1"
|
||||||
|
local _res=""
|
||||||
|
local -i _i _len=${#_str} _cur=0
|
||||||
|
|
||||||
|
for (( _i = _len ; _i > 0; --_i )); do
|
||||||
|
_cur=$(rnd "$_i")
|
||||||
|
_res+=${_str:$_cur:1}
|
||||||
|
_str="${_str:0:_cur}${_str:_cur+1}"
|
||||||
|
done
|
||||||
|
printf "%s" "$_res"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
# rnd_hex() - get a random 2-digits hex number
|
# rnd_hex() - get a random 2-digits hex number
|
||||||
#
|
#
|
||||||
# @return: 0, output a string with the random integer on stdout.
|
# @return: 0, output a string with the random integer on stdout.
|
||||||
@@ -236,17 +298,19 @@ rnd_word() {
|
|||||||
|
|
||||||
# rnd_charset() - get a random string from a charset
|
# rnd_charset() - get a random string from a charset
|
||||||
# $1: A string with characters to choose from
|
# $1: A string with characters to choose from
|
||||||
# $2: An integer
|
# $2: An integer, the length of returned string
|
||||||
#
|
#
|
||||||
# @return: 0, output a random string from charset $1, with length $2.
|
# @return: 0, output a random string from charset $1, with length $2.
|
||||||
rnd_charset() {
|
rnd_charset() {
|
||||||
local charset="$1" ret=""
|
local charset="$1" ret=""
|
||||||
local -i len=$2 _i
|
local -i len=$2 _i
|
||||||
|
|
||||||
|
log "rnd_charset: %d from '%s'" "$len" "$charset"
|
||||||
for ((_i=0; _i<len; ++_i)); do
|
for ((_i=0; _i<len; ++_i)); do
|
||||||
ret+=${charset:$(rnd ${#charset}):1}
|
ret+=${charset:$(rnd ${#charset}):1}
|
||||||
done
|
done
|
||||||
|
|
||||||
|
log "rnd_charset: return '%s'" "$ret"
|
||||||
printf "%s" "$ret"
|
printf "%s" "$ret"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -345,24 +409,46 @@ pw_commands["passphrase"]=pwd_passphrase
|
|||||||
|
|
||||||
# pwd_string() - generate a string from a charset
|
# pwd_string() - generate a string from a charset
|
||||||
# $1: Integer, the string length
|
# $1: Integer, the string length
|
||||||
# $5: The charset
|
# $5: The charset definition (e.g. "a:1:")
|
||||||
#
|
#
|
||||||
# @return: 0, output a random string from $5 charset.
|
# @return: 0, output a random string from $5 charset.
|
||||||
pwd_string() {
|
pwd_string() {
|
||||||
local -i i n="$1" _rnd=0 _lcharset=0
|
local -i i n="$1"
|
||||||
local sep="" _charset="${5}" _char=""
|
local _charset="${5}" _allchars=""
|
||||||
local str="" _str="" _key="" _dummy=""
|
local str="" _c="" _char=""
|
||||||
|
|
||||||
_lcharset=${#_charset}
|
log "string setup: len=%d charset=[%s]" "$n" "$_charset"
|
||||||
log "string setup: len=%d charset[%d]=[%s]" "$n" "$_lcharset" "$_charset"
|
# finds out mandatory characters and build final charset
|
||||||
|
log -n "mandatory chars:"
|
||||||
|
for (( i = 0; i < ${#_charset}; ++i )); do
|
||||||
|
_c="${_charset:i:1}"
|
||||||
|
if [[ ${_charset:i+1:1} == ":" ]]; then
|
||||||
|
_char=$(rnd_charset "${pw_charsets[$_c]}" 1)
|
||||||
|
log -n " [%s]" "$_char"
|
||||||
|
str+="$_char"
|
||||||
|
(( i++ ))
|
||||||
|
else
|
||||||
|
_allchars+=${pw_charsets[$_c]}
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
log ""
|
||||||
|
if (( ${#str} < n && ${#_allchars} == 0 )); then
|
||||||
|
printf "Fatal: No charset to choose from ! Please check '-x' option."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
for ((i = 0; i < n; ++i)); do
|
log -n "generating %d remaining chars:" "$((n-${#str}))"
|
||||||
_rnd=$(rnd "$_lcharset")
|
for ((i = ${#str}; i < n; ++i)); do
|
||||||
_char=${_charset:$_rnd:1}
|
_char=$(rnd_charset "$_allchars" 1)
|
||||||
log "char pos=%d [%s]" "$_rnd" "$_char"
|
log -n " [%s]" "$_char"
|
||||||
str+="$_char"
|
str+="$_char"
|
||||||
done
|
done
|
||||||
printf "%s" "$str"
|
log ""
|
||||||
|
log "string before shuffle : %s" "$str"
|
||||||
|
str="$(shuffle "$str")"
|
||||||
|
# cut string if too long (may happen if too many mandatory chars)
|
||||||
|
(( ${#str} > n)) && log "truncating '%s' to '%s'" "$str" "${str:0:n}"
|
||||||
|
printf "%s" "${str:0:n}"
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
pw_commands["string"]=pwd_string
|
pw_commands["string"]=pwd_string
|
||||||
@@ -373,7 +459,7 @@ pw_commands["string"]=pwd_string
|
|||||||
# @return: 0
|
# @return: 0
|
||||||
print_command() {
|
print_command() {
|
||||||
local -n arr="$1"
|
local -n arr="$1"
|
||||||
local -a label=("function" "length" "sep" "cap" "dict")
|
local -a label=("function" "length" "sep" "cap" "dict" "charset")
|
||||||
local -i i
|
local -i i
|
||||||
for i in "${!arr[@]}"; do
|
for i in "${!arr[@]}"; do
|
||||||
log -s "%s=[%s]" "${label[$i]}" "${arr[$i]}"
|
log -s "%s=[%s]" "${label[$i]}" "${arr[$i]}"
|
||||||
@@ -396,10 +482,10 @@ gui_passwd() {
|
|||||||
--button=gtk-ok:252 --window-icon=dialog-password
|
--button=gtk-ok:252 --window-icon=dialog-password
|
||||||
res=$?
|
res=$?
|
||||||
log "res=%d\n" "$res"
|
log "res=%d\n" "$res"
|
||||||
if ((res == 0)); then
|
if (( res == 0 )); then
|
||||||
log "%s" "$passwd" | xsel -bi
|
printf "%s" "$passwd" | xsel -bi
|
||||||
fi
|
fi
|
||||||
((res == 1))
|
((res != 252))
|
||||||
do true; done
|
do true; done
|
||||||
return $res
|
return $res
|
||||||
}
|
}
|
||||||
@@ -409,7 +495,9 @@ parse_opts() {
|
|||||||
local sopts="cCd:ghms:vx:"
|
local sopts="cCd:ghms:vx:"
|
||||||
local lopts="copy,capitalize,dictionary:,gui,help,man,separator:,verbose,extended:"
|
local lopts="copy,capitalize,dictionary:,gui,help,man,separator:,verbose,extended:"
|
||||||
# set by options
|
# set by options
|
||||||
local tmp="" tmp_length="" tmp_sep="" tmp_cap="" tmp_dict="" tmp_chars=""
|
local tmp="" tmp_length="" tmp_sep="" tmp_cap="" tmp_dict="" tmp_dir=""
|
||||||
|
local tmp_charset=""
|
||||||
|
local c2="" c3=""
|
||||||
local -i i
|
local -i i
|
||||||
|
|
||||||
if ! tmp=$(getopt -o "$sopts" -l "$lopts" -n "$CMD" -- "$@"); then
|
if ! tmp=$(getopt -o "$sopts" -l "$lopts" -n "$CMD" -- "$@"); then
|
||||||
@@ -455,13 +543,17 @@ parse_opts() {
|
|||||||
;;
|
;;
|
||||||
'-x'|'--extended')
|
'-x'|'--extended')
|
||||||
for (( i = 0; i < ${#2}; ++i)); do
|
for (( i = 0; i < ${#2}; ++i)); do
|
||||||
case "${2:$i:1}" in
|
c2="${2:i:1}"
|
||||||
'a') tmp_chars+="$pw_a" ;;
|
case "$c2" in
|
||||||
'A') tmp_chars+="$pw_A" ;;
|
a|A|1|x|y|k|e)
|
||||||
'1') tmp_chars+="$pw_1" ;;
|
tmp_charset+="$c2"
|
||||||
'x') tmp_chars+="$pw_x" ;;
|
c3="${2:i+1:1}"
|
||||||
'y') tmp_chars+="$pw_y" ;;
|
if [[ "$c3" == ":" ]]; then
|
||||||
'k') tmp_chars+="$pw_k" ;;
|
tmp_charset+=":"
|
||||||
|
(( i++ ))
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
|
||||||
*) printf "unknown character set '%s\n" "${2:$i:1}"
|
*) printf "unknown character set '%s\n" "${2:$i:1}"
|
||||||
usage
|
usage
|
||||||
exit 1
|
exit 1
|
||||||
@@ -511,7 +603,9 @@ parse_opts() {
|
|||||||
string)
|
string)
|
||||||
pw_type="string"
|
pw_type="string"
|
||||||
tmp_length=10
|
tmp_length=10
|
||||||
[[ -n $tmp_chars ]] && pw_charset="$tmp_chars"
|
if [[ -n $tmp_charset ]]; then
|
||||||
|
pw_charset="$tmp_charset"
|
||||||
|
fi
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
printf "%s: Unknown '%s' password type.\n" "$CMDNAME" "$type"
|
printf "%s: Unknown '%s' password type.\n" "$CMDNAME" "$type"
|
||||||
@@ -539,6 +633,9 @@ parse_opts() {
|
|||||||
[[ $pw_sep = "0" ]] && pw_sep=""
|
[[ $pw_sep = "0" ]] && pw_sep=""
|
||||||
[[ -n $tmp_cap ]] && pw_cap=$tmp_cap
|
[[ -n $tmp_cap ]] && pw_cap=$tmp_cap
|
||||||
[[ -n $tmp_dict ]] && pw_dict=$tmp_dict
|
[[ -n $tmp_dict ]] && pw_dict=$tmp_dict
|
||||||
|
|
||||||
|
# look for dictionary file
|
||||||
|
check_dict pw_dict || exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
parse_opts "$@"
|
parse_opts "$@"
|
||||||
|
Reference in New Issue
Block a user