AnemoneLabs / unmessage

Privacy enhanced instant messenger
GNU General Public License v3.0
42 stars 7 forks source link

Support voice conversations #13

Open felipedau opened 7 years ago

felipedau commented 7 years ago

As requested by @rxcomm in previous discussions and @HulaHoopWhonix in #5, unMessage should allow users to do voice chat. This is related to #11 and some structure or a VoiceElement class should be used.

@HulaHoopWhonix also suggested to use "TCP latency tolerant codecs like those in mumble".

It will be interesting to see how this feature behaves with Tor's latency.

rxcomm commented 7 years ago

I took a look at the Mumble codecs - celt, speex, and vorbis have all been superceded by opus. So it's pretty clear that is the one to use.

I've got a simple audio chat client running over tor using the opus codec. Including symmetric encryption of the payloads (same key, not ephemeral), the latencies are ~200-300 ms. Not bad! Codec parameters are: 48000 samples/sec with 16 bit samples, 20msec packets (payload 128 bytes each, total encrypted packet size 168 bytes), single-channel.

The audio is very good. We could probably tune the codec params to reduce the bandwidth requirements (8.4 kbytes/sec encrypted) if we need to, although from my testing things seem to work fine with the above params. Obviously, that will be circuit-dependent to a certain extent.

I'm not aware of any other real-time audio chat clients running over tor. This could be a big enhancement for unMessage. It shouldn't be too hard to integrate ;)

HulaHoopWhonix commented 7 years ago

Thats incredible :)

I also like Opus its modern and also seems to be coded with security in mind. That feature makes unMessage the first of its kind. Thank you!

cc/ @adrelanos

adrelanos commented 7 years ago

Sounds great!

You could also consider an option to enable push to talk walkie-talkie style. A voice messages one can sent. (Similar to WhatsApp.)

Not as a replacement for real phone calling. Just as an option for slow connections.

I mean, Tor already is slow. Phone calling might work for people having fast connections and Tor. For others on slow connections plus Tor, such a fallback mode could be neat.

We have some general advice on VoIP and anonymity in the Whonix wiki.

https://www.whonix.org/wiki/VoIP

HulaHoopWhonix commented 7 years ago

Can you please make sure Opus is only running in a constant bitrate? We know at least that ZRTP encryption cannot Protect VBR Streams as the pauses in a conversation produce fingerprints in the encrypted stream that allow the adversary to infer what words are being said.

http://zfoneproject.com/faq.html#vbr

EDIT:

Important part worth quoting that makes it clear:

It's not a problem if the codec adapts the bit rate to the available channel bandwidth. The dangerous codecs are the ones that change their bit rate depending on the type of sound being compressed.

rxcomm commented 7 years ago

Yep. That's the way I've got it implemented.

@felipedau and I are going to test a bit today. After that, if you'd like to give it a try, let me know and I can get you a tarball.

rxcomm commented 7 years ago

Tests yesterday went very well. We were able to have several ~hour-long audio conversations.

@felipedau is working on integration with unMessage now. We'll probably have a first commit to unMessage sometime tomorrow.

felipedau commented 7 years ago

Sounds great! You could also consider an option to enable push to talk walkie-talkie style. A voice messages one can sent. (Similar to WhatsApp.) Not as a replacement for real phone calling. Just as an option for slow connections. I mean, Tor already is slow. Phone calling might work for people having fast connections and Tor. For others on slow connections plus Tor, such a fallback mode could be neat. We have some general advice on VoIP and anonymity in the Whonix wiki. https://www.whonix.org/wiki/VoIP

That's a great idea @adrelanos, we should be able to implement that!

@felipedau is working on integration with unMessage now. We'll probably have a first commit to unMessage sometime tomorrow.

Well, it took longer than expected but we finally finished the integration and tested it basically every day since @rxcomm developed the first version. Unfortunately we do not have many machines to test it with different devices, so if you can, run the unMessage code from the develop branch (which is now the primary branch).

