diff --git a/how-to-create-encrypted-paper-backup/README.md b/how-to-create-encrypted-paper-backup/README.md index ea85e38..33d54c1 100644 --- a/how-to-create-encrypted-paper-backup/README.md +++ b/how-to-create-encrypted-paper-backup/README.md @@ -85,7 +85,7 @@ Select “Localisation Options”, then “Keyboard”, then “Generic 105-key ```console $ sudo apt update -$ sudo apt install -y fim imagemagick +$ sudo apt install -y expect fim imagemagick $ pip3 install mnemonic pillow qrcode --user diff --git a/how-to-create-encrypted-paper-backup/test.sh b/how-to-create-encrypted-paper-backup/test.sh new file mode 100755 index 0000000..b61f1de --- /dev/null +++ b/how-to-create-encrypted-paper-backup/test.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +set -e +set -o pipefail + +bold=$(tput bold) +normal=$(tput sgr0) + +printf "$bold%s$normal\n" "Please type root password and press enter" +read -rs password + +export password=$password + +printf "%s\n" "Running unit tests…" + +expect ./tests/bip39.exp +expect ./tests/electrum.exp +expect ./tests/default.exp +expect ./tests/shamir.exp +expect ./tests/shamir2of3.exp diff --git a/how-to-create-encrypted-paper-backup/tests/bip39.exp b/how-to-create-encrypted-paper-backup/tests/bip39.exp new file mode 100644 index 0000000..df7c5ef --- /dev/null +++ b/how-to-create-encrypted-paper-backup/tests/bip39.exp @@ -0,0 +1,190 @@ +#!/usr/bin/expect + +# exp_internal 1 +# log_file -noappend ~/expect.log + +set timeout 30 + +proc bold {} { + return [exec tput bold] +} +proc red {} { + return [exec tput setaf 1] +} +proc green {} { + return [exec tput setaf 2] +} +proc normal {} { + return [exec tput sgr0] +} + +set bip39_mnemonic "online pipe enough dutch decorate want moment scheme rigid enlist blast boat purse sick chalk shop brush all return betray jacket salon abandon retire" +set electrum_mnemonic "month pet slice know amused leave now vague palm guess cattle element cross truly auto put among craft repeat van sample nephew sad family" +set failed "[bold][red]Failed[normal]" +set ok "[bold][green]OK[normal]" + +puts "[bold]Should create BIP39 mnemonic[normal]" + +spawn qr-backup.sh --create-bip39-mnemonic + +expect { + default { + puts $failed + exit 1 + } + -re {Format USB flash drive \(y or n\)\?} { + send "n\r" + } +} + +expect { + default { + puts $failed + exit 1 + } + -re {\[sudo\] password for pi:} { + send "$env(password)\r" + } +} + +expect { + default { + puts $failed + exit 1 + } + -re {Creating BIP39 mnemonic…} +} + +expect { + default { + puts $failed + exit 1 + } + -re {(([a-z]+ ?){24})} { + exit 0 + } +} + +puts "[bold]Should validate valid BIP39 mnemonic[normal]" + +spawn qr-backup.sh --validate-bip39-mnemonic + +expect { + default { + puts $failed + exit 1 + } + -re {Format USB flash drive \(y or n\)\?} { + send "n\r" + } +} + +expect { + default { + puts $failed + exit 1 + } + -re {\[sudo\] password for pi:} { + send "$env(password)\r" + } +} + +expect { + default { + puts $failed + exit 1 + } + -re {Please type secret and press enter, then ctrl\+d} { + sleep 0.1 + send "$bip39_mnemonic\r" + sleep 0.1 + send "\x04" + } +} + +expect { + default { + puts $failed + exit 1 + } + -re {Please type bip39_mnemonic and press enter, then ctrl\+d \(again\)} { + sleep 0.1 + send "$secret\r" + sleep 0.1 + send "\x04" + } +} + +expect { + default { + puts $failed + exit 1 + } + -re {Please type passphrase and press enter} { + puts $ok + exit 0 + } +} + +puts "[bold]Should fail to validate invalid BIP39 mnemonic[normal]" + +spawn qr-backup.sh --validate-bip39-mnemonic + +expect { + default { + puts $failed + exit 1 + } + -re {Format USB flash drive \(y or n\)\?} { + send "n\r" + } +} + +expect { + default { + puts $failed + exit 1 + } + -re {\[sudo\] password for pi:} { + send "$env(password)\r" + } +} + +expect { + default { + puts $failed + exit 1 + } + -re {Please type secret and press enter, then ctrl\+d} { + sleep 0.1 + send "$electrum_mnemonic\r" + sleep 0.1 + send "\x04" + } +} + +expect { + default { + puts $failed + exit 1 + } + -re {Please type electrum_mnemonic and press enter, then ctrl\+d \(again\)} { + sleep 0.1 + send "$secret\r" + sleep 0.1 + send "\x04" + } +} + +expect { + default { + puts $failed + exit 1 + } + -re {Invalid BIP39 mnemonic} { + puts $ok + exit 0 + } +} + +interact diff --git a/how-to-create-encrypted-paper-backup/tests/default.exp b/how-to-create-encrypted-paper-backup/tests/default.exp new file mode 100644 index 0000000..2a8fc81 --- /dev/null +++ b/how-to-create-encrypted-paper-backup/tests/default.exp @@ -0,0 +1,214 @@ +#!/usr/bin/expect + +# exp_internal 1 +# log_file -noappend ~/expect.log + +set timeout 30 + +proc bold {} { + return [exec tput bold] +} +proc red {} { + return [exec tput setaf 1] +} +proc green {} { + return [exec tput setaf 2] +} +proc normal {} { + return [exec tput sgr0] +} + +set secret "foo\nbar" +set passphrase "asdasd" +set failed "[bold][red]Failed[normal]" +set ok "[bold][green]OK[normal]" + +puts "[bold]Should backup secret[normal]" + +spawn qr-backup.sh + +expect { + default { + puts $failed + exit 1 + } + -re {Format USB flash drive \(y or n\)\?} { + sleep 0.1 + send "y\r" + } +} + +expect { + default { + puts $failed + exit 1 + } + -re {\[sudo\] password for pi:} { + sleep 0.1 + send "$env(password)\r" + } +} + +expect { + default { + puts $failed + exit 1 + } + -re {mkfs\.fat 4\.1 \(2017-01-24\)} +} + +expect { + default { + puts $failed + exit 1 + } + -re {Please type secret and press enter, then ctrl\+d} { + sleep 0.1 + send "$secret\r" + sleep 0.1 + send "\x04" + } +} + +expect { + default { + puts $failed + exit 1 + } + -re {Please type secret and press enter, then ctrl\+d \(again\)} { + sleep 0.1 + send "$secret\r" + sleep 0.1 + send "\x04" + } +} + +expect { + default { + puts $failed + exit 1 + } + -re {Please type passphrase and press enter} { + sleep 0.1 + send "$passphrase\r" + } +} + +expect { + default { + puts $failed + exit 1 + } + -re {Please type passphrase and press enter \(again\)} { + sleep 0.1 + send "$passphrase\r" + } +} + +expect { + default { + puts $failed + exit 1 + } + -re {Show passphrase \(y or n\)\?} { + sleep 0.1 + send "y\r" + } +} + +expect { + default { + puts $failed + exit 1 + } + $passphrase +} + +expect { + default { + puts $failed + exit 1 + } + -re {SHA512 short hash: .+?([a-f0-9]{8})} { + set short_hash $expect_out(1,string) + } +} + +expect { + default { + puts $failed + exit 1 + } + -re {Show SHA512 hash as QR code \(y or n\)\?} { + sleep 0.1 + send "n\r" + } +} + +expect { + default { + puts $failed + exit 1 + } + -re {Done} +} + +puts "[bold]Should restore secret[normal]" + +spawn qr-restore.sh --images $short_hash.jpg + +expect { + default { + puts $failed + exit 1 + } + -re {\[sudo\] password for pi:} { + sleep 0.1 + send "$env(password)\r" + } +} + +expect { + default { + puts $failed + exit 1 + } + -re {Please type passphrase and press enter} { + sleep 0.1 + send "$passphrase\r" + } +} + +expect { + default { + puts $failed + exit 1 + } + -re {Show secret \(y or n\)\?} { + sleep 0.1 + send "y\r" + } +} + +expect { + default { + puts $failed + exit 1 + } + -re {Secret:\r\n((.|\r\n)+?)\r\nDone} { + set restored_secret $expect_out(1,string) + } +} + +regsub -all {(\e\(B)?\e\[[0-9]*?m} $restored_secret {} restored_secret +regsub -all {\r} $restored_secret {} restored_secret + +if { "$restored_secret" != "$secret" } { + puts $failed + exit 1 +} else { + puts $ok + exit 0 +} + +interact diff --git a/how-to-create-encrypted-paper-backup/tests/electrum.exp b/how-to-create-encrypted-paper-backup/tests/electrum.exp new file mode 100644 index 0000000..c104da5 --- /dev/null +++ b/how-to-create-encrypted-paper-backup/tests/electrum.exp @@ -0,0 +1,68 @@ +#!/usr/bin/expect + +# exp_internal 1 +# log_file -noappend ~/expect.log + +set timeout 30 + +proc bold {} { + return [exec tput bold] +} +proc red {} { + return [exec tput setaf 1] +} +proc green {} { + return [exec tput setaf 2] +} +proc normal {} { + return [exec tput sgr0] +} + +set passphrase "asdasd" +set failed "[bold][red]Failed[normal]" +set ok "[bold][green]OK[normal]" + +puts "[bold]Should create Electrum mnemonic[normal]" + +spawn qr-backup.sh --create-electrum-mnemonic + +expect { + default { + puts $failed + exit 1 + } + -re {Format USB flash drive \(y or n\)\?} { + send "n\r" + } +} + +expect { + default { + puts $failed + exit 1 + } + -re {\[sudo\] password for pi:} { + send "$env(password)\r" + } +} + +expect { + default { + puts $failed + exit 1 + } + -re {Creating Electrum mnemonic…} +} + +expect { + default { + puts $failed + exit 1 + } + -re {(([a-z]+ ?){24})} { + puts $ok + exit 0 + } +} + +interact diff --git a/how-to-create-encrypted-paper-backup/tests/shamir.exp b/how-to-create-encrypted-paper-backup/tests/shamir.exp new file mode 100644 index 0000000..ae2105b --- /dev/null +++ b/how-to-create-encrypted-paper-backup/tests/shamir.exp @@ -0,0 +1,338 @@ +#!/usr/bin/expect + +# exp_internal 1 +# log_file -noappend ~/expect.log + +set timeout 30 + +proc bold {} { + return [exec tput bold] +} +proc red {} { + return [exec tput setaf 1] +} +proc green {} { + return [exec tput setaf 2] +} +proc normal {} { + return [exec tput sgr0] +} + +set passphrase "asdasd" +set secret "foo\nbar" +set failed "[bold][red]Failed[normal]" +set ok "[bold][green]OK[normal]" + +puts "[bold]Should backup secret using Shamir Secret Sharing[normal]" + +spawn qr-backup.sh --shamir-secret-sharing + +expect { + default { + puts $failed + exit 1 + } + -re {Format USB flash drive \(y or n\)\?} { + sleep 0.1 + send "y\r" + } +} + +expect { + default { + puts $failed + exit 1 + } + -re {\[sudo\] password for pi:} { + sleep 0.1 + send "$env(password)\r" + } +} + +expect { + default { + puts $failed + exit 1 + } + -re {mkfs\.fat 4\.1 \(2017-01-24\)} +} + +expect { + default { + puts $failed + exit 1 + } + -re {Please type secret and press enter, then ctrl\+d} { + sleep 0.1 + send "$secret\r" + sleep 0.1 + send "\x04" + } +} + +expect { + default { + puts $failed + exit 1 + } + -re {Please type secret and press enter, then ctrl\+d \(again\)} { + sleep 0.1 + send "$secret\r" + sleep 0.1 + send "\x04" + } +} + +expect { + default { + puts $failed + exit 1 + } + -re {Please type passphrase and press enter} { + sleep 0.1 + send "$passphrase\r" + } +} + +expect { + default { + puts $failed + exit 1 + } + -re {Please type passphrase and press enter \(again\)} { + sleep 0.1 + send "$passphrase\r" + } +} + +expect { + default { + puts $failed + exit 1 + } + -re {Show passphrase \(y or n\)\?} { + sleep 0.1 + send "y\r" + } +} + +expect { + default { + puts $failed + exit 1 + } + $passphrase +} + +expect { + default { + puts $failed + exit 1 + } + {Encrypting secret share 1 of 5…} +} + +expect { + default { + puts $failed + exit 1 + } + -re {SHA512 short hash: .+?([a-f0-9]{8})} { + set short_hash_1 $expect_out(1,string) + } +} + +expect { + default { + puts $failed + exit 1 + } + -re {Show SHA512 hash as QR code \(y or n\)\?} { + sleep 0.1 + send "n\r" + } +} + +expect { + default { + puts $failed + exit 1 + } + {Encrypting secret share 2 of 5…} +} + +expect { + default { + puts $failed + exit 1 + } + -re {SHA512 short hash: .+?([a-f0-9]{8})} { + set short_hash_2 $expect_out(1,string) + } +} + +expect { + default { + puts $failed + exit 1 + } + -re {Show SHA512 hash as QR code \(y or n\)\?} { + sleep 0.1 + send "n\r" + } +} + +expect { + default { + puts $failed + exit 1 + } + {Encrypting secret share 3 of 5…} +} + +expect { + default { + puts $failed + exit 1 + } + -re {SHA512 short hash: .+?([a-f0-9]{8})} { + set short_hash_3 $expect_out(1,string) + } +} + +expect { + default { + puts $failed + exit 1 + } + -re {Show SHA512 hash as QR code \(y or n\)\?} { + sleep 0.1 + send "n\r" + } +} + +expect { + default { + puts $failed + exit 1 + } + {Encrypting secret share 4 of 5…} +} + +expect { + default { + puts $failed + exit 1 + } + -re {SHA512 short hash: .+?([a-f0-9]{8})} { + set short_hash_4 $expect_out(1,string) + } +} + +expect { + default { + puts $failed + exit 1 + } + -re {Show SHA512 hash as QR code \(y or n\)\?} { + sleep 0.1 + send "n\r" + } +} + +expect { + default { + puts $failed + exit 1 + } + {Encrypting secret share 5 of 5…} +} + +expect { + default { + puts $failed + exit 1 + } + -re {SHA512 short hash: .+?([a-f0-9]{8})} { + set short_hash_5 $expect_out(1,string) + } +} + +expect { + default { + puts $failed + exit 1 + } + -re {Show SHA512 hash as QR code \(y or n\)\?} { + sleep 0.1 + send "n\r" + } +} + +expect { + default { + puts $failed + exit 1 + } + -re {Done} +} + +puts "[bold]Should restore secret using Shamir Secret Sharing[normal]" + +spawn qr-restore.sh --images "$short_hash_1.jpg,$short_hash_2.jpg,$short_hash_5.jpg" --shamir-secret-sharing + +expect { + default { + puts $failed + exit 1 + } + -re {\[sudo\] password for pi:} { + sleep 0.1 + send "$env(password)\r" + } +} + +expect { + default { + puts $failed + exit 1 + } + -re {Please type passphrase and press enter} { + sleep 0.1 + send "$passphrase\r" + } +} + +expect { + default { + puts $failed + exit 1 + } + -re {Show secret \(y or n\)\?} { + sleep 0.1 + send "y\r" + } +} + +expect { + default { + puts $failed + exit 1 + } + -re {Secret:\r\n((.|\r\n)+?)\r\nDone} { + set restored_secret $expect_out(1,string) + } +} + +regsub -all {(\e\(B)?\e\[[0-9]*?m} $restored_secret {} restored_secret +regsub -all {\r} $restored_secret {} restored_secret + +if { "$restored_secret" != "$secret" } { + puts $failed + exit 1 +} else { + puts $ok + exit 0 +} + +interact diff --git a/how-to-create-encrypted-paper-backup/tests/shamir2of3.exp b/how-to-create-encrypted-paper-backup/tests/shamir2of3.exp new file mode 100644 index 0000000..73d9409 --- /dev/null +++ b/how-to-create-encrypted-paper-backup/tests/shamir2of3.exp @@ -0,0 +1,280 @@ +#!/usr/bin/expect + +# exp_internal 1 +# log_file -noappend ~/expect.log + +set timeout 30 + +proc bold {} { + return [exec tput bold] +} +proc red {} { + return [exec tput setaf 1] +} +proc green {} { + return [exec tput setaf 2] +} +proc normal {} { + return [exec tput sgr0] +} + +set passphrase "asdasd" +set secret "foo\nbar" +set failed "[bold][red]Failed[normal]" +set ok "[bold][green]OK[normal]" + +puts "[bold]Should backup secret using 2 of 3 Shamir Secret Sharing[normal]" + +spawn qr-backup.sh --shamir-secret-sharing --number-of-shares 3 --share-threshold 2 + +expect { + default { + puts $failed + exit 1 + } + -re {Format USB flash drive \(y or n\)\?} { + sleep 0.1 + send "y\r" + } +} + +expect { + default { + puts $failed + exit 1 + } + -re {\[sudo\] password for pi:} { + sleep 0.1 + send "$env(password)\r" + } +} + +expect { + default { + puts $failed + exit 1 + } + -re {mkfs\.fat 4\.1 \(2017-01-24\)} +} + +expect { + default { + puts $failed + exit 1 + } + -re {Please type secret and press enter, then ctrl\+d} { + sleep 0.1 + send "$secret\r" + sleep 0.1 + send "\x04" + } +} + +expect { + default { + puts $failed + exit 1 + } + -re {Please type secret and press enter, then ctrl\+d \(again\)} { + sleep 0.1 + send "$secret\r" + sleep 0.1 + send "\x04" + } +} + +expect { + default { + puts $failed + exit 1 + } + -re {Please type passphrase and press enter} { + sleep 0.1 + send "$passphrase\r" + } +} + +expect { + default { + puts $failed + exit 1 + } + -re {Please type passphrase and press enter \(again\)} { + sleep 0.1 + send "$passphrase\r" + } +} + +expect { + default { + puts $failed + exit 1 + } + -re {Show passphrase \(y or n\)\?} { + sleep 0.1 + send "y\r" + } +} + +expect { + default { + puts $failed + exit 1 + } + $passphrase +} + +expect { + default { + puts $failed + exit 1 + } + {Encrypting secret share 1 of 3…} +} + +expect { + default { + puts $failed + exit 1 + } + -re {SHA512 short hash: .+?([a-f0-9]{8})} { + set short_hash_1 $expect_out(1,string) + } +} + +expect { + default { + puts $failed + exit 1 + } + -re {Show SHA512 hash as QR code \(y or n\)\?} { + sleep 0.1 + send "n\r" + } +} + +expect { + default { + puts $failed + exit 1 + } + {Encrypting secret share 2 of 3…} +} + +expect { + default { + puts $failed + exit 1 + } + -re {SHA512 short hash: .+?([a-f0-9]{8})} { + set short_hash_2 $expect_out(1,string) + } +} + +expect { + default { + puts $failed + exit 1 + } + -re {Show SHA512 hash as QR code \(y or n\)\?} { + sleep 0.1 + send "n\r" + } +} + +expect { + default { + puts $failed + exit 1 + } + {Encrypting secret share 3 of 3…} +} + +expect { + default { + puts $failed + exit 1 + } + -re {SHA512 short hash: .+?([a-f0-9]{8})} { + set short_hash_3 $expect_out(1,string) + } +} + +expect { + default { + puts $failed + exit 1 + } + -re {Show SHA512 hash as QR code \(y or n\)\?} { + sleep 0.1 + send "n\r" + } +} + +expect { + default { + puts $failed + exit 1 + } + -re {Done} +} + +puts "[bold]Should restore secret using 2 of 3 Shamir Secret Sharing[normal]" + +spawn qr-restore.sh --images "$short_hash_1.jpg,$short_hash_2.jpg" --shamir-secret-sharing --share-threshold 2 + +expect { + default { + puts $failed + exit 1 + } + -re {\[sudo\] password for pi:} { + sleep 0.1 + send "$env(password)\r" + } +} + +expect { + default { + puts $failed + exit 1 + } + -re {Please type passphrase and press enter} { + sleep 0.1 + send "$passphrase\r" + } +} + +expect { + default { + puts $failed + exit 1 + } + -re {Show secret \(y or n\)\?} { + sleep 0.1 + send "y\r" + } +} + +expect { + default { + puts $failed + exit 1 + } + -re {Secret:\r\n((.|\r\n)+?)\r\nDone} { + set restored_secret $expect_out(1,string) + } +} + +regsub -all {(\e\(B)?\e\[[0-9]*?m} $restored_secret {} restored_secret +regsub -all {\r} $restored_secret {} restored_secret + +if { "$restored_secret" != "$secret" } { + puts $failed + exit 1 +} else { + puts $ok + exit 0 +} + +interact