Interstellar-Whisper

Interstellar Whisper

Sending whispers across the interstellar space!

stellar rocket in space

This project holds the development of encrypted messaging over the distributed Stellar network.

$./whisper.py -h
     ___  .   __            .    __       ___         .
 . /  _/___  / /____ *__________/ /____  / / /___ ______ +  /\
   / // __ \/ __/ _ \/ ___/ ___/ __/ _ \/ / / __ `/ ___/  .'  '.
 _/ // / / / /_/  __/ /  (__  ) /_/  __/ / / /_/ / /     /======\
/___/_/ /_____/\___/_/  /____/\__/\___/_/_/\__,_/_/     ;:.  _   ;
| |   . / / /_  (_)________  ___  _____                 |:. (_)  |
| | /| / / __ \/ / ___/ __ \/ _ \/ ___/            +    ;:.      ;
| |/ |/ / / / / (__  ) /_/ /  __/ /                   .' \:.XLM / `.
|__/|__/_/ /_/_/____/ .___/\___/_/     .        .    / .-'':._.'`-. \
                   /_/                               |/    /||\    \|
Usage:
  whisper.py (-r [-n N] | -s MSG -a ADDR) [-k FILE] [-e ENC]
  whisper.py -h | --help
  whisper.py -v | --version

Options:
  -r            Read messages.
  -s MSG        The message text to send.
  -a ADDR       The destination address (required for sending).
  -n N          Read last N messages (optional for reading) [default: 1].
  -k FILE       Path to the file containing the password-protected stellar
                seed for your account [default: ~/.stellar/wallet].
  -e ENC        Required encoding for the message text [default: 0].
                Valid options are:
                  0 = raw (no) encoding,
                  1 = GSM 03.38 encoding,
                  2 = Sixbit ASCII encoding,
                  3 = smaz compression.
  -v --version  Display version and exit.
  -h --help     Show this screen.

Similar projects!

As a shout-out to fellow like-minded cryptonauts (is this even a word?) I’m starting with some links to similar projects that I found about recently:

It’s inspiring to see other people to come to similar ideas!

Introduction

Previous attempts at ubiquitous encryption, such as the Web of trust concepts of PGP/GPG, PKI, and DNSSEC have been (and to some extent still are) hampered by a lack of proper incentives. Security just isn’t considered a must-have in the eyes of a typical user.

For example, I still remember myself trying to use GPG with some discipline approximately 10 years ago, only to lose sync of the public keys of my contacts, and eventually losing my own keys at some point. I didn’t even bother to recover them. I had nothing to loose. My interactions continued un-encrypted. Eventually, even the most enthusiastic of my contacts gave up.

On the other hand, the idea of public-key cryptography is essentially embedded into the concept of cryptocurrencies. In simplified terms, your public key (or sometimes a hash of it, as in the case of Bitcoin) is the address, to which you can send a coin, and your secret key (which you should really never tell anyone) is the ticket that allows you to spend the coins that you own.

One of the benefits of the rise, adoption, and proliferation of cryptocurrencies is that adopters are also necessarily (stake)holders of their cryptographic key pairs. As such, they have a direct monetary incentive to never lose their keys! Considering this, it becomes obvious that these exact same cryptographic keys could be further utilized and leveraged.

In this project I propose using cryptocurrency keys for highly secure, persistent, and resilient messaging. What features do we gain by sending messages over cryptocurrency networks?

A break of any of the above would at the same time mean a break of the underlying cryptography, breaking the network itself. As such, cryptocurrencies will continue to evolve towards more secure algorithms when security margin become too low.

Using the distributed Stellar network as a vehicle for transporting messages

From the various cryptocurrencies that I am familiar with, I could not find a better candidate than Stellar (XLM) for this project.

Stellar has one of the best developer ecosystems that I have looked at. There are official SDK libraries available for Java, JavaScript, Ruby and Go with excellent documentation. Further community SDKs for Python, C#, and C++ are also available.

