Created
November 2, 2017 15:57
-
-
Save brianoflan/2d0d80034d9281441d27af5bea9ac49d to your computer and use it in GitHub Desktop.
Encrypt and decrypt short strings with the user's default SSH key pair
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 | |
# Encrypts and decrypts short strings with the user's default SSH key pair. | |
# USAGE: | |
# encrypt file: cat some_short_file.txt | encrypt_str | |
# encrypt variable: echo "$some_variable" | encrypt_str | |
# decrypt file: cat something.encrypted | decrypt_str | |
# decrypt variable: echo "$string" | decrypt_str | |
# | |
# # Arguments instead of pipes/STDIN: | |
# encrypt string: encrypt_str 'some short string' | |
# encrypt variable: encrypt_str "$some_variable" | |
# decrypt variable: decrypt_str "$some_variable" | |
# | |
# # Advanced: | |
# export my_encrypted_password='Pb59O+X/A...JQl=' # Note the ellipsis. | |
# decrypt variable: echo "$my_encrypted_password" | decrypt_str | |
# decrypt string: echo Pb59O+X/A...JQl= | decrypt_str | |
# # Encrypted strings are base64-encoded jumbles that are usually much | |
# # longer than the input string (which is always the size of the private key, | |
# # increased according to the 4/3 base64 ratio). | |
# DETAILS: | |
# Using the default ~/.ssh/id_rsa[.pub] key pair to encrypt and decrypt small | |
# strings is quick and easy, uses a cryptographic resource most people already | |
# have (their own SSH keys). The length of the plaintext string that can be | |
# encrypted is limited by the size of the private key and the nature of the | |
# "openssl rsautl" tool: A string may be 83 characters long (for 1024 bits) | |
# - or up to 481 characters long (for a 4096 bit private key). | |
# Not for long strings: Use "openssl smime" with a cert (which can be | |
# generated from your SSH keypair if you want something convenient). | |
# DETAILS ABOUT THE INPUT TO "encrypt_str()": | |
# | |
# NOTE: About command line arguments: It is best to pass input to encrypt_str | |
# via STDIN (just pipe it in, eg. "echo 'some short string' | encrypt_str"). | |
# It is possible to pass input to encrypt_str as a command line argument ($1) | |
# and this case takes precedence over STDIN (eg. | |
# "echo 'some string' | encrypt_str 'another'" | |
# will encrypt 'another', not 'some string'). | |
# CAVEAT: If using a command line argument to encrypt a string with whitespace | |
# or any characters outside the small, usual set of English keyboard | |
# alphanumerics and simple punctuation, the string should be quoted (and, if | |
# necessary, escaped) as the first and only argument. All arguments, including | |
# the first argument and any following ones are smooshing into one single | |
# string via "$*". This may cause data corruption if there is contiguous | |
# whitespace in an unquoted/unescaped clump of arguments (whitespace would be | |
# considered an argument delimiter - and "$*" will truncate any length of | |
# whitespace into a single \x20 space character). Example: | |
# "encrypt_str my long string with contiguous spaces" | |
# will actually encrypt 'my long string with contiguous spaces' (single space | |
# between each word), not the actual intended input. | |
# DESIGN DECISION: Regarding the case in which a user insists on using command | |
# line args instead of STDIN to input a string that includes plural whitespace | |
# that should be preserved - but is not quoted: this case seems sufficiently | |
# unlikely that I have kept "$*" instead of just forcing "$1" and throwing an | |
# error if $2 is defined. This system is designed for short, simple strings | |
# and STDIN or well-quoted command line arguments are adequate to preserve | |
# special and unexpected characters. | |
get_domain() { | |
local shost=$(hostname -s) | |
local fqdn=$(hostname -f) | |
[[ $shost != $fqdn ]] || fqdn=$(host $(hostname) | awk '{print $1}') | |
echo "$fqdn" | cut -d. -f2- | |
} | |
ensure_ssh_priv() { | |
local d="$HOME/.ssh" | |
local f="$d/id_rsa" | |
[[ -f "$f" ]] || { | |
[[ -d "$d" ]] || mkdir -p "$d" | |
chmod go-w $(dirname $d) | |
chmod go-rwx "$d" "$d/" | |
ssh-keygen -t rsa -b 4096 -f "$f" -N '' -C "$(id -un)@$(get_domain)" | |
} | |
} | |
ensure_ssh_pub() { | |
local f="$HOME/.ssh/id_rsa" | |
[[ -f "$f.pub" ]] || { | |
ensure_ssh_priv 1>&2 | |
ssh-keygen -y -f "$f" > "$f.pub" | |
} | |
} | |
ensure_ssh_pkcs8() { | |
local f="$HOME/.ssh/id_rsa.pub" | |
ensure_ssh_pub 1>&2 | |
[[ -f "$f.pkcs8" ]] || { | |
ssh-keygen -f "$f" -e -m PKCS8 > "$f.pkcs8" | |
} | |
} | |
_encrypt_str() { | |
local str=$1 | |
ensure_ssh_pkcs8 1>&2 | |
echo "$str" | openssl rsautl -encrypt \ | |
-pubin -ssl -inkey "$HOME/.ssh/id_rsa.pub.pkcs8" \ | |
| base64 | |
} | |
encrypt_str() { | |
local result='' | |
local str="$*" | |
if [[ -z $str ]] ; then | |
# read str; | |
str='' | |
local l='' | |
while read l; do | |
[[ -z $str ]] && str=$l || str=$(echo -e "$str\n$l") | |
done ; | |
_encrypt_str "$str" | |
else | |
_encrypt_str "$str" | |
fi ; | |
} | |
_base64_d() { | |
if echo MQo= | base64 -d > /dev/null 2>&1 ; then | |
if [ -z ${1+x} ] ; then | |
cat - | base64 -d | |
else | |
echo "$1" | base64 -d | |
fi ; | |
else | |
if [ -z ${1+x} ] ; then | |
cat - | base64 -D | |
else | |
echo "$1" | base64 -D | |
fi ; | |
fi ; | |
} | |
_decrypt_str() { | |
local result='' | |
ensure_ssh_priv 1>&2 | |
echo "$str" | _base64_d | openssl rsautl -decrypt -inkey "$HOME/.ssh/id_rsa" | |
} | |
decrypt_str() { | |
local result='' | |
local str="$*" | |
if [[ -z $str ]] ; then | |
# read str; | |
str='' | |
local l='' | |
while read l; do | |
[[ -z $str ]] && str=$l || str=$(echo -e "$str\n$l") | |
done ; | |
_decrypt_str "$str" | |
else | |
_decrypt_str "$str" | |
fi ; | |
} | |
# |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment