Since it is not possible to rely on the encryption that is provided for us in our daily applications (email, chat, etc), so, I decide to create this method as an alternative to quickly send sensitive data through current chat applications, email, etc.
Using openssl in both sides (the sender and the receiver) is possible to exchange encrypted messages using our preffered chat application. In this process, I tied receiver's github account with his SSH public key, that way we can believe a little bit more if the receiver is who we think he is.
Generally all the bellow checks are OK for MacOS/Linux and you can just go to the Communicating session and start playing. If you have problems, then Solving Problems session is your friend.
-
Check if the receiver has a RSA key pair.
Solution: if not, check bellow how to deal with that.
-
Check if the receiver has a github account.
Solution: if not, ask him to create it.
-
Check if the receiver already have his SSH public key configured in his github account.
Solution: if not, ask him to add it.
-
Check if the receiver has the private key that originated his github SSH public key in the machine he will read the encrypted message.
Solution: if not, ask him to provide it.
-
Check if the receiver private key does not begins with "BEGIN OPENSSH PRIVATE KEY"
Solution: if not, check bellow how to deal with that.
-
Check if the receiver is able to execute openssl in his machine's terminal.
Solution: if not, check bellow how to deal with that.
In this session we see how to send / receive messages.
Now create a script called openssl-messenger.sh in the sender machine:
#!/bin/bash
set -o pipefail
function helprouter {
type=$1
msg=$2
case $type in
selectKey)
echo "This github account has more than one ssh public key."
echo
echo "$msg"
echo
echo "to send a message to him, you need to choose just one his ssh public keys."
echo "Select the last 7 bytes of one of his keys and run the script again like this:"
echo "$0 <github account>[:<sshkeylast7bytes>] <message>"
;;
selectedKeyDoesNotExist)
echo "the key you informed is not among the receiver's keys. try again."
echo
echo "$msg"
echo
echo "to send a message to him, you need to choose just one his ssh public keys."
echo "Select the last 7 bytes of one of his keys and run the script again like this:"
echo "$0 <github account>[:<sshkeylast7bytes>] <message>"
;;
account)
echo "github account does not exist"
echo "$0 <githubaccount> <message>"
;;
githubkeys)
echo "this github account has no public ssh keys configured!"
;;
conversionError)
echo "problem converting receiver's SSH public key to PKCS8"
;;
encryptionError)
echo "something went wrong while encrypting the message"
;;
*)
echo "you need to add the message parameter"
echo "$0 <githubaccount> <message>"
;;
esac
exit
}
receivergithub=$1
receiverMessage=$2
if [[ -z "$receivergithub" || -z "$receiverMessage" ]]; then
helprouter
fi
githubaccount=$(echo $receivergithub | awk -F: '{print $1}')
receiverKeyendsWith=""
receiverKeyendsWith=$(echo $receivergithub | awk -F: '{print $2}')
checkIfUserHasKeys=$(curl -s -o /dev/null -w "%{http_code}\n" https://github.com/${githubaccount}.keys)
if [[ "$checkIfUserHasKeys" != "200" ]]; then
helprouter account
fi
receiverKeys=$(curl -s https://github.com/${githubaccount}.keys)
countKeys=$(echo "${receiverKeys}" | grep -c ssh-rsa)
if [[ $countKeys == 0 ]]; then
helprouter githubkeys
fi
if [[ $countKeys > 1 && -z "$receiverKeyendsWith" ]]; then
helprouter selectKey "$receiverKeys"
fi
receiverSelectedKey=$(echo "$receiverKeys" | egrep "${receiverKeyendsWith}$")
ret=$?
if [[ $ret != 0 ]]; then
helprouter selectedKeyDoesNotExist "$receiverKeys"
fi
receiverkeytoPKCS8=$(ssh-keygen -e -m PKCS8 -f <(echo "$receiverSelectedKey"))
ret=$?
if [[ $ret != 0 ]]; then
helprouter conversionError
fi
toClipBoard=$(echo echo "$( echo "$receiverMessage" | \
openssl rsautl -encrypt -inkey <(echo "$receiverkeytoPKCS8") -pubin | \
openssl enc -base64 -A) | \
base64 -D | openssl rsautl -decrypt -inkey ~/.ssh/id_rsa")
ret=$?
if [[ $ret != 0 ]]; then
helprouter encryptionError
fi
echo command sent to clipboard:
echo $toClipBoard
# if you dont have pbcopy in your machine, then ignore this one and do the copy&paste manually.
echo $toClipBoard | pbcopy
#end
Exemple of execution
$ ./openssl-messenger.sh gsilos "
> hello=world
> message=secret
> "
command sent to clipboard:
echo TbZB5cUpF3wNBNyzo0q11RBqbNegqnn0zpPTFc1Q2gvzFNgQaznrYCrcUTpx+rv3t/UtJS6ao1lmERKkCHu+PE7ABtkFxCVsnU6mBF6LTro8aUd03ScyOhvyQ6oKeFdULlIX3c+MOoI3W0qjBb8wi0iuFQr+SBTDvV0zaRBNYIKAGqZ5ptRJyY3ncuchykVursZ1Q7wVWjPS488SWnc8/QoFt5grr7zG1rf+7lt2SgsBZ2QPpV10CmU6dyRovwJXaR0SNAvtwzEEo7FUrRpyOddW1r8b/FS+78BvZowi4mer1OV3CuJTv1pK3Kf6aa7yqnJHP/EjLaL0SxRemOYZQA== | base64 -D | openssl rsautl -decrypt -inkey ~/.ssh/id_rsa
Note: in the above example I showed how to send a message breaking lines.
Then, open your chat with the receiver (slack, telegram, skype, whatever) , copy the output of the script (the line bellow "command sent to clipboard) into your counterpart's chat and ask his to execute it in his terminal for him to see the message (or just type CTRL+V in his chat).
Assuming receiver has his private key under ~/.ssh/id_rsa, then just execute the command the sender send to him and he will be able to see what is in the message.
Example:
$ echo TbZB5cUpF3wNBNyzo0q11RBqbNegqnn0zpPTFc1Q2gvzFNgQaznrYCrcUTpx+rv3t/UtJS6ao1lmERKkCHu+PE7ABtkFxCVsnU6mBF6LTro8aUd03ScyOhvyQ6oKeFdULlIX3c+MOoI3W0qjBb8wi0iuFQr+SBTDvV0zaRBNYIKAGqZ5ptRJyY3ncuchykVursZ1Q7wVWjPS488SWnc8/QoFt5grr7zG1rf+7lt2SgsBZ2QPpV10CmU6dyRovwJXaR0SNAvtwzEEo7FUrRpyOddW1r8b/FS+78BvZowi4mer1OV3CuJTv1pK3Kf6aa7yqnJHP/EjLaL0SxRemOYZQA== | base64 -D | openssl rsautl -decrypt -inkey ~/.ssh/id_rsa
hello=world
message=secret
To check if the receiver's private key does not begins with "BEGIN OPENSSH PRIVATE KEY", the receiver need to execute:
head -1 ~/.ssh/id_rsa
Note: assuming the receiver's private key is in ~/.ssh/id_rsa
If the receiver's private key begins with "BEGIN OPENSSH PRIVATE KEY", then he needs to convert his private key to RSA format in order to be able to decrypt the messages.
The bellow command will do the conversion. By doing that his private key will be still tied to his existing public key. Anyways, if he is not confortable executing the bellow command, just do a backup before converting it. To convert, execute:
ssh-keygen -p -m PEM -f ~/.ssh/id_rsa
PS: if his private key has a password in it, he will need his password the password to do that. if the receiver does not use password for his private key, then no password is needed and the conversion will be done by ssh-keygen.
If the receiver does not have a RSA private key and a SSH public key yet, then he can create one using these commands:
openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:4096 -out ~/.ssh/mykey.pri
chmod 0600 ~/.ssh/mykey.pri
ssh-keygen -y -f ~/.ssh/mykey.pri > ~/.ssh/mykey.pub
then add ~/.ssh/mykey.pub to the receiver's github account under http://github.com/settings/ssh
If the receiver does not have openssl in his machine, he can install it using brew install openssl
if he uses MacOS or he can try to check how to do that in his own operating system.
I tested communicating using my RSA key that has 4096 bits in it and I was able to send messages of 501 bytes. If the RSA private key has 2048 bits, then it is possible to send a maximum of 248 bytes. When the limit is reached, openssl an error like:
140735827354568:error:0406D06E:rsa routines:RSA_padding_add_PKCS1_type_2:data too large for key size:rsa_pk1.c:174:
The script implemented here supports only ssh-rsa public key algorithm, but you can change it to implement other public key algorithms, for example dsa
or ecdsa
or ed25519
. Of course each of these algorithms will impose different limitations in the message size.
By default, when a encryption is made using the script, it will generate a command to decrypt that works on MacOS. To make it work in linux for example, just adjust the decryption command to execute "base64 -d" instead of "base64 -D". I tried to not use this decoder because the usage differs between linux and macos, but this decoder is the only one that works with messages that has special characters in it. The command "openssl enc -d -base64" work on both linux and mac, but in mac it will be calling the openssl binary that comes with "libressl" package, and this binary does not work well with messages that contain special characters. Example try to send "Olá" message to your self and decyrpt it with openssl from libressl - you will see an error like "Error reading input Data" when trying to use base64 decoder that comes with that openssl from libressl.