#!/bin/bash # # .---. . . # | | | # |--- .--. .-. .-. .-.| .-. .--.--. |.-. .-. .--. .-. # | | (.-' (.-' ( | ( )| | | | )( )| | (.-' # ' ' --' --' -' - -' ' ' -' -' -' ' - --' # # Freedom in the Cloud # # Makes a USB drive containing a gpg key fragment # # License # ======= # # Copyright (C) 2015-2017 Bob Mottram # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . PROJECT_NAME='freedombone' export TEXTDOMAIN=${PROJECT_NAME}-keydrive export TEXTDOMAINDIR="/usr/share/locale" USB_DRIVE=/dev/sdb1 USB_MOUNT=/mnt/usb KEY_FRAGMENTS=3 FRAGMENTS_DIR=$USB_MOUNT/.gnupg_fragments MY_USERNAME=$USER MASTER_DRIVE="no" FORMAT="no" function show_help { echo '' echo $"${PROJECT_NAME}-keydrive -u [username] -d [device, eg. sdb] --master [yes/no] -n [no of fragments] --format [yes/no]" echo '' exit 0 } while [[ $# > 1 ]] do key="$1" case $key in -h|--help) show_help ;; -u|--user) shift MY_USERNAME="$1" ;; -d|--dev) shift if [[ "${1}" != '/dev/'* ]]; then USB_DRIVE=/dev/${1}1 else USB_DRIVE=${1} fi ;; -m|--master) shift MASTER_DRIVE="$1" ;; -n|--fragments) shift KEY_FRAGMENTS=$1 ;; -f|--format) shift FORMAT="yes" ;; *) # unknown option ;; esac shift done if [ ! $MY_USERNAME ]; then echo $'No username given' exit 69350 fi if [ ! -d /home/$MY_USERNAME ]; then echo $"Home directory for $MY_USERNAME not found. This user may not exist on the system" exit 72378 fi if [ ! -b $USB_DRIVE ]; then echo $'Please attach a USB drive' exit 65743 fi umount -f $USB_MOUNT if [ ! -d $USB_MOUNT ]; then mkdir $USB_MOUNT fi if [ -f /dev/mapper/encrypted_usb ]; then rm -rf /dev/mapper/encrypted_usb fi cryptsetup luksClose encrypted_usb # optionally format the drive if [[ $FORMAT == "yes" ]]; then ${PROJECT_NAME}-format ${USB_DRIVE::-1} if [ ! "$?" = "0" ]; then exit 36823 fi fi cryptsetup luksOpen $USB_DRIVE encrypted_usb if [ "$?" = "0" ]; then USB_DRIVE=/dev/mapper/encrypted_usb fi mount $USB_DRIVE $USB_MOUNT if [ ! "$?" = "0" ]; then echo $"There was a problem mounting the USB drive to $USB_MOUNT" rm -rf $USB_MOUNT exit 78543 fi # optionally create a master drive which contains the full GPG keyring if [[ $MASTER_DRIVE == "yes" || $MASTER_DRIVE == "y" || $MASTER_DRIVE == "1" ]]; then if [ ! -d /home/$MY_USERNAME/.gnupg ]; then echo $"No .gnupg directory was found for $MY_USERNAME" umount -f $USB_MOUNT rm -rf $USB_MOUNT exit 73025 fi # export the gpg key and backup key as text # so that it may be imported at the beginning of new installs GPG_TTY=$(tty) export GPG_TTY USER_EMAIL_ADDRESS=$MY_USERNAME@$HOSTNAME GPG_ID=$(su -m root -c "gpg --list-keys $USER_EMAIL_ADDRESS | sed -n '2p' | sed 's/^[ \t]*//'" - $MY_USERNAME) GPG_BACKUP_ID=$(su -m root -c "gpg --list-keys \"(backup key)\" | sed -n '2p' | sed 's/^[ \t]*//'" - $MY_USERNAME) gpgerrstr=$'error' gpgkey=$(gpg --homedir=/home/$MY_USERNAME/.gnupg --armor --export $GPG_ID) if [[ "$gpgkey" == *"$gpgerrstr"* ]]; then echo $'Problem exporting public gpg key' echo "$gpgkey" exit 735282 fi echo '' echo $'Enter your gpg private key passphrase:' gpgprivkey=$(gpg --homedir=/home/$MY_USERNAME/.gnupg --armor --export-secret-key $GPG_ID) if [[ "$gpgprivkey" == *"$gpgerrstr"* ]]; then echo $'Problem exporting private gpg key' echo "$gpgprivkey" gpgprivkey= exit 629362 fi # Dummy password to get around not being able to create a key without passphrase BACKUP_DUMMY_PASSWORD='backup' backupgpgkey=$(gpg --homedir=/home/$MY_USERNAME/.gnupg --armor --export $GPG_BACKUP_ID) if [[ "$backupgpgkey" == *"$gpgerrstr"* ]]; then echo $'Problem exporting public gpg backup key' echo "$backupgpgkey" exit 735282 fi backupgpgprivkey=$(echo "$BACKUP_DUMMY_PASSWORD" | gpg --batch --passphrase-fd 0 --homedir=/home/$MY_USERNAME/.gnupg --armor --export-secret-key $GPG_BACKUP_ID) if [[ "$backupgpgprivkey" == *"$gpgerrstr"* ]]; then echo $'Problem exporting private gpg backup key' echo "$backupgpgprivkey" backupgpgprivkey= exit 629362 fi echo "$gpgkey" > $USB_MOUNT/.mastergpgkey echo "$gpgprivkey" >> $USB_MOUNT/.mastergpgkey echo "$backupgpgkey" > $USB_MOUNT/.backupgpgkey echo "$backupgpgprivkey" >> $USB_MOUNT/.backupgpgkey cp -rf /home/$MY_USERNAME/.gnupg $USB_MOUNT if [ -d /etc/letsencrypt ]; then cp -rf /etc/letsencrypt $USB_MOUNT echo $"LetsEncrypt keys copied to $USB_DRIVE" fi if [ -d $USB_MOUNT/.gnupg ]; then echo $"GPG Keyring copied to $USB_DRIVE. You may now remove the drive." else echo $"Unable to copy gpg keyring to $USB_DRIVE" fi umount -f $USB_MOUNT rm -rf $USB_MOUNT exit 0 fi # Don't use the USB drive if it already contains a full keyring if [ -d $USB_MOUNT/.gnupg ]; then echo $'A full GPG keyring already exists on the USB drive.' echo $'Either reformat the USB drive or use a different drive.' umount -f $USB_MOUNT rm -rf $USB_MOUNT exit 3392 fi # Append the username as a subdirectory. # This has a down side in that it does identify a given fragment # as belonging to a given user, but has the convenience upside # of being able to carry key fragments for multiple friends on # the same USB drive FRAGMENTS_DIR=$FRAGMENTS_DIR/$MY_USERNAME # make a directory to contain the fragments if [ ! -d $FRAGMENTS_DIR ]; then mkdir -p $FRAGMENTS_DIR echo $"Made directory $FRAGMENTS_DIR" fi if [ ! -d $FRAGMENTS_DIR ]; then echo $"There was a problem making the directory $FRAGMENTS_DIR" umount -f $USB_MOUNT rm -rf $USB_MOUNT exit 6843 fi cd $FRAGMENTS_DIR no_of_usb_shares=$(ls -afq keyshare.asc.* | wc -l) if [ ! "$?" = "0" ]; then no_of_usb_shares=0 fi if (( no_of_usb_shares > 0 )); then echo $"A key fragment already exists on the drive for the user $MY_USERNAME" cd ~/ umount -f $USB_MOUNT rm -rf $USB_MOUNT exit 58945 fi # copy a random fragment to the drive LOCAL_FRAGMENTS_DIR=/home/$MY_USERNAME/.gnupg_fragments if [ ! -d $LOCAL_FRAGMENTS_DIR ]; then ${PROJECT_NAME}-splitkey -u $MY_USERNAME -n $KEY_FRAGMENTS fi cd $LOCAL_FRAGMENTS_DIR no_of_local_shares=$(ls -afq keyshare.asc.* | wc -l) if [ ! "$?" = "0" ]; then no_of_local_shares=0 fi if (( no_of_local_shares < 3 )); then ${PROJECT_NAME}-splitkey -u $MY_USERNAME -n $KEY_FRAGMENTS cd $LOCAL_FRAGMENTS_DIR no_of_local_shares=$(ls -afq keyshare.asc.* | wc -l) if [ ! "$?" = "0" ]; then no_of_local_shares=0 fi fi if (( no_of_local_shares < 3 )); then echo $"Not enough key fragments available ${no_of_local_shares}" cd ~/ umount -f $USB_MOUNT rm -rf $USB_MOUNT exit 63386 fi share_files=($LOCAL_FRAGMENTS_DIR/keyshare.asc.*) SHARE_FILENAME=${share_files[RANDOM % ${#share_files[@]}]} cp -f $SHARE_FILENAME $FRAGMENTS_DIR cd $FRAGMENTS_DIR no_of_usb_shares=$(ls -afq keyshare.asc.* | wc -l) echo $"Number of fragments on the drive: ${no_of_usb_shares}" if (( no_of_usb_shares > 1 )); then echo $"Too many key fragments exist in $FRAGMENTS_DIR" ls $FRAGMENTS_DIR cd ~/ umount -f $USB_MOUNT rm -rf $USB_MOUNT exit 54292 fi if (( no_of_usb_shares <= 0 )); then echo $"There was a problem copying the key fragment to $USB_DRIVE" echo $"Files found: ${no_of_usb_shares}" ls $FRAGMENTS_DIR cd ~/ umount -f $USB_MOUNT rm -rf $USB_MOUNT exit 54292 fi cd ~/ umount -f $USB_MOUNT rm -rf $USB_MOUNT echo $"Key fragment copied to $USB_DRIVE. You may now remove the drive." exit 0