Transactions are also very fast (resolve in 2 - 5 seconds) and cheap (100 stroops ~ 0.000003 USD at the time of writing). Decentralization and the size of the network continue to increase and there is currently no end in sight. But the most important criterion is, in my opinion, the open-mindedness of the Stellar Development Foundation.

Proposed protocol

Prior to messaging, Alice and Bob convert their Ed25519 Elliptic Curve keys, corresponding to Stellar’s private seed and public address, to Curve25519 keys which will allow them to perform Elliptic Curve Diffie-Hellman exchange according to the rules of X25519.

Let’s call these Curve25519 keys sk_Bob, pk_Bob, sk_Alice, and pk_Alice.

Scenario: Bob sends a message to Alice

Step 1: Diffie-Hellman

Bob calculates the shared secret by using his secret key and Alice’s public key using the ECDH algorithm. Alice does the same calculation using her secret key and Bob’s public key. Let’s call this shared 256-bit secret value k,

k = ECDH(pk_Alice, sk_Bob) = ECDH(pk_Bob, sk_Alice)

Step 2: Message encapsulation

The encapsulation is easiest to describe on an example. Imagine wanting to transmit a 46 byte long payload. The payload itself is a suitably encoded plaintext message or a small file that Bob wants to transmit.

|0                  |10                 |20                 |30                 |40
|0 1 2 3 4 5 6 7 8 9|0 1 2 3 4 5 6 7 8 9|0 1 2 3 4 5 6 7 8 9|0 1 2 3 4 5 6 7 8 9|0 1 2 3 4 5 6
┌─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┐
| Payload                                                                            46 bytes |
└─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┘
  1. The first step of encapsulation is to split the payload into fragments of maximum length of 31 bytes, resulting in two fragments of lengths of 31 and 15.

    |0                  |10                 |20                 |30
    |0 1 2 3 4 5 6 7 8 9|0 1 2 3 4 5 6 7 8 9|0 1 2 3 4 5 6 7 8 9|0
    ┌─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┐
    | Fragment 1                                         31 bytes |
    └─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┘
    ┌─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┐
    | Fragment 2           15 bytes |
    └─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┘
    
  2. Next, a 1 byte header H is attached to each fragment

    |0                  |10                 |20                 |30
    |0 1 2 3 4 5 6 7 8 9|0 1 2 3 4 5 6 7 8 9|0 1 2 3 4 5 6 7 8 9|0 1
    ┌─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┐
    |H| Fragment 1                                1 + 31 = 32 bytes |
    └─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┘
    ┌─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┐
    |H| Fragment 2  1 + 15 = 16 bytes |
    └─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┘
    

The 8 bits of the header depend on the length L of the fragment (encoded in bits 0 - 4) and on the encoding E of the payload (encoded in bits 5 - 7). The fragment length is encoded in the header in the following way:

Length (L) Header bits 0-4 Description
1 … 31 00001 … 11111 Last fragment of the payload of size L
0 00000 Full-size fragment, payload continues in the next fragment

The next 3 bits of the header encode the encoding:

Header bits 5-7 Content Description Symbol rate
000 binary no encoding, raw 8-bit 31 B / fragment
001 SMS TEXT GSM 03.38 charset 35 characters / fragment
010 restricted uppercase TEXT Sixbit ASCII 41 characters / fragment
011 TEXT smaz/smac compression ~ 31 - 60 B / fragment
100 RESERVED for future use    
101 RESERVED for future use    
110 RESERVED for future use    
111 RESERVED for future use    

For instance, the headers of fragments of the above hypothetical 46 B compression-encoded payload look like this:

  |0 1 2 3 4|5 6 7|
  ┌─┬─┬─┬─┬─┬─┬─┬─┐
  |0 0 0 0 0|0 1 1|    header of Fragment 1
  └─┴─┴─┴─┴─┴─┴─┴─┘
  ┌─┬─┬─┬─┬─┬─┬─┬─┐
  |0 1 1 1 1|0 1 1|    header of Fragment 2
  └─┴─┴─┴─┴─┴─┴─┴─┘

