1#!@SHELL@ 2# 3# This program is free software; you can redistribute it and/or 4# modify it under the terms of the GNU General Public License 5# as published by the Free Software Foundation; either version 2 6# of the License, or (at your option) any later version. 7# 8# This program is distributed in the hope that it will be useful, 9# but WITHOUT ANY WARRANTY; without even the implied warranty of 10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11# GNU General Public License for more details. 12# 13# You should have received a copy of the GNU General Public License 14# along with this program; if not, write to the Free Software 15# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 16# 17# Amanda, The Advanced Maryland Automatic Network Disk Archiver 18# 19# Permission to use, copy, modify, distribute, and sell this software and its 20# documentation for any purpose is hereby granted without fee, provided that 21# the above copyright notice appear in all copies and that both that 22# copyright notice and this permission notice appear in supporting 23# documentation, and that the name of U.M. not be used in advertising or 24# publicity pertaining to distribution of the software without specific, 25# written prior permission. U.M. makes no representations about the 26# suitability of this software for any purpose. It is provided "as is" 27# without express or implied warranty. 28# 29# U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL 30# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M. 31# BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 32# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 33# OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 34# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 35# 36# Copyright (c) 2006 Ben Slusky <sluskyb@paranoiacs.org> 37 38 39# amcrypt-ossl-asym.sh - asymmetric crypto helper using OpenSSL 40# Usage: amcrypt-ossl-asym.sh [-d] 41# 42 43# Keys can be generated with the standard OpenSSL commands, e.g.: 44# 45# $ openssl genrsa -aes128 -out backup-privkey.pem 1024 46# Generating RSA private key, 1024 bit long modulus 47# [...] 48# Enter pass phrase for backup-privkey.pem: <ENTER YOUR PASS PHRASE> 49# Verifying - Enter pass phrase for backup-privkey.pem: <ENTER YOUR PASS PHRASE> 50# 51# $ openssl rsa -in backup-privkey.pem -pubout -out backup-pubkey.pem 52# Enter pass phrase for backup-privkey.pem: <ENTER YOUR PASS PHRASE> 53# Writing RSA key 54# 55 56prefix="@prefix@" 57exec_prefix="@exec_prefix@" 58sbindir="@sbindir@" 59amlibexecdir="@amlibexecdir@" 60. "${amlibexecdir}/amanda-sh-lib.sh" 61 62# change these as needed 63OPENSSL= # whatever's in $PATH 64CIPHER=aes-256-cbc # see `openssl help` for more ciphers 65AMANDA_HOME=~@CLIENT_LOGIN@ 66RANDFILE=$AMANDA_HOME/.rnd 67export RANDFILE 68PASSPHRASE=$AMANDA_HOME/.am_passphrase # optional 69PRIVKEY=$AMANDA_HOME/backup-privkey.pem 70PUBKEY=$AMANDA_HOME/backup-pubkey.pem 71 72# where might openssl be? 73PATH=/bin:/usr/bin:/usr/local/bin:/usr/ssl/bin:/usr/local/ssl/bin:/opt/csw/bin 74export PATH 75MAGIC='AmAnDa+OpEnSsL' 76ME=`basename "$0"` 77WORKDIR="/tmp/.${ME}.$$" 78 79 80# first things first 81if [ -z "${OPENSSL:=`which openssl`}" ]; then 82 echo `_ '%s: %s not found' "${ME}" "openssl"` >&2 83 exit 1 84elif [ ! -x "${OPENSSL}" ]; then 85 echo `_ "%s: can't execute %s (%s)" "${ME}" "openssl" "${OPENSSL}"` >&2 86 exit 1 87fi 88 89if [ -n "${PASSPHRASE}" ]; then 90 # check the openssl version. if it's too old, we have to handle 91 # the pass phrase differently. 92 OSSL_VERSION=`eval \"${OPENSSL}\" version |cut -d\ -f2` 93 case "${OSSL_VERSION}" in 94 ''|0.[0-8].*|0.9.[0-6]*|0.9.7|0.9.7[a-c]*) 95 echo `_ '%s: %s is version %s' "${ME}" "${OPENSSL}" "${OSSL_VERSION}"` >&2 96 echo `_ '%s: Using pass phrase kluge for OpenSSL version >=0.9.7d' "${ME}"` >&2 97 PASS_FROM_STDIN=yes 98 ;; 99 esac 100fi 101 102mkdir -m 700 "${WORKDIR}" 103if [ $? -ne 0 ]; then 104 echo `_ '%s: failed to create temp directory' "${ME}"` >&2 105 exit 1 106fi 107# ignore SIGINT 108trap "" 2 109trap "rm -rf \"${WORKDIR}\"" 0 1 3 15 110 111# we'll need to pad the datastream to a multiple of the cipher block size 112# prior to encryption and decryption. 96 bytes (= 768 bits) should be good 113# for any cipher. 114pad() { 115 perl -pe 'BEGIN { $bs = 96; $/ = \8192 } $nbytes = ($nbytes + length) % $bs; END { print "\0" x ($bs - $nbytes) }' 116} 117 118encrypt() { 119 # generate a random printable cipher key (on one line) 120 echo `"${OPENSSL}" rand -base64 80` >"${WORKDIR}/pass" 121 122 # encrypt the cipher key using the RSA public key 123 "${OPENSSL}" rsautl -encrypt -in "${WORKDIR}/pass" -out "${WORKDIR}/pass.ciphertext" -pubin -inkey "${PUBKEY}" -pkcs 124 [ $? -eq 0 ] || return 1 125 126 # print magic 127 printf "%s" "${MAGIC}" 128 129 # print the encrypted cipher key, preceded by size 130 ls -l "${WORKDIR}/pass.ciphertext" | awk '{ printf("%-10d", $5) }' 131 cat "${WORKDIR}/pass.ciphertext" 132 133 # encrypt data using the cipher key and print 134 pad | "${OPENSSL}" enc "-${CIPHER}" -nopad -e -pass "file:${WORKDIR}/pass" -nosalt 135 [ $? -eq 0 ] || return 1 136} 137 138decrypt() { 139 # read magic 140 magicsize=`printf "%s" "${MAGIC}" | wc -c | sed 's/^ *//'` 141 magic=`dd bs=$magicsize count=1 2>/dev/null` 142 if [ "$magic" != "${MAGIC}" ]; then 143 echo `_ '%s: bad magic' "${ME}"` >&2 144 return 1 145 fi 146 147 # read size of encrypted cipher key 148 n=`dd bs=10 count=1 2>/dev/null` 149 [ $n -gt 0 ] 2>/dev/null 150 if [ $? -ne 0 ]; then 151 echo `_ '%s: bad header' "${ME}"` >&2 152 return 1 153 fi 154 155 # read the encrypted cipher key 156 dd "of=${WORKDIR}/pass.ciphertext" bs=$n count=1 2>/dev/null 157 158 # decrypt the cipher key using the RSA private key 159 if [ "${PASS_FROM_STDIN}" = yes ]; then 160 "${OPENSSL}" rsautl -decrypt -in "${WORKDIR}/pass.ciphertext" -out "${WORKDIR}/pass" -inkey "${PRIVKEY}" -pkcs < "${PASSPHRASE}" 161 else 162 "${OPENSSL}" rsautl -decrypt -in "${WORKDIR}/pass.ciphertext" -out "${WORKDIR}/pass" -inkey "${PRIVKEY}" ${PASSARG} -pkcs 3< "${PASSPHRASE}" 163 fi 164 [ $? -eq 0 ] || return 1 165 166 # use the cipher key to decrypt data 167 pad | "${OPENSSL}" enc "-${CIPHER}" -nopad -d -pass "file:${WORKDIR}/pass" -nosalt 168 169 # N.B.: in the likely event that we're piping to gzip, the above command 170 # may return a spurious error if gzip closes the output stream early. 171 return 0 172} 173 174if [ "$1" = -d ]; then 175 if [ -z "${PRIVKEY}" ]; then 176 echo `_ '%s: must specify private key for decryption' "${ME}"` >&2 177 exit 1 178 elif [ ! -r "${PRIVKEY}" ]; then 179 echo `_ "%s: can't read private key from %s" "${ME}" "${PRIVKEY}"` >&2 180 exit 1 181 fi 182 183 if [ -n "${PASSPHRASE}" -a -e "${PASSPHRASE}" -a -r "${PASSPHRASE}" ]; then 184 PASSARG='-passin fd:3' 185 else 186 PASSPHRASE=/dev/null 187 fi 188 189 decrypt 190 if [ $? -ne 0 ]; then 191 echo `_ '%s: decryption failed' "${ME}"` >&2 192 exit 1 193 fi 194else 195 if [ -z "${PUBKEY}" ]; then 196 echo `_ '%s: must specify public key for encryption' "${ME}"` >&2 197 exit 1 198 elif [ ! -r "${PUBKEY}" ]; then 199 echo `_ "%s: can't read public key from %s" "${ME}" "${PUBKEY}"` >&2 200 exit 1 201 fi 202 203 encrypt 204 if [ $? -ne 0 ]; then 205 echo `_ '%s: encryption failed' "${ME}"` >&2 206 exit 1 207 fi 208fi 209