2021-02-24 06:18:01 -05:00
|
|
|
#! /bin/bash
|
|
|
|
|
|
|
|
set -e
|
2021-04-15 19:41:12 -04:00
|
|
|
set -o pipefail
|
|
|
|
|
|
|
|
shamir_secret_sharing=false
|
2021-02-24 06:18:01 -05:00
|
|
|
|
2021-04-15 12:53:41 -04:00
|
|
|
number_of_shares=5
|
|
|
|
share_threshold=3
|
|
|
|
|
2021-02-25 14:03:38 -05:00
|
|
|
positional=()
|
2021-05-03 07:40:09 -04:00
|
|
|
while [ $# -gt 0 ]; do
|
2021-02-25 14:03:38 -05:00
|
|
|
argument="$1"
|
|
|
|
case $argument in
|
2021-03-02 16:44:24 -05:00
|
|
|
-h|--help)
|
|
|
|
printf "%s\n" \
|
|
|
|
"Usage: qr-backup.sh [options]" \
|
|
|
|
"" \
|
|
|
|
"Options:" \
|
2021-11-05 09:09:00 -04:00
|
|
|
" --create-bip39-mnemonic create BIP39 mnemonic" \
|
|
|
|
" --validate-bip39-mnemonic validate if secret is valid BIP39 mnemonic" \
|
2022-01-10 08:16:25 -05:00
|
|
|
" --create-passphrase create passphrase" \
|
|
|
|
" --wordlist <wordlist> wordlist (defaults to large)" \
|
|
|
|
" --word-count <count> word count (defaults to 7)" \
|
2021-11-05 09:09:00 -04:00
|
|
|
" --shamir-secret-sharing split secret using Shamir Secret Sharing" \
|
|
|
|
" --number-of-shares <shares> number of shares (defaults to 5)" \
|
|
|
|
" --share-threshold <threshold> shares required to access secret (defaults to 3)" \
|
|
|
|
" --no-qr disable show SHA512 hash as QR code prompt" \
|
|
|
|
" --label <label> print label after short hash" \
|
|
|
|
" -h, --help display help for command"
|
2021-03-02 16:44:24 -05:00
|
|
|
exit 0
|
|
|
|
;;
|
2021-04-09 13:57:09 -04:00
|
|
|
--create-bip39-mnemonic)
|
|
|
|
create_bip39_mnemonic=true
|
2021-03-06 14:37:53 -05:00
|
|
|
shift
|
|
|
|
;;
|
2021-04-09 13:57:09 -04:00
|
|
|
--validate-bip39-mnemonic)
|
|
|
|
validate_bip39_mnemonic=true
|
|
|
|
shift
|
|
|
|
;;
|
2022-01-10 08:16:25 -05:00
|
|
|
--create-passphrase)
|
|
|
|
create_passphrase=true
|
|
|
|
shift
|
|
|
|
;;
|
|
|
|
--wordlist)
|
|
|
|
wordlist=$2
|
|
|
|
shift
|
|
|
|
shift
|
|
|
|
;;
|
|
|
|
--word-count)
|
|
|
|
word_count=$2
|
|
|
|
shift
|
|
|
|
shift
|
|
|
|
;;
|
2021-04-15 12:53:41 -04:00
|
|
|
--shamir-secret-sharing)
|
|
|
|
shamir_secret_sharing=true
|
|
|
|
shift
|
|
|
|
;;
|
|
|
|
--number-of-shares)
|
|
|
|
number_of_shares=$2
|
|
|
|
shift
|
|
|
|
shift
|
|
|
|
;;
|
|
|
|
--share-threshold)
|
|
|
|
share_threshold=$2
|
|
|
|
shift
|
|
|
|
shift
|
|
|
|
;;
|
|
|
|
--no-qr)
|
|
|
|
no_qr=true
|
|
|
|
shift
|
|
|
|
;;
|
2021-04-09 13:57:09 -04:00
|
|
|
--label)
|
|
|
|
label=$2
|
|
|
|
shift
|
2021-02-25 14:03:38 -05:00
|
|
|
shift
|
|
|
|
;;
|
|
|
|
*)
|
|
|
|
positional+=("$1")
|
|
|
|
shift
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
done
|
|
|
|
|
|
|
|
set -- "${positional[@]}"
|
|
|
|
|
2021-02-24 06:18:01 -05:00
|
|
|
bold=$(tput bold)
|
|
|
|
red=$(tput setaf 1)
|
|
|
|
normal=$(tput sgr0)
|
|
|
|
|
2021-02-25 14:03:38 -05:00
|
|
|
basedir=$(dirname "$0")
|
|
|
|
|
2021-02-24 06:18:01 -05:00
|
|
|
dev="/dev/sda1"
|
2021-03-03 15:10:07 -05:00
|
|
|
tmp="/tmp/pi"
|
|
|
|
usb="/tmp/usb"
|
2021-02-24 06:18:01 -05:00
|
|
|
|
2021-02-25 14:03:38 -05:00
|
|
|
tput reset
|
|
|
|
|
2021-04-15 12:53:41 -04:00
|
|
|
wait_for_usb_flash_drive () {
|
2021-02-24 06:18:01 -05:00
|
|
|
if [ ! -e $dev ]; then
|
2021-04-15 12:53:41 -04:00
|
|
|
printf "$bold%s$normal" "Insert USB flash drive and press enter"
|
2021-02-24 06:18:01 -05:00
|
|
|
read -r confirmation
|
2021-04-15 12:53:41 -04:00
|
|
|
wait_for_usb_flash_drive
|
2021-02-24 06:18:01 -05:00
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
2021-04-15 12:53:41 -04:00
|
|
|
wait_for_usb_flash_drive
|
2021-02-25 14:03:38 -05:00
|
|
|
|
2021-04-15 19:41:12 -04:00
|
|
|
printf "$bold%s$normal\n" "Format USB flash drive (y or n)?"
|
2021-02-25 14:03:38 -05:00
|
|
|
|
|
|
|
read -r answer
|
|
|
|
if [ "$answer" = "y" ]; then
|
2021-04-15 19:41:12 -04:00
|
|
|
if mount | grep $dev > /dev/null; then
|
2021-02-25 14:03:38 -05:00
|
|
|
sudo umount $dev
|
|
|
|
fi
|
|
|
|
sudo mkfs -t vfat $dev
|
|
|
|
fi
|
2021-02-24 06:18:01 -05:00
|
|
|
|
|
|
|
sudo mkdir -p $usb
|
2021-04-15 19:41:12 -04:00
|
|
|
|
|
|
|
if ! mount | grep $dev > /dev/null; then
|
|
|
|
sudo mount $dev $usb --options uid=pi,gid=pi
|
2021-02-24 06:18:01 -05:00
|
|
|
fi
|
|
|
|
|
2021-04-15 14:04:08 -04:00
|
|
|
if [ -z "$duplicate" ] && [ "$create_bip39_mnemonic" = true ]; then
|
2021-04-09 13:57:09 -04:00
|
|
|
printf "%s\n" "Creating BIP39 mnemonic…"
|
|
|
|
secret=$(python3 $basedir/create-bip39-mnemonic.py)
|
|
|
|
echo $secret
|
|
|
|
sleep 1
|
|
|
|
fi
|
|
|
|
|
2022-01-10 08:16:25 -05:00
|
|
|
if [ -z "$duplicate" ] && [ "$create_passphrase" = true ]; then
|
|
|
|
printf "%s\n" "Creating passphrase…"
|
|
|
|
wordlist_arg=""
|
|
|
|
if [ -n "$wordlist" ]; then
|
|
|
|
wordlist_arg=" --$wordlist"
|
|
|
|
fi
|
|
|
|
word_count_arg=""
|
|
|
|
if [ -n "$word_count" ]; then
|
|
|
|
word_count_arg=" $word_count"
|
|
|
|
fi
|
|
|
|
secret=$(passphraseme$wordlist_arg$word_count_arg)
|
2021-03-06 14:37:53 -05:00
|
|
|
echo $secret
|
|
|
|
sleep 1
|
|
|
|
fi
|
|
|
|
|
2021-04-15 14:04:08 -04:00
|
|
|
if [ -z "$duplicate" ] && [ -z "$secret" ]; then
|
2021-02-25 14:03:38 -05:00
|
|
|
tput sc
|
2021-04-15 19:41:12 -04:00
|
|
|
printf "$bold%s$normal\n" "Please type secret and press enter, then ctrl+d"
|
2021-04-15 12:53:41 -04:00
|
|
|
readarray -t secret_array
|
|
|
|
secret=$(printf "%s\n" "${secret_array[@]}")
|
2021-02-25 14:03:38 -05:00
|
|
|
tput rc
|
|
|
|
tput ed
|
2021-04-15 19:41:12 -04:00
|
|
|
printf "$bold%s$normal\n" "Please type secret and press enter, then ctrl+d (again)"
|
2021-04-15 12:53:41 -04:00
|
|
|
readarray -t secret_confirmation_array
|
|
|
|
secret_confirmation=$(printf "%s\n" "${secret_confirmation_array[@]}")
|
2021-02-25 14:03:38 -05:00
|
|
|
if [ ! "$secret" = "$secret_confirmation" ]; then
|
2021-04-15 19:41:12 -04:00
|
|
|
printf "$bold$red%s$normal\n" "Secrets do not match"
|
2021-02-25 14:03:38 -05:00
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
|
2021-04-15 14:04:08 -04:00
|
|
|
if [ -z "$duplicate" ] && [ "$validate_bip39_mnemonic" = true ]; then
|
2021-04-09 13:57:09 -04:00
|
|
|
printf "%s\n" "Validating if secret is valid BIP39 mnemonic…"
|
2021-04-15 12:53:41 -04:00
|
|
|
if ! echo -n "$secret" | python3 $basedir/validate-bip39-mnemonic.py; then
|
|
|
|
printf "$bold$red%s$normal\n" "Invalid BIP39 mnemonic"
|
2021-03-07 05:46:55 -05:00
|
|
|
exit 1
|
|
|
|
fi
|
2021-02-24 06:18:01 -05:00
|
|
|
fi
|
|
|
|
|
2021-04-15 19:41:12 -04:00
|
|
|
read_passphrase () {
|
|
|
|
local -n data=$1
|
|
|
|
|
|
|
|
printf "$bold%s$normal\n" "Please type passphrase and press enter"
|
|
|
|
read -rs data
|
|
|
|
printf "$bold%s$normal\n" "Please type passphrase and press enter (again)"
|
|
|
|
read -rs data_confirmation
|
|
|
|
if [ ! "$data" = "$data_confirmation" ]; then
|
2021-04-18 10:06:04 -04:00
|
|
|
printf "$bold$red%s$normal\n" "Passphrases do not match"
|
2021-04-15 19:41:12 -04:00
|
|
|
return 1
|
2021-04-15 14:04:08 -04:00
|
|
|
fi
|
2021-04-15 12:53:41 -04:00
|
|
|
|
2021-04-15 19:41:12 -04:00
|
|
|
printf "$bold%s$normal\n" "Show passphrase (y or n)?"
|
|
|
|
|
|
|
|
read -r answer
|
|
|
|
if [ "$answer" = "y" ]; then
|
|
|
|
printf "%s\n" $data
|
2021-06-10 22:15:15 -04:00
|
|
|
printf "$bold%s$normal\n" "Press enter to continue"
|
|
|
|
read -r answer
|
2021-04-15 12:53:41 -04:00
|
|
|
fi
|
2021-04-15 19:41:12 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
if [ "$shamir_secret_sharing" = true ]; then
|
|
|
|
read_passphrase passphrase
|
2021-02-24 06:18:01 -05:00
|
|
|
|
2021-04-15 12:53:41 -04:00
|
|
|
share_number=1
|
2021-04-15 19:41:12 -04:00
|
|
|
|
2021-04-15 12:53:41 -04:00
|
|
|
for share in $(echo -n "$secret" | secret-share-split -n $number_of_shares -t $share_threshold); do
|
2021-04-15 19:41:12 -04:00
|
|
|
printf "$bold%s$normal\n" "Encrypting secret share $share_number of $number_of_shares…"
|
|
|
|
|
|
|
|
encrypted_secret=$(echo -n "$share" | gpg --batch --passphrase-fd 3 --s2k-mode 3 --s2k-count 65011712 --s2k-digest-algo sha512 --cipher-algo AES256 --symmetric --armor 3<<<"$passphrase")
|
2021-02-24 06:18:01 -05:00
|
|
|
|
2021-04-15 12:53:41 -04:00
|
|
|
encrypted_secret_hash=$(echo -n "$encrypted_secret" | openssl dgst -sha512 | sed 's/^.* //')
|
|
|
|
encrypted_secret_short_hash=$(echo -n "$encrypted_secret_hash" | head -c 8)
|
2021-02-24 06:18:01 -05:00
|
|
|
|
2021-04-15 12:53:41 -04:00
|
|
|
printf "%s\n" "$encrypted_secret"
|
|
|
|
printf "%s: $bold%s$normal\n" "SHA512 hash" "$encrypted_secret_hash"
|
|
|
|
printf "%s: $bold%s$normal\n" "SHA512 short hash" "$encrypted_secret_short_hash"
|
2021-02-24 06:18:01 -05:00
|
|
|
|
2021-04-15 12:53:41 -04:00
|
|
|
echo -n "$encrypted_secret" | qr --error-correction L > "$tmp/secret.png"
|
2021-02-24 06:18:01 -05:00
|
|
|
|
2021-04-15 12:53:41 -04:00
|
|
|
font_size=$(echo "$(convert "$tmp/secret.png" -format "%h" info:) / 8" | bc)
|
|
|
|
text_offset=$(echo "$font_size * 1.5" | bc)
|
|
|
|
|
|
|
|
if [ -z "$label" ]; then
|
2021-04-15 19:41:12 -04:00
|
|
|
text="$encrypted_secret_short_hash"
|
2021-04-15 12:53:41 -04:00
|
|
|
else
|
2021-04-15 19:41:12 -04:00
|
|
|
text="$encrypted_secret_short_hash $label"
|
2021-04-15 12:53:41 -04:00
|
|
|
fi
|
|
|
|
|
|
|
|
convert "$tmp/secret.png" -gravity center -scale 200% -extent 125% -scale 125% -gravity south -font /usr/share/fonts/truetype/noto/NotoMono-Regular.ttf -pointsize $font_size -fill black -draw "text 0,$text_offset '$text'" "$usb/$encrypted_secret_short_hash.jpg"
|
|
|
|
|
|
|
|
if [ -z "$no_qr" ]; then
|
2021-04-15 19:41:12 -04:00
|
|
|
printf "$bold%s$normal\n" "Show SHA512 hash as QR code (y or n)?"
|
2021-04-15 12:53:41 -04:00
|
|
|
|
|
|
|
read -r answer
|
|
|
|
if [ "$answer" = "y" ]; then
|
|
|
|
printf "$bold%s$normal\n" "Press q to quit"
|
|
|
|
sleep 1
|
|
|
|
echo -n "$encrypted_secret_hash" | qr --error-correction L > "$tmp/secret-hash.png"
|
|
|
|
sudo fim --autozoom --quiet --vt 1 "$tmp/secret-hash.png"
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
|
|
|
|
share_number=$((share_number+1))
|
|
|
|
done
|
2021-04-09 13:57:09 -04:00
|
|
|
else
|
2021-04-15 19:41:12 -04:00
|
|
|
if [ "$duplicate" = true ] && [ -n "$encrypted_secret" ]; then
|
|
|
|
printf "%s\n" "Duplicating encrypted secret…"
|
|
|
|
else
|
|
|
|
read_passphrase passphrase
|
|
|
|
|
|
|
|
printf "$bold%s$normal\n" "Encrypting secret…"
|
|
|
|
|
|
|
|
encrypted_secret=$(echo -n "$secret" | gpg --batch --passphrase-fd 3 --s2k-mode 3 --s2k-count 65011712 --s2k-digest-algo sha512 --cipher-algo AES256 --symmetric --armor 3<<<"$passphrase")
|
|
|
|
fi
|
|
|
|
|
2021-04-15 12:53:41 -04:00
|
|
|
encrypted_secret_hash=$(echo -n "$encrypted_secret" | openssl dgst -sha512 | sed 's/^.* //')
|
|
|
|
encrypted_secret_short_hash=$(echo -n "$encrypted_secret_hash" | head -c 8)
|
2021-04-09 13:57:09 -04:00
|
|
|
|
2021-04-15 12:53:41 -04:00
|
|
|
printf "%s\n" "$encrypted_secret"
|
|
|
|
printf "%s: $bold%s$normal\n" "SHA512 hash" "$encrypted_secret_hash"
|
|
|
|
printf "%s: $bold%s$normal\n" "SHA512 short hash" "$encrypted_secret_short_hash"
|
2021-02-24 06:18:01 -05:00
|
|
|
|
2021-04-15 12:53:41 -04:00
|
|
|
echo -n "$encrypted_secret" | qr --error-correction L > "$tmp/secret.png"
|
2021-02-24 06:18:01 -05:00
|
|
|
|
2021-04-15 12:53:41 -04:00
|
|
|
font_size=$(echo "$(convert "$tmp/secret.png" -format "%h" info:) / 8" | bc)
|
|
|
|
text_offset=$(echo "$font_size * 1.5" | bc)
|
|
|
|
|
|
|
|
if [ -z "$label" ]; then
|
|
|
|
text="$encrypted_secret_short_hash"
|
|
|
|
else
|
|
|
|
text="$encrypted_secret_short_hash $label"
|
|
|
|
fi
|
|
|
|
|
|
|
|
convert "$tmp/secret.png" -gravity center -scale 200% -extent 125% -scale 125% -gravity south -font /usr/share/fonts/truetype/noto/NotoMono-Regular.ttf -pointsize $font_size -fill black -draw "text 0,$text_offset '$text'" "$usb/$encrypted_secret_short_hash.jpg"
|
|
|
|
|
|
|
|
if [ -z "$no_qr" ]; then
|
2021-04-15 19:41:12 -04:00
|
|
|
printf "$bold%s$normal\n" "Show SHA512 hash as QR code (y or n)?"
|
2021-04-15 12:53:41 -04:00
|
|
|
|
|
|
|
read -r answer
|
|
|
|
if [ "$answer" = "y" ]; then
|
|
|
|
printf "$bold%s$normal\n" "Press q to quit"
|
|
|
|
sleep 1
|
|
|
|
echo -n "$encrypted_secret_hash" | qr --error-correction L > "$tmp/secret-hash.png"
|
|
|
|
sudo fim --autozoom --quiet --vt 1 "$tmp/secret-hash.png"
|
|
|
|
fi
|
|
|
|
fi
|
2021-02-24 06:18:01 -05:00
|
|
|
fi
|
|
|
|
|
2021-04-15 19:41:12 -04:00
|
|
|
sudo umount $dev
|
2021-02-24 06:18:01 -05:00
|
|
|
|
|
|
|
printf "%s\n" "Done"
|