Created
September 1, 2022 21:29
-
-
Save u8sand/53b48f0266f1bbff6d2ee50d79601de8 to your computer and use it in GitHub Desktop.
Use ssh keys & github for quick and easy crypto.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# | |
# A helper for using ssh keys & github for encrypting/decrypting messages intended for specific recipients. | |
# Installation (assumes ~/.local/sbin/ is in your PATH, put it wherever you want): | |
# 1. Download script | |
# 2. mv ssh-crypt.sh ~/.local/sbin/ssh-crypt | |
# 3. chmod +x ~/.local/sbin/ssh-crypt | |
# | |
# See `ssh-crypt help` for command information. | |
_help() { | |
COMMAND=$1 | |
case "${COMMAND}" in | |
help) | |
echo "Usage: $0 ${COMMAND} [COMMAND]" | |
echo | |
echo " Get help about one of the subcommands" | |
;; | |
pubkey-from-github) | |
echo "Usage: $0 ${COMMAND} [github-username-1 github-username-2 ...]" | |
echo | |
echo " Fetch the public key(s) from a user on github, these can be used to encrypt messages intended for that user." | |
;; | |
encrypt) | |
echo "Usage: $0 ${COMMAND} <pubkey-1 pubkey-2 ...> < file > file.enc.tar" | |
echo | |
echo " Encrypts a message or file on stdin, and writes encrypted bundle to stdout." | |
echo " the bundle can be decrypted with decrypt." | |
echo | |
echo "Arguments:" | |
echo " pubkey-n The public key(s) of your intended recipient(s)" | |
echo " can often be obtained through github with pubkey-from-github command" | |
echo " e.g. $0 ${command} \<($0 pubkey-from-github username) < file > file.enc.tar" | |
echo | |
echo "Details:" | |
echo " The bundle contains a symetric decryption key for the message, and" | |
echo " the key encrypted using all provided public keys." | |
;; | |
decrypt) | |
echo "Usage: $0 ${COMMAND} [privkey] < file.enc.tar > file" | |
echo | |
echo " Decrypts an encrypted bundle from stdin (created with encrypt), and writes" | |
echo " decrypted message/file to stdout." | |
echo | |
echo "Arguments:" | |
echo " privkey The private key of the public key used to encrypt the message." | |
echo " defaults to ~/.ssh/id_rsa" | |
;; | |
encrypt-short) | |
echo "Usage: $0 ${COMMAND} <pubkey> < file > file.enc" | |
echo | |
echo " Encrypts a message on stdin, and writes encrypted message to stdout." | |
echo | |
echo "Arguments:" | |
echo " pubkey The public key of your intended recipient. Since users can have multiple" | |
echo " public keys on github, you should prefer encrypt unless you have their pubkey." | |
echo | |
echo "Details:" | |
echo " This uses the keys directly without a intermediary key, this means only one public key" | |
echo " can be used, and the message should not be too large." | |
;; | |
decrypt-short) | |
echo "Usage: $0 ${COMMAND} [privkey] < file.enc.tar > file" | |
echo | |
echo " Decrypts an encrypted message from stdin (created with encrypt-short), and writes" | |
echo " decrypted message to stdout." | |
echo | |
echo "Arguments:" | |
echo " privkey The private key of the public key used to encrypt the message." | |
echo " defaults to ~/.ssh/id_rsa" | |
;; | |
*) | |
echo "Usage: $0 COMMAND [ARGS]..." | |
echo | |
echo " Use ssh keys & github for quick and easy crypto." | |
echo | |
echo "Commands:" | |
echo " help Get help about one of the commands." | |
echo " pubkey-from-github Fetch the public key of a user on github for message encryption." | |
echo " encrypt Encryption a message or file, decryptable by your specified recipient(s)." | |
echo " decrypt Decrypt a message or file sent to you." | |
echo " encrypt-short Encryption a short message, decryptable by your specified recipient." | |
echo " decrypt-short Decrypt a short message sent to you." | |
;; | |
esac | |
} | |
# This ensures the private key is available in pem format | |
_ensure_privkey_pem() { | |
privkey="$1" | |
if [[ -z "${privkey}" ]]; then | |
privkey="$HOME/.ssh/id_rsa" | |
fi | |
if [[ "$(basename ${privkey} .key)" == "$(basename ${privkey})" ]]; then | |
if [[ ! -e "${privkey}.key" ]]; then | |
echo "creating openssl compatible key file from ${privkey}..." >> /dev/stderr | |
cp "${privkey}" "${privkey}.key" | |
ssh-keygen -f "${privkey}.key" -p -m pem | |
fi | |
privkey="${privkey}.key" | |
fi | |
echo "${privkey}" | |
} | |
# This extracts pubkeys from github for user(s) | |
pubkey_from_github() { | |
if [[ -z "$1" ]]; then | |
echo "Missing username argument" >> /dev/stderr; | |
return 1; | |
fi | |
while [[ ! -z "$1" ]]; do | |
pubkeys="$(curl -s https://github.com/$1.keys)" | |
if [[ -z "${pubkeys}" ]]; then | |
echo "$1 has no public keys" >> /dev/stderr; | |
return 1; | |
fi; | |
if [[ "${pubkeys}" == "Not Found" ]]; then | |
echo "$1 was not found on github" >> /dev/stderr; | |
return 1; | |
fi; | |
echo "${pubkeys}" | |
shift; | |
done | |
} | |
# encrypt a file with an intermediary key, store the encrypted key & message in a tarball. Encrypted key | |
# is encrypted using any/all pubkeys provided, allowing you to send to multiple recipients or simply a user | |
# with multiple public keys | |
encrypt_full() { | |
pubkeys="$1" | |
if [[ -z "${pubkeys}" ]]; then | |
echo "Missing pubkeys argument" | |
return 1 | |
fi | |
tmpdir="$(mktemp -d)" | |
openssl rand -base64 -out "${tmpdir}/key" 32 | |
let n=0 | |
echo "${pubkeys}" | while IFS= read -r pubkey; do | |
echo "encrypting key-${n}" >> /dev/stderr; | |
ssh-keygen -f <(echo "${pubkey}") -e -m pkcs8 > "${tmpdir}/${n}.pkcs8.pub"; | |
openssl rsautl -encrypt -pubin -inkey "${tmpdir}/${n}.pkcs8.pub" -in "${tmpdir}/key" -out "${tmpdir}/key-${n}.enc"; | |
let n="$n+1"; | |
done | |
echo "encrypting message" >> /dev/stderr; | |
openssl enc -aes-256-cbc -pbkdf2 -iter 100000 -salt -in - -out "${tmpdir}/message.enc" -pass file:"${tmpdir}/key" | |
echo "bundling..." >> /dev/stderr; | |
cwd=$(pwd); cd "${tmpdir}"; tar cf - key-*.enc message.enc; cd "${cwd}" | |
rm -r "${tmpdir}" | |
} | |
# decrypt a file which was encrypted with encrypt_full, attempt to decrypt the intermediary key(s) | |
# the an ssh private key, if successful, use that key to decrypt the message. | |
decrypt_full() { | |
privkey="$(_ensure_privkey_pem $1)" | |
tmpdir="$(mktemp -d)" | |
tar xf - -C "${tmpdir}" | |
ls "${tmpdir}"/key-*.enc | while read keyfile_enc; do | |
openssl rsautl -decrypt -inkey "${privkey}" -in "${keyfile_enc}" -out "${tmpdir}/key" 2> /dev/null; | |
if [[ "$?" -eq 0 ]]; then | |
break; | |
fi; | |
done | |
if [[ ! -e "${tmpdir}/key" ]]; then | |
echo "Failed to decrypt keyfile" >> /dev/stderr; | |
rm -r "${tmpdir}" | |
return 1 | |
else | |
openssl enc -d -aes-256-cbc -pbkdf2 -iter 100000 -in "${tmpdir}/message.enc" -out - -pass file:"${tmpdir}/key" | |
rm -r "${tmpdir}" | |
fi | |
} | |
# encrypt a small snippet with a ssh public key | |
encrypt_short() { | |
pubkey=$1 | |
if [[ -z "${pubkey}" ]]; then | |
echo "Missing pubkey argument" >> /dev/stderr | |
return 1 | |
fi | |
openssl rsautl -encrypt -pubin -inkey <(ssh-keygen -f ${pubkey} -e -m pkcs8) -pubin -in - -out - | base64 | |
} | |
# decrypt a small snippet with a ssh private key | |
decrypt_short() { | |
privkey="$(_ensure_privkey_pem $1)" | |
base64 -d | openssl rsautl -decrypt -inkey ${privkey} -in - -out - | |
} | |
COMMAND="$1" | |
shift | |
OPT="$1" | |
if [[ "${OPT}" == "-h" || "${OPT}" == "--help" ]]; then | |
shift | |
set -- "${COMMAND}" "$@" | |
COMMAND="help" | |
fi | |
case "${COMMAND}" in | |
pubkey-from-github) | |
pubkey_from_github $* | |
;; | |
encrypt) | |
encrypt_full $* | |
;; | |
decrypt) | |
decrypt_full $* | |
;; | |
encrypt-short) | |
encrypt_short $* | |
;; | |
decrypt-short) | |
decrypt_short $* | |
;; | |
help) | |
_help $* | |
;; | |
*) | |
_help | |
exit 2 | |
;; | |
esac |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment