Skip to content

Instantly share code, notes, and snippets.

@gsilos
Last active September 10, 2023 19:28
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save gsilos/734123ebac39d34a791b7a63a9a8c177 to your computer and use it in GitHub Desktop.
Save gsilos/734123ebac39d34a791b7a63a9a8c177 to your computer and use it in GitHub Desktop.
secure communication

Why?

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.

How?

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.

Before starting

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.

Communicating

In this session we see how to send / receive messages.

sending

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).

receiving

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

Solving problems

BEGIN OPENSSH PRIVATE KEY

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.

RSA Key pair

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

openssl not installed

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.

Limitations

message size

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:

public key algorithms

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.

decryption

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment