From 943c893a6fa16f8a78481a5efebae4c3ea62626d Mon Sep 17 00:00:00 2001 From: Sun Knudsen <hello@sunknudsen.com> Date: Thu, 22 Apr 2021 09:33:45 -0400 Subject: [PATCH] Implemented trezor-restore feature and fixed tmux-buttons bug --- .../README.md | 70 ++++++++++----- .../tmux-buttons.py | 11 +-- .../tmux-buttons.py.sig | 26 +++--- .../trezor-restore.sh | 88 +++++++++++++++++++ .../trezor-restore.sh.sig | 16 ++++ .../trezor-verify-integrity.sh | 31 +++---- .../trezor-verify-integrity.sh.sig | 26 +++--- 7 files changed, 194 insertions(+), 74 deletions(-) create mode 100755 how-to-create-encrypted-paper-backup/trezor-restore.sh create mode 100644 how-to-create-encrypted-paper-backup/trezor-restore.sh.sig diff --git a/how-to-create-encrypted-paper-backup/README.md b/how-to-create-encrypted-paper-backup/README.md index 89f6e89..5af12aa 100644 --- a/how-to-create-encrypted-paper-backup/README.md +++ b/how-to-create-encrypted-paper-backup/README.md @@ -45,7 +45,7 @@ ssh pi@10.0.1.248 -i ~/.ssh/pi ```console $ sudo apt update -$ sudo apt install -y git python3-pip +$ sudo apt install -y git python3-pip python3-rpi.gpio $ sudo pip3 install adafruit-python-shell click==7.0 @@ -230,7 +230,7 @@ $ pip3 install --user Electrum-$ELECTRUM_RELEASE_SEMVER.tar.gz $ rm Electrum-$ELECTRUM_RELEASE_SEMVER.tar.gz* ``` -### Step 8: install `tmux` and [trezorcrl](https://wiki.trezor.io/Using_trezorctl_commands_with_Trezor) (used to verify integrity of [Trezor](https://trezor.io/) devices) +### Step 8: install `tmux` and [trezorcrl](https://wiki.trezor.io/Using_trezorctl_commands_with_Trezor) (used to verify integrity of and restore [Trezor](https://trezor.io/) devices) ```console $ sudo apt update @@ -242,17 +242,7 @@ $ pip3 install attrs trezor --user $ sudo curl -o /etc/udev/rules.d/51-trezor.rules https://data.trezor.io/udev/51-trezor.rules ``` -### Step 9: install `python3-rpi.gpio` and `keyboard` (used to control `tmux` panes) - -```console -$ sudo apt update - -$ sudo apt install -y python3-rpi.gpio - -$ sudo pip3 install keyboard -``` - -### Step 10: import Sunβs PGP public key (used to verify downloads bellow) +### Step 9: import Sunβs PGP public key (used to verify downloads bellow) ```console $ curl https://sunknudsen.com/sunknudsen.asc | gpg --import @@ -268,7 +258,7 @@ imported: 1 π -### Step 11: download and verify [create-bip39-mnemonic.py](./create-bip39-mnemonic.py) +### Step 10: download and verify [create-bip39-mnemonic.py](./create-bip39-mnemonic.py) ```console $ curl -o /home/pi/.local/bin/create-bip39-mnemonic.py https://sunknudsen.com/static/media/privacy-guides/how-to-create-encrypted-paper-backup/create-bip39-mnemonic.py @@ -302,7 +292,7 @@ Good signature π -### Step 12: download and verify [validate-bip39-mnemonic.py](./validate-bip39-mnemonic.py) +### Step 11: download and verify [validate-bip39-mnemonic.py](./validate-bip39-mnemonic.py) ```console $ curl -o /home/pi/.local/bin/validate-bip39-mnemonic.py https://sunknudsen.com/static/media/privacy-guides/how-to-create-encrypted-paper-backup/validate-bip39-mnemonic.py @@ -336,7 +326,7 @@ Good signature π -### Step 13: download and verify [tmux-buttons.py](./tmux-buttons.py) +### Step 12: download and verify [tmux-buttons.py](./tmux-buttons.py) ```console $ curl -o /home/pi/.local/bin/tmux-buttons.py https://sunknudsen.com/static/media/privacy-guides/how-to-create-encrypted-paper-backup/tmux-buttons.py @@ -351,7 +341,7 @@ $ curl -o /home/pi/.local/bin/tmux-buttons.py.sig https://sunknudsen.com/static/ $ gpg --verify /home/pi/.local/bin/tmux-buttons.py.sig gpg: assuming signed data in '/home/pi/.local/bin/tmux-buttons.py' -gpg: Signature made Wed 21 Apr 2021 09:23:12 EDT +gpg: Signature made Thu Apr 22 09:13:47 2021 EDT gpg: using RSA key A98CCD122243655B26FAFB611FA767862BBD1305 gpg: Good signature from "Sun Knudsen <hello@sunknudsen.com>" [unknown] gpg: WARNING: This key is not certified with a trusted signature! @@ -370,7 +360,7 @@ Good signature π -### Step 14: download and verify [qr-backup.sh](./qr-backup.sh) +### Step 13: download and verify [qr-backup.sh](./qr-backup.sh) ```console $ curl -o /home/pi/.local/bin/qr-backup.sh https://sunknudsen.com/static/media/privacy-guides/how-to-create-encrypted-paper-backup/qr-backup.sh @@ -404,7 +394,7 @@ Good signature π -### Step 15: download and verify [qr-restore.sh](./qr-restore.sh) +### Step 14: download and verify [qr-restore.sh](./qr-restore.sh) ```console $ curl -o /home/pi/.local/bin/qr-restore.sh https://sunknudsen.com/static/media/privacy-guides/how-to-create-encrypted-paper-backup/qr-restore.sh @@ -438,7 +428,7 @@ Good signature π -### Step 16: download and verify [qr-clone.sh](./qr-clone.sh) +### Step 15: download and verify [qr-clone.sh](./qr-clone.sh) ```console $ curl -o /home/pi/.local/bin/qr-clone.sh https://sunknudsen.com/static/media/privacy-guides/how-to-create-encrypted-paper-backup/qr-clone.sh @@ -472,7 +462,7 @@ Good signature π -### Step 17: download and verify [secure-erase.sh](./secure-erase.sh) +### Step 16: download and verify [secure-erase.sh](./secure-erase.sh) ```console $ curl -o /home/pi/.local/bin/secure-erase.sh https://sunknudsen.com/static/media/privacy-guides/how-to-create-encrypted-paper-backup/secure-erase.sh @@ -506,7 +496,7 @@ Good signature π -### Step 18: download and verify [trezor-verify-integrity.sh](./trezor-verify-integrity.sh) (used to validate Trezor devices) +### Step 17: download and verify [trezor-verify-integrity.sh](./trezor-verify-integrity.sh) (used to validate Trezor devices) ```console $ curl -o /home/pi/.local/bin/trezor-verify-integrity.sh https://sunknudsen.com/static/media/privacy-guides/how-to-create-encrypted-paper-backup/trezor-verify-integrity.sh @@ -521,7 +511,7 @@ $ curl -o /home/pi/.local/bin/trezor-verify-integrity.sh.sig https://sunknudsen. $ gpg --verify /home/pi/.local/bin/trezor-verify-integrity.sh.sig gpg: assuming signed data in '/home/pi/.local/bin/trezor-verify-integrity.sh' -gpg: Signature made Wed Apr 21 13:15:30 2021 EDT +gpg: Signature made Thu Apr 22 09:13:56 2021 EDT gpg: using RSA key A98CCD122243655B26FAFB611FA767862BBD1305 gpg: Good signature from "Sun Knudsen <hello@sunknudsen.com>" [unknown] gpg: WARNING: This key is not certified with a trusted signature! @@ -540,6 +530,40 @@ Good signature π +### Step 18: download and verify [trezor-restore.sh](./trezor-restore.sh) (used to validate Trezor devices) + +```console +$ curl -o /home/pi/.local/bin/trezor-restore.sh https://sunknudsen.com/static/media/privacy-guides/how-to-create-encrypted-paper-backup/trezor-restore.sh + % Total % Received % Xferd Average Speed Time Time Time Current + Dload Upload Total Spent Left Speed +100 1283 100 1283 0 0 1189 0 0:00:01 0:00:01 --:--:-- 1189 + +$ curl -o /home/pi/.local/bin/trezor-restore.sh.sig https://sunknudsen.com/static/media/privacy-guides/how-to-create-encrypted-paper-backup/trezor-restore.sh.sig + % Total % Received % Xferd Average Speed Time Time Time Current + Dload Upload Total Spent Left Speed +100 833 100 833 0 0 944 0 --:--:-- --:--:-- --:--:-- 944 + +$ gpg --verify /home/pi/.local/bin/trezor-restore.sh.sig +gpg: assuming signed data in '/home/pi/.local/bin/trezor-restore.sh' +gpg: Signature made Thu Apr 22 09:14:04 2021 EDT +gpg: using RSA key A98CCD122243655B26FAFB611FA767862BBD1305 +gpg: Good signature from "Sun Knudsen <hello@sunknudsen.com>" [unknown] +gpg: WARNING: This key is not certified with a trusted signature! +gpg: There is no indication that the signature belongs to the owner. +Primary key fingerprint: C4FB DDC1 6A26 2672 920D 0A0F C132 3A37 7DE1 4C8B + Subkey fingerprint: A98C CD12 2243 655B 26FA FB61 1FA7 6786 2BBD 1305 + +$ chmod 700 /home/pi/.local/bin/trezor-restore.sh +``` + +Primary key fingerprint matches [published](../how-to-encrypt-sign-and-decrypt-messages-using-gnupg-on-macos#verify-suns-pgp-public-key-using-its-fingerprint) fingerprints + +π + +Good signature + +π + ### Step 19: make filesystem read-only > Heads-up: shout-out to Nico Kaiser for his amazing [guide](https://gist.github.com/nicokaiser/08aa5b7b3958f171cf61549b70e8a34b) on how to configure a read-only Raspberry Pi. diff --git a/how-to-create-encrypted-paper-backup/tmux-buttons.py b/how-to-create-encrypted-paper-backup/tmux-buttons.py index d18f0e7..22e9626 100644 --- a/how-to-create-encrypted-paper-backup/tmux-buttons.py +++ b/how-to-create-encrypted-paper-backup/tmux-buttons.py @@ -1,5 +1,5 @@ import RPi.GPIO as GPIO -import keyboard +import subprocess import time GPIO.setmode(GPIO.BCM) @@ -10,13 +10,14 @@ GPIO.setup(23, GPIO.IN, pull_up_down = GPIO.PUD_UP) def click(channel): if channel == 17: - keyboard.send("ctrl+b, up") + subprocess.run(["tmux", "select-pane", "-t", "0"]) elif channel == 22: - keyboard.send("ctrl+b, down") + subprocess.run(["tmux", "select-pane", "-t", "1"]) elif channel == 23: - keyboard.send("ctrl+b, shift+7") + subprocess.run(["tmux", "kill-session"]) # elif channel == 27: - # keyboard.send("") + # subprocess.run(["tmux"]) + GPIO.add_event_detect(17, GPIO.RISING, callback=click, bouncetime=300) GPIO.add_event_detect(22, GPIO.RISING, callback=click, bouncetime=300) GPIO.add_event_detect(23, GPIO.RISING, callback=click, bouncetime=300) diff --git a/how-to-create-encrypted-paper-backup/tmux-buttons.py.sig b/how-to-create-encrypted-paper-backup/tmux-buttons.py.sig index 29e5c00..ce8259f 100644 --- a/how-to-create-encrypted-paper-backup/tmux-buttons.py.sig +++ b/how-to-create-encrypted-paper-backup/tmux-buttons.py.sig @@ -1,16 +1,16 @@ -----BEGIN PGP SIGNATURE----- -iQIzBAABCgAdFiEEqYzNEiJDZVsm+vthH6dnhiu9EwUFAmCAJ0AACgkQH6dnhiu9 -EwWl6hAAuswrzfBiZ0kboM1qa4vtCtv/Mst1ZGmSs+pzTwH0K7uPnITMiW5JN1Cu -jODENEZPRNmpgoSSOV6tvJmGhYKWEVHRHP6fdU3xHG9AJZcrrq0LR+i+7qO+kdoJ -iBc/w1KZsjv8Iu0vpXSeqROAxwvG6enUGexx4Ov4EovZHnUjttC2O62VQ1yIVlUy -UxVs3Ky95w9WIo3KTUTjJrrQ3drpi3G0ezq4JHQRvPDscHZnTAcj7oxsPMKVZ8z1 -kBI1UUyPgUKvMRssnLjp8hUC+Bc2mrZXt8f66Y+R0C0/xp5r8UijabogbIsM83sz -oreDHsaDgidzvxKO3OPy3YBG+HLaccKddcyb7mYsH6oBzpx0WgcAwszICCV33bke -PEyPMQ3jVyl6EtlGSxGvofglA4MqP0K7enCAmhMsbWF6p2iyz203dDfvV/fFwONi -PBRjgbk6z9x67uAc9XnZrTwaIYsiCYel6EBW39w/ZfUGocnEGuIjrDCypN7b0b3U -pQy2ML6gC0/bsXo4wGThN3wMI32cxxFrEjwZDYwzS14h4eufar96JFlVohPsBdr1 -589goQwkfQToClwnA7Jlsmqc/ZctGSkqQl/wY7beT+/KJYSIA36aolgVNlefgTc0 -i+esMZRMxc1WQrt8XZEjg0Nu8DjUPdkapQJStdsrZiqO61EPfHc= -=gTZ3 +iQIzBAABCgAdFiEEqYzNEiJDZVsm+vthH6dnhiu9EwUFAmCBdosACgkQH6dnhiu9 +EwVO0w/+OuHCOnL3nAF0ShoQx2851IFsuiJHP3FHKpQNBIqde4DhudYDjusrOyGR +NnmCo6gotUMVqzCUaqPhC23tUzUYB4KhpjDA/mz0HTEr1JIFQvxa0N1AMW0HnsnZ +EJLi53eCzjx+9lA8Wy+Okh+mZtM5hflatv/yONIrXyMXV+jDk0sgWJ1amxQvPEaT +D/L/9LGvJ9S7QQ/BJfxNVLu+CkBJAqxr8IPKG+mLJMX9nChF+AXu58xGmH35YZtP +nQwjEINFhUziTIyJJwRSLKZa96LhPkXLFtdfDcgs8br+T+Hjaa9AOGd9WJiU1SkX +p3F1rsbeC1w7KEsbFG1KkyS4KQe4oOFMXBGhBtvTiSXn/f7BWjJ6G3vMImzBWJ7I +tszifz/xcVxYsTHMfjtCMIvS+Es/wqAn6MOzsLJwc6T6qT+hz2bA+aP4MM2BQ2QB +mzeEavFumvlpFrCnEbeKNF+WyNK3ULDOEBrK1B1sT+CBzVmQm0RVovgs9Diqsxfi +zEYDnjY569tr9lh6rYHm9IjC4lMsQ7d8u/seaFROqK0BFd9vezItDFOYz2YqI06M +pTYTghBymSlxBgWspieBggH62Ji7wD+0t3MW0f34O4i226h9Ol7CWj9luA5MGADB +I2by6x5m9m5L6aK0ipD/hP/n3uUHvFitnPjNYY3FJvCYXLMME1I= +=RWAj -----END PGP SIGNATURE----- diff --git a/how-to-create-encrypted-paper-backup/trezor-restore.sh b/how-to-create-encrypted-paper-backup/trezor-restore.sh new file mode 100755 index 0000000..c041e6d --- /dev/null +++ b/how-to-create-encrypted-paper-backup/trezor-restore.sh @@ -0,0 +1,88 @@ +#! /bin/bash + +set -e +set -o pipefail + +function cleanup() +{ + kill 0 + exit 0 +} + +trap cleanup EXIT + +positional=() +while [[ $# -gt 0 ]]; do + argument="$1" + case $argument in + -h|--help) + printf "%s\n" \ + "Usage: trezor-restore.sh [options]" \ + "" \ + "Options:" \ + " --label <label> set Trezor label" \ + " --qr-restore-options see \`qr-restore.sh --help\`" \ + " -h, --help display help for command" + exit 0 + ;; + --qr-restore-options) + qr_restore_options=$2 + shift + shift + ;; + --label) + label=$2 + shift + shift + ;; + *) + positional+=("$1") + shift + ;; + esac +done + +set -- "${positional[@]}" + +bold=$(tput bold) +red=$(tput setaf 1) +normal=$(tput sgr0) + +basedir=$(dirname "$0") + +label_arg="" +if [ -n "$label" ]; then + label_arg="--label \"$label\" " +fi + +tput reset + +printf "$bold$red%s$normal\n" "Restore Trezor device using encrypted paper backup (y or n)?" +read -r answer +if [ "$answer" != "y" ]; then + printf "%s\n" "Cancelled" + exit 0 +fi + +printf "$bold$red%s$normal\n" "TREZOR WILL BE PERMANENTLY WIPED." + +printf "$bold$red%s$normal\n" "Do you wish to proceed (y or n)?" +read -r answer +if [ "$answer" != "y" ]; then + printf "%s\n" "Cancelled" + exit 0 +fi + +printf "%s\n" "Spawning tmux panesβ¦" + +sleep 1 + +python3 $basedir/tmux-buttons.py & + +tmux new -d -s trezor-restore +tmux rename-window -t trezor-restore trezorctl +tmux send-keys -t trezor-restore "trezorctl wipe-device && trezorctl recovery-device --pin-protection --passphrase-protection $label_arg--words 24 --type scrambled" Enter +tmux split-window -t trezor-restore +tmux rename-window -t trezor-restore qr-restore +tmux send-keys -t trezor-restore "qr-restore.sh $(echo $qr_restore_options | sed 's/--word-list *//') --word-list" Enter +tmux attach -t trezor-restore diff --git a/how-to-create-encrypted-paper-backup/trezor-restore.sh.sig b/how-to-create-encrypted-paper-backup/trezor-restore.sh.sig new file mode 100644 index 0000000..3ad32de --- /dev/null +++ b/how-to-create-encrypted-paper-backup/trezor-restore.sh.sig @@ -0,0 +1,16 @@ +-----BEGIN PGP SIGNATURE----- + +iQIzBAABCgAdFiEEqYzNEiJDZVsm+vthH6dnhiu9EwUFAmCBdpwACgkQH6dnhiu9 +EwXizA/+Ja8i0nH2r6u7jXk+YhljdRjZFGNDOq3xLxMhDadUELbHJA5NhIdFHjY4 +OGXUmQh2dH0pbX825kYnVCVcfBhRH9+umX7Ddlqb9YThp466/XMoSVJzvXA7IDHb +cBQ6WsZ2VcJnc36/R6drwp333Sg7CJ7FGLFhgmk2l/y6wvc1WaZ2f2MLjc4fRl3b +GYwoqZcDx1z8QPsto6ba9SQuGPs4gjDxd7f3kaYba1PMcLCZxx3dOrtk7VSyA19r +yGGaP2zTT9OOlP/Mm3dm/NXya0sOj01np9bZ4hrcK3CsZNJeyf2XaaAaYY9mEHNU +8nPuT1kq4svbeaXI4U2J5CYOy3LLBOpjyZr87ClI8ppSmOHwYSZI++4A3/NkaBQK ++r5RDwlQIRC6FEO9gIMoWoInhM4GOCNnQITJENVhKDBKR7rG0K/FZLyZUKmnMM/y +wYPLqk8s4Cbu/aakXd94vbEna8OeAM/v7sZCiUwg70Q2BeB/otMyrqnzP1a6VCxB +L0AWzc9fJYd4NlzKHuzNRcNM+fWMOH0sXhffkA7wS52+G7rakiZ/VgZ2FrIx3abA +DCgzac11KfA+RXUHcmE+NoxtWad4Y8Y8OzNcbiKU1a2umyJg0g4bH2esiP/itVZm +aCnI3KXuhwRYaIfIub9T9xZZoktHb8CLPDQRhrUeIDW1j5rqQag= +=hbtz +-----END PGP SIGNATURE----- diff --git a/how-to-create-encrypted-paper-backup/trezor-verify-integrity.sh b/how-to-create-encrypted-paper-backup/trezor-verify-integrity.sh index d5c4c80..61bd62b 100755 --- a/how-to-create-encrypted-paper-backup/trezor-verify-integrity.sh +++ b/how-to-create-encrypted-paper-backup/trezor-verify-integrity.sh @@ -5,11 +5,11 @@ set -o pipefail function cleanup() { - sudo kill 0 + kill 0 exit 0 } -trap cleanup INT EXIT +trap cleanup EXIT positional=() while [[ $# -gt 0 ]]; do @@ -17,7 +17,7 @@ while [[ $# -gt 0 ]]; do case $argument in -h|--help) printf "%s\n" \ - "Usage: trezor-validate.sh [options]" \ + "Usage: trezor-verify-integrity.sh [options]" \ "" \ "Options:" \ " --qr-restore-options see \`qr-restore.sh --help\`" \ @@ -49,21 +49,12 @@ printf "%s\n" "Spawning tmux panesβ¦" sleep 1 -sudo bash -c "python3 $basedir/tmux-buttons.py &" +python3 $basedir/tmux-buttons.py & -tmux new -d -s trezor-validate -tmux rename-window -t trezor-validate trezorctl -tmux send-keys -t trezor-validate "trezorctl recovery-device --words 24 --type scrambled --dry-run" Enter -tmux split-window -t trezor-validate -tmux rename-window -t trezor-validate qr-restore -tmux send-keys -t trezor-validate "qr-restore.sh $(echo $qr_restore_options | sed 's/--word-list *//') --word-list" Enter -tmux attach -t trezor-validate - -tput reset - -printf "$bold%s$normal\n" "Press ctrl+c to exit" - -while : -do - sleep 60 -done +tmux new -d -s trezor-verify-integrity +tmux rename-window -t trezor-verify-integrity trezorctl +tmux send-keys -t trezor-verify-integrity "trezorctl recovery-device --words 24 --type scrambled --dry-run" Enter +tmux split-window -t trezor-verify-integrity +tmux rename-window -t trezor-verify-integrity qr-restore +tmux send-keys -t trezor-verify-integrity "qr-restore.sh $(echo $qr_restore_options | sed 's/--word-list *//') --word-list" Enter +tmux attach -t trezor-verify-integrity diff --git a/how-to-create-encrypted-paper-backup/trezor-verify-integrity.sh.sig b/how-to-create-encrypted-paper-backup/trezor-verify-integrity.sh.sig index 3b2cb82..d7ceaf0 100644 --- a/how-to-create-encrypted-paper-backup/trezor-verify-integrity.sh.sig +++ b/how-to-create-encrypted-paper-backup/trezor-verify-integrity.sh.sig @@ -1,16 +1,16 @@ -----BEGIN PGP SIGNATURE----- -iQIzBAABCgAdFiEEqYzNEiJDZVsm+vthH6dnhiu9EwUFAmCAXbIACgkQH6dnhiu9 -EwVBFg/9EctBpaNqFR54nzCPKsZoa6g5DqCAkGeWI7JXOjbV551Do6SAFK7RrG5S -g454q77w7XmMFrJFIl8Yd+h88KyKni0zoi5AFtEL4qVAiVaJJZvMxHYAfxvS4zgE -ksM0M2svVf/FkIBEmzJsDliNTCAALsaT7XZ6s4cLjaBs1P6RK9LZb/cobkckDOqL -/3hcaOplDPGaLIOFzdjuYZv6k/WE9wf+uuAlKgnmevnCDWq+eO0W0CasGkIDcw61 -QIqllFK3c8RJKSv7Ab+9GPQGFM//+Is4rRXXH10StaTvnpTTP+Q9QBG7faFGjwZv -dzwKI88fZAxY8cCKYeNdHsA2RNqf74bJ/3S5INdudfKbelj1oU1o1CTk8eMCsqSP -XdGjv7KVkoTI1bHhkBy2s2lBs9ZDU4GjPmD7gaABDPQk2u4Yatw+zN/8cFZ8LrgT -0CaCVCXBVwwihrtdpO0OM4c9YCTEWPyphAkUs3S0+geElyaYWHFBFODpM/yxqS3f -GA1E6hvQD+jZmVM++bHVyWq4Li0nXtknsihNTnURcD+S0GsKlpdFgYTmggMyNyCQ -nbEuUHMs6J0dQFYHo1se6rKTEpRdcSvVLsj8UbIVdA5Ip7OX810poxU3Z+as4cKO -1MU4K7mzVtda0LLz156iyAEKiJHhGvoneFgcqqZx92FzBsV+Mlk= -=MGmG +iQIzBAABCgAdFiEEqYzNEiJDZVsm+vthH6dnhiu9EwUFAmCBdpQACgkQH6dnhiu9 +EwXQTg/+Nhi3XmFBXGQmGBfB606ZVaFbE6Gwl9ltzvMlS/bPRn7ypMeeGPfmSpvR +1pt54zBMhW77mfYFnq70gx44Jt2GslcnFFyL1SB3C8+W1v/Hhx5ukIgOFXjwmxQ6 +BbP1tSH0M6RHm1NxJ+ct5ju/7EgDE7xIDRU6KRQTb3rMGq5X2lvmvHFpS62BsA/i +G9PldYjL947q5jntoeCj3pJmbk7u8aFZwvKgxiPOTUzd78Im70oDwlhMeUGNMKfm +ux9gy1lTvsYMmAM7XNjdKGmqduCWqmAr8/xp59VArYkOUnD8U4GK/a+NqV63I4o9 +ey1uvyFwM2Y4vvLp2GqJgWE/ul1agrFaW4+yir8H3zNs9TbjOdytMhZSY9XbuSST +KEhRNNfKF7VSo+qHjMrBZVuJ6sGEDmylBFBsBVfyl1fCS7siyDQ6x0MSqVjqANQd +Nb8dsTkErhnxZHbYH/O09+hqgPiGoEvA0VES+xcIk7jjPtYK/0Hnodjy7HNznwhM ++HO8RV+IWllVFM8bX/KwlFBhf99d/SqpU6peBh5B+1Y81v/UpkuQzlxKqIEa9png +wzPG21/5YTkKEzrS16qxIprT3TOcabfNmYO5BGCszmJTiV8ceTsjX7kDqMFXbtsO +nNJYtaatmNw+HU/qqrQ5a0I5Y28641nMCcrfwJbammNQ0JgmuQg= +=OvCj -----END PGP SIGNATURE-----