From 27fc4d233bac17d54e76e9b17c228316b9b9be74 Mon Sep 17 00:00:00 2001 From: Jun Sun Date: Fri, 16 Oct 2020 20:09:37 -0700 Subject: [PATCH] Check in a baseline so that we don't worry about losing files. --- README.md | 66 +++++++++++++- build_eros.sh | 231 ++++++++++++++++++++++++++++++++++++++++++++++++ chroot_build.sh | 230 +++++++++++++++++++++++++++++++++++++++++++++++ cleanup.sh | 21 +++++ tech-notes.txt | 21 +++++ 5 files changed, 567 insertions(+), 2 deletions(-) create mode 100755 build_eros.sh create mode 100755 chroot_build.sh create mode 100755 cleanup.sh create mode 100644 tech-notes.txt diff --git a/README.md b/README.md index 237d400..ac44502 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,64 @@ -# eroas -Electrum-running-on-a-stick (Eroas) runs Electrum wallet on a fingerprint protected USB disk securely and easily +# EROAS + +EROAS stands for "Electrum Running On A Stick". +EROAS runs Electrum wallet on fingerprint-protected USB disk to achieve +cold-wallet security and warm-wallet convenience at a budget price. +It is meant to +operate like a safe or saving account for infrequent transactions (perhaps <1 transaction per day), +and is suitable to protect assets from anywhere from $1K to $10M USD. + +To use EROAS, simply insert EROAS USB drive into PC/MacBook and boot +from it. Press your fingerprint to unlock the secure drive. Afterwards, +Electrum will start and guide you through the transactions. +Afterwards you shut down the machine, unplug the drive and store it +securely. + + +### Operating modes: + +- Use EROAS with Tor to connect to open Electrum netowrk +- Use EROAS with a single designated Electrum server for better security and privacy + +### Security features + +- The system image is an unmutable ISO image, resistent to all persistent attacks. +- Data partition + - is password-protected crypto file system + - is on a hidden, secondary partiton + - is on a fingerprint-protect secure drive +- Networking + - In Tor mode, no incoming traffic is allowed + - In dedicated electrum server mode, no incoming traffic is allowed, and + only outgoing traffic allowed is for the dedicated server at dedicated + port +- Usual security measures in Electrum (e.g, wallet password) +- Every byte of code is generated from open source software and you can build from scratch +- Only use general purposed and open architecture hardware (PC/Mac/USB disks) + +### Other features + +- supported usb drives include: + - Lexar JumpDrive Fingerprint (https://www.lexar.com/portfolio_page/jumpdrive-fingerprint-f35-usb-3-0-flash-drive/) + - Eaget fingerprint pendrive +- support 2 ways to backup and restore + backup data partition as a backup file. + backup Electrum Mnemonic phrases +- support both mac and PC + + +### User experience + +One-time preparation +- (optional) Build EROAS ISO image from source +- Flash ISO image to the USB public drive + +Running +- Insert USB into any PC or Mac and boot from the USB drive. +- Press finger to unlock secure drive +- if it is first time running + - Upon prompt, select and enter password for encrypted filesystem + - Select Electrum network options: using Tor or using a trusted server. +- Otherwise + - Upon prompt, enter password for encrypted filesystem +- Electrum wallet will start automatically. Follow its UI to create wallet and start transactions. +- Power down machine after every use. diff --git a/build_eros.sh b/build_eros.sh new file mode 100755 index 0000000..4911258 --- /dev/null +++ b/build_eros.sh @@ -0,0 +1,231 @@ +#!/bin/bash + +set -e # exit on error +set -o pipefail # exit on pipeline error +set -u # treat unset variable as error +#set -x + +SCRIPT_DIR="$(dirname "$(readlink -f "$0")")" +CHROOT_DIR=$SCRIPT_DIR/chroot + +CMD=(setup_host debootstrap run_chroot build_iso) + +DATE=`TZ="UTC" date +"%y%m%d-%H%M%S"` + +function help() { + # if $1 is set, use $1 as headline message in help() + if [ -z ${1+x} ]; then + echo -e "This script builds EROAS (Electrum-Running-On-A-Stick)" + echo -e + else + echo -e $1 + echo + fi + echo -e "Supported commands : ${CMD[*]}" + echo -e + echo -e "Syntax: $0 [start_cmd] [-] [end_cmd]" + echo -e "\trun from start_cmd to end_end" + echo -e "\tif start_cmd is omitted, start from first command" + echo -e "\tif end_cmd is omitted, end with last command" + echo -e "\tenter single cmd to run the specific command" + echo -e "\tenter '-' as only argument to run all commands" + echo -e + exit 0 +} + +function find_index() { + local ret; + local i; + for ((i=0; i<${#CMD[*]}; i++)); do + if [ "${CMD[i]}" == "$1" ]; then + index=$i; + return; + fi + done + help "Command not found : $1" +} + +function check_host() { + local os_ver; + os_ver=`lsb_release -d | grep "Ubuntu 20.04"` + if [[ $os_ver == "" ]]; then + echo "WARNING : OS is not Ubuntu 20.04 and is untested" + fi + + if [ $(id -u) -eq 0 ]; then + echo "This script should not be run as 'root'" + exit 1 + fi +} + +function setup_host() { + echo "=====> running setup_host ..." + sudo apt update + sudo apt install -y binutils debootstrap squashfs-tools xorriso grub-pc-bin grub-efi-amd64-bin mtools + sudo mkdir -p $CHROOT_DIR +} + +function debootstrap() { + echo "=====> running debootstrap ... will take a couple of minutes ..." + sudo debootstrap --arch=amd64 --variant=minbase focal $CHROOT_DIR http://us.archive.ubuntu.com/ubuntu/ +} + +function run_chroot() { + echo "=====> running run_chroot ..." + sudo mount --bind /dev $CHROOT_DIR/dev + sudo mount --bind /run $CHROOT_DIR/run + + sudo ln -f $SCRIPT_DIR/chroot_build.sh $CHROOT_DIR/root/chroot_build.sh + sudo chroot $CHROOT_DIR /root/chroot_build.sh - + + sudo umount $CHROOT_DIR/dev + sudo umount $CHROOT_DIR/run +} + +function build_iso() { + echo "=====> running build_iso ..." + + mkdir -p image/{casper,isolinux,install} + + # copy kernel files + sudo cp chroot/boot/vmlinuz-**-**-generic image/casper/vmlinuz + sudo cp chroot/boot/initrd.img-**-**-generic image/casper/initrd + + # grub + touch image/ubuntu + cat < image/isolinux/grub.cfg + +search --set=root --file /ubuntu + +insmod all_video + +set default="0" +set timeout=30 + +menuentry "Run EROAS (Electrum Running On A Stick)" { + linux /casper/vmlinuz boot=casper nopersistent toram quiet splash --- + initrd /casper/initrd +} + +menuentry "Check disc for defects" { + linux /casper/vmlinuz boot=casper integrity-check quiet splash --- + initrd /casper/initrd +} +EOF + + # generate manifest + sudo chroot chroot dpkg-query -W --showformat='${Package} ${Version}\n' | sudo tee image/casper/filesystem.manifest + sudo cp -v image/casper/filesystem.manifest image/casper/filesystem.manifest-desktop + sudo sed -i '/ubiquity/d' image/casper/filesystem.manifest-desktop + sudo sed -i '/casper/d' image/casper/filesystem.manifest-desktop + sudo sed -i '/discover/d' image/casper/filesystem.manifest-desktop + sudo sed -i '/laptop-detect/d' image/casper/filesystem.manifest-desktop + sudo sed -i '/os-prober/d' image/casper/filesystem.manifest-desktop + + # compress rootfs + sudo mksquashfs chroot image/casper/filesystem.squashfs + printf $(sudo du -sx --block-size=1 chroot | cut -f1) > image/casper/filesystem.size + + # create diskdefines + cat < image/README.diskdefines +#define DISKNAME Electrum Running on Stick +#define TYPE binary +#define TYPEbinary 1 +#define ARCH amd64 +#define ARCHamd64 1 +#define DISKNUM 1 +#define DISKNUM1 1 +#define TOTALNUM 0 +#define TOTALNUM0 1 +EOF + + # create iso image + cd $SCRIPT_DIR/image + grub-mkstandalone \ + --format=x86_64-efi \ + --output=isolinux/bootx64.efi \ + --locales="" \ + --fonts="" \ + "boot/grub/grub.cfg=isolinux/grub.cfg" + + ( + cd isolinux && \ + dd if=/dev/zero of=efiboot.img bs=1M count=10 && \ + sudo mkfs.vfat efiboot.img && \ + LC_CTYPE=C mmd -i efiboot.img efi efi/boot && \ + LC_CTYPE=C mcopy -i efiboot.img ./bootx64.efi ::efi/boot/ + ) + + grub-mkstandalone \ + --format=i386-pc \ + --output=isolinux/core.img \ + --install-modules="linux16 linux normal iso9660 biosdisk memdisk search tar ls" \ + --modules="linux16 linux normal iso9660 biosdisk search" \ + --locales="" \ + --fonts="" \ + "boot/grub/grub.cfg=isolinux/grub.cfg" + + cat /usr/lib/grub/i386-pc/cdboot.img isolinux/core.img > isolinux/bios.img + + sudo /bin/bash -c "(find . -type f -print0 | xargs -0 md5sum | grep -v -e 'md5sum.txt' -e 'bios.img' -e 'efiboot.img' > md5sum.txt)" + + sudo xorriso \ + -as mkisofs \ + -iso-level 3 \ + -full-iso9660-filenames \ + -volid "Electrum Running On Stick" \ + -eltorito-boot boot/grub/bios.img \ + -no-emul-boot \ + -boot-load-size 4 \ + -boot-info-table \ + --eltorito-catalog boot/grub/boot.cat \ + --grub2-boot-info \ + --grub2-mbr /usr/lib/grub/i386-pc/boot_hybrid.img \ + -eltorito-alt-boot \ + -e EFI/efiboot.img \ + -no-emul-boot \ + -append_partition 2 0xef isolinux/efiboot.img \ + -output "../eros-$DATE.iso" \ + -m "isolinux/efiboot.img" \ + -m "isolinux/bios.img" \ + -graft-points \ + "/EFI/efiboot.img=isolinux/efiboot.img" \ + "/boot/grub/bios.img=isolinux/bios.img" \ + "." +} + +# ============= main ================ + +check_host + +# check number of args +if [[ $# == 0 || $# > 3 ]]; then help; fi + +# loop through args +dash_flag=false +start_index=0 +end_index=${#CMD[*]} +for ii in "$@"; +do + if [[ $ii == "-" ]]; then + dash_flag=true + continue + fi + find_index $ii + if [[ $dash_flag == false ]]; then + start_index=$index + else + end_index=$(($index+1)) + fi +done +if [[ $dash_flag == false ]]; then + end_index=$(($start_index + 1)) +fi + +#loop through the commands +for ((ii=$start_index; ii<$end_index; ii++)); do + ${CMD[ii]} +done + +echo "$0 - Initial build is done!" + diff --git a/chroot_build.sh b/chroot_build.sh new file mode 100755 index 0000000..afc52ae --- /dev/null +++ b/chroot_build.sh @@ -0,0 +1,230 @@ +#!/bin/bash + +set -e # exit on error +set -o pipefail # exit on pipeline error +set -u # treat unset variable as error +#set -x + +SCRIPT_DIR="$(dirname "$(readlink -f "$0")")" +CHROOT_DIR=$SCRIPT_DIR/chroot + +CMD=(setup_host install_pkg finish_up) + +function help() { + # if $1 is set, use $1 as headline message in help() + if [ -z ${1+x} ]; then + echo -e "This script builds EROAS (Electrum-Running-On-A-Stick)" + echo -e + else + echo -e $1 + echo + fi + echo -e "Supported commands : ${CMD[*]}" + echo -e + echo -e "Syntax: $0 [start_cmd] [-] [end_cmd]" + echo -e "\trun from start_cmd to end_end" + echo -e "\tif start_cmd is omitted, start from first command" + echo -e "\tif end_cmd is omitted, end with last command" + echo -e "\tenter single cmd to run the specific command" + echo -e "\tenter '-' as only argument to run all commands" + echo -e + exit 0 +} + +function find_index() { + local ret; + local i; + for ((i=0; i<${#CMD[*]}; i++)); do + if [ "${CMD[i]}" == "$1" ]; then + index=$i; + return; + fi + done + help "Command not found : $1" +} + +function check_host() { + if [ $(id -u) -ne 0 ]; then + echo "This script should be run as 'root'" + exit 1 + fi + + export HOME=/root + export LC_ALL=C +} + +function setup_host() { + echo "=====> running setup_host ..." + mount none -t proc /proc + mount none -t sysfs /sys + mount none -t devpts /dev/pts + + echo "EROAS" > /etc/hostname + + cat < /etc/apt/sources.list +deb http://us.archive.ubuntu.com/ubuntu/ focal main restricted universe multiverse +deb-src http://us.archive.ubuntu.com/ubuntu/ focal main restricted universe multiverse + +deb http://us.archive.ubuntu.com/ubuntu/ focal-security main restricted universe multiverse +deb-src http://us.archive.ubuntu.com/ubuntu/ focal-security main restricted universe multiverse + +deb http://us.archive.ubuntu.com/ubuntu/ focal-updates main restricted universe multiverse +deb-src http://us.archive.ubuntu.com/ubuntu/ focal-updates main restricted universe multiverse +EOF + + # we need to install systemd first, to configure machine id + apt-get update + apt-get install -y libterm-readline-gnu-perl systemd-sysv + + #configure machine id + dbus-uuidgen > /etc/machine-id + ln -fs /etc/machine-id /var/lib/dbus/machine-id + + # don't understand why, but multiple sources indicate this + dpkg-divert --local --rename --add /sbin/initctl + ln -s /bin/true /sbin/initctl +} + +function install_pkg() { + install_pkg_full +} + +function install_pkg_simple() { + echo "=====> running install_pkg ... will take a long time ..." + apt-get -y upgrade + + # install live linux packages + apt-get install -y ubuntu-standard casper lupin-casper laptop-detect os-prober linux-generic + + # install graphics and desktop + apt-get install -y xfce4 +} + +function install_pkg_full() { + echo "=====> running install_pkg ... will take a long time ..." + apt-get -y upgrade + + # install live linux packages + apt-get install -y \ + ubuntu-standard \ + casper \ + lupin-casper \ + discover \ + laptop-detect \ + os-prober \ + network-manager \ + resolvconf \ + net-tools \ + wireless-tools \ + wpagui \ + locales \ + linux-generic + + # skip ubiquity + apt-get install -y \ + ubiquity \ + ubiquity-casper \ + ubiquity-frontend-gtk \ + ubiquity-slideshow-ubuntu \ + ubiquity-ubuntu-artwork + + # install graphics and desktop + apt-get install -y \ + plymouth-theme-ubuntu-logo \ + ubuntu-gnome-desktop \ + ubuntu-gnome-wallpapers + + # useful tools + apt-get install -y \ + clamav-daemon \ + terminator \ + apt-transport-https \ + curl \ + vim \ + nano \ + less + + # purge + apt-get purge -y \ + transmission-gtk \ + transmission-common \ + gnome-mahjongg \ + gnome-mines \ + gnome-sudoku \ + aisleriot \ + hitori + + # remove unused and clean up apt cache + apt-get autoremove -y + + # final touch + dpkg-reconfigure locales + dpkg-reconfigure resolvconf + + # network manager + cat < /etc/NetworkManager/NetworkManager.conf +[main] +rc-manager=resolvconf +plugins=ifupdown,keyfile +dns=dnsmasq + +[ifupdown] +managed=false +EOF + dpkg-reconfigure network-manager + + apt-get clean -y +} + +function finish_up() { + echo "=====> finish_up" + + # truncate machine id (why??) + truncate -s 0 /etc/machine-id + + # remove diversion (why??) + rm /sbin/initctl + dpkg-divert --rename --remove /sbin/initctl + + rm -rf /tmp/* ~/.bash_history + + umount /proc + umount /sys + umount /dev/pts +} + +# ============= main ================ + +check_host + +# check number of args +if [[ $# == 0 || $# > 3 ]]; then help; fi + +# loop through args +dash_flag=false +start_index=0 +end_index=${#CMD[*]} +for ii in "$@"; +do + if [[ $ii == "-" ]]; then + dash_flag=true + continue + fi + find_index $ii + if [[ $dash_flag == false ]]; then + start_index=$index + else + end_index=$(($index+1)) + fi +done +if [[ $dash_flag == false ]]; then + end_index=$(($start_index + 1)) +fi + +# loop through the commands +for ((ii=$start_index; ii<$end_index; ii++)); do + ${CMD[ii]} +done + +echo "$0 - Initial build is done!" + diff --git a/cleanup.sh b/cleanup.sh new file mode 100755 index 0000000..083273b --- /dev/null +++ b/cleanup.sh @@ -0,0 +1,21 @@ +#!/bin/bash + +# safely remove chroot/ directory top working directory + +echo "STOP!!! - This script will delete chroot/ and image/ directories " +echo " - It makes env ready for a new ISO build" +echo +read -p "Press RETURN to continue ..." answer + +set -x + +sudo chroot chroot umount /proc > /dev/null 2>&1 +sudo chroot chroot umount /sys > /dev/null 2>&1 +sudo chroot chroot umount /dev/pts > /dev/null 2>&1 + +sudo umount chroot/dev > /dev/null 2>&1 +sudo umount chroot/run > /dev/null 2>&1 + +sudo rm -rf chroot + +rm -rf image/ diff --git a/tech-notes.txt b/tech-notes.txt new file mode 100644 index 0000000..43b89d0 --- /dev/null +++ b/tech-notes.txt @@ -0,0 +1,21 @@ +references + +- setup electrum/EPS + https://curiosityoverflow.xyz/posts/bitcoin-electrum-wallet/ + https://medium.com/@armantheparman/bitcoin-core-full-node-on-mac-os-with-electrum-personal-server-and-electrum-desktop-wallet-c4ad0c1543ec + +- electrum intro (good) + https://bitzuma.com/posts/a-beginners-guide-to-the-electrum-bitcoin-wallet/ + +- create liveCD ubuntu + https://help.ubuntu.com/community/LiveCDCustomizationFromScratch + https://help.ubuntu.com/community/LiveCDCustomization + https://github.com/mvallim/live-custom-ubuntu-from-scratch (GOOD) + https://medium.com/pranav-kulshrestha/building-your-own-customized-liveiso-from-scratch-e32b82522bf7 + +- create usb persistent partition + https://askubuntu.com/questions/1181854/how-is-it-easier-to-make-a-persistent-live-drive-with-ubuntu-19-10 + +- ARM vs x86 performance study + see http://junsun.net/wordpress/2020/10/aws-arm64-vs-x86_64-bitcoin-performance-comparison/ + t4g.medium is sufficient for running full node.