The combination of the header and the fragment will be called a block.

Step 3: Encryption

Step 4: Sending the message

The encrypted blocks c_i are set to the 32 byte MEMO_HASH field of the Stellar transaction object. A payment transaction is constructed (e.g. using the 0.0000001 XLM minimum amount). The total cost in this case will be 0.00000101 XLM per fragment (the total cost is the sum of the transaction fee and the payment amount). The transactions for all message fragments are executed sequentially with consecutive sequence numbers.

Step 5: Decryption, Assembly, Extraction and Decoding

Basically, for receiving the message, the corresponding inverse operations of steps 1-4 are performed at the receiving site in the opposite order: the encrypted blocks are decrypted and assembled into the payload (removing the headers and padding), and finally the payload is decoded.

Proof of concept

The application is running on TESTNET at the moment, but that can easily be switched as soon as the security measures for protecting your seed are implemented (see TODO).

Bob (identified by this address GD2TA…2TIY) can send a message to Alice (identified by this address GCU2R…7ZDH):

$./whisper.py -s "Wow! A message through Stellar!" -a GCU2RRJHYBEIP6R6SJHLTCC32FVFGATYMTYB3ZBKT3OMPZLCTVSS7ZDH -k .bob_wallet
    ____  .   __            .    __       ___         .
 . /  _/___  / /____ *__________/ /____  / / /___ ______ +  /\
   / // __ \/ __/ _ \/ ___/ ___/ __/ _ \/ / / __ `/ ___/  .'  '.
 _/ // / / / /_/  __/ /  (__  ) /_/  __/ / / /_/ / /     /======\
/___/_/ /_____/\___/_/  /____/\__/\___/_/_/\__,_/_/     ;:.  _   ;
| |   . / / /_  (_)________  ___  _____                 |:. (_)  |
| | /| / / __ \/ / ___/ __ \/ _ \/ ___/            +    ;:.      ;
| |/ |/ / / / / (__  ) /_/ /  __/ /                   .' \:.XLM / `.
|__/|__/_/ /_/_/____/ .___/\___/_/     .        .    / .-'':._.'`-. \
                   /_/                               |/    /||\    \|
Enter password:

Sending message to GCU2RRJHYBEIP6R6SJHLTCC32FVFGATYMTYB3ZBKT3OMPZLCTVSS7ZDH...  Done.

Alice can indeed read the message.

$./whisper.py -r -n 1 -k .alice_wallet
    ____  .   __            .    __       ___         .
 . /  _/___  / /____ *__________/ /____  / / /___ ______ +  /\
   / // __ \/ __/ _ \/ ___/ ___/ __/ _ \/ / / __ `/ ___/  .'  '.
 _/ // / / / /_/  __/ /  (__  ) /_/  __/ / / /_/ / /     /======\
/___/_/ /_____/\___/_/  /____/\__/\___/_/_/\__,_/_/     ;:.  _   ;
| |   . / / /_  (_)________  ___  _____                 |:. (_)  |
| | /| / / __ \/ / ___/ __ \/ _ \/ ___/            +    ;:.      ;
| |/ |/ / / / / (__  ) /_/ /  __/ /                   .' \:.XLM / `.
|__/|__/_/ /_/_/____/ .___/\___/_/     .        .    / .-'':._.'`-. \
                   /_/                               |/    /||\    \|
Enter password:

Date        From            Message
2018-04-24  GD2TA2JCQTM6…   Wow! A message through Stellar!

Note: If you want to play around in the TESTNET using these two demo accounts, the password of both wallet files is aaaa1111, which is something one can reasonably quickly type during testing.

Requirements

The code is written in Python 3. You need the following python packages (install them with pip):

TODO