Here are some instructions to use unTalk (that's what we are calling this feature) for a fresh installation:

  1. sudo apt-get install build-essential gcc libffi-dev libopus0 libsodium-dev portaudio19-dev python-dev python-tk tor
  2. git clone https://github.com/AnemoneLabs/unmessage (It should clone the develop branch by default)
  3. sudo pip install -e unmessage/
  4. Launch unMessage with unmessage-cli -n your_peer
  5. Make sure you have a conversation with some other peer you own or someone else (Let us know if you would like to test with us so we can exchange identities)
  6. Make sure the conversation is active by either waiting for unMessage to display that the_other_peer is online (this will only work if either of the peers use /pres-on to notify their presence) or /msg them and wait for it to be delivered (A line like the_other_peer< the message you sent is displayed right below the command's echo
  7. Send a request to start a voice conversation with /untalk the_other_peer
  8. After receiving the request, the other peer should accept it with /untalk your_peer

If no errors occur and you start listening to each other: awesome!

  1. Use /untalk the_other_peer to end the voice conversation or just /quit

However, if some error occur or someone/no one seems to listen/speak, then you probably have to adjust the devices you have available. This part can be a bit tricky and we still have to find a better way to do this.

Look for default and pulse. The former is (usually) an input device and the latter an output device. Let's say that their index numbers are respectively 2 and 1:

You should be able to talk. If it does not work, you will probably have to try different combinations until you find the right one. I would make sure to restart unMessage every time you repeat the process (sorry :/). I would hate to see you spending time to make it work, so if things go wrong, please let us know so we can try to find a solution.

Once we are able to test with more devices and we are sure this new version is a bit stable, then we will merge to master, make a new release, upload to PyPI, etc.

Thank you very much guys!

felipedau commented 7 years ago

I would also like to clarify that this feature does not use ephemeral encryption. The requests do use the regular packets (ephemerally encrypted) to exchange handshake keys (short term, randomly generated every session) but each session uses a shared key to symmetrically encrypt the packets. The key is generated with Triple DH using the identity keys (longterm) and the handshake keys previously exchanged.

rxcomm commented 7 years ago

@felipedau - great job on the integration!

One additional point I could make is that if people have underrun audio errors or choppy audio, they might try starting by setting the PULSE_LATENCY_MSEC environment variable:

PULSE_LATENCY_MSEC=30 unmessage[-cli] ...

Choose a latency appropriate to your hardware. This helps with slow machines and other ideosyncracies.

rxcomm commented 7 years ago

I've created a docker image with the develop branch of unmessage. This image supports audio chat: https://github.com/rxcomm/unmessage-client/tree/master/src/unmessage-client-audio

To run the container, you first need to authenticate the docker daemon to your host's pulseaudio. To do that, run the dockerpulse.sh script: https://github.com/rxcomm/unmessage-client/blob/master/util/dockerpulse.sh

and then with the output of that script, start the container with the audio.sh script: https://github.com/rxcomm/unmessage-client/blob/master/util/audio.sh

./audio.sh <docker daemon ip> <pulseaudio port>

The dockerpulse.sh script will give you the parameters for the audio.sh script.

Example:

host_$ ./dockerpulse.sh
Configuring pulseaudio sound over tcp for docker container

Pulse port: 56272
Docker daemon: 172.17.0.1
Pulse module id: 25

Now run: ./audio.sh 172.17.0.1 56272
to start the container

To unload the pulseaudio module, run: pactl unload-module 25
host_$ ./audio.sh 172.17.0.1 56272
[sudo] password for <user>: 
Starting with UID : 1000
useradd: warning: the home directory already exists.
Not copying any file from skel directory into it.
user@6d7b62174a2c:~$ unmessage
rxcomm commented 7 years ago

unMessage requires a mono microphone. If your microphone is stereo (like mine ;), pulseaudio will map it to mono for you:

pacmd list-sources | grep name:
pacmd load-module module-remap-source master=<name of your mic here> \
    master_channel_map=front-left,front-right channels=2 channel_map=mono,mono

The name of your mic should not include the angle brackets.

To make this automatically load when pulseaudio starts, you can add the argument of the second pacmd command to either /etc/pulse/defaults.pa or ~/.config/pulse/defaults.pa.

felipedau commented 7 years ago

Thanks @rxcomm! I'll add that to the docs once I start writing instructions for unTalk.