mumble-voip / mumble

Mumble is an open-source, low-latency, high quality voice chat software.
https://www.mumble.info
Other
6.28k stars 1.11k forks source link

Update/clarify encryption implementation documentation #3487

Open ianling opened 6 years ago

ianling commented 6 years ago

This page from Read the Docs details the format of the UDP ping packet: https://mumble-protocol.readthedocs.io/en/latest/voice_data.html#ping-packet

Further down on the page, it mentions that the UDP channel uses OCB-AES128 encryption. The key and nonces used are provided by the server in the CryptSetup message: https://github.com/mumble-voip/mumble/blob/master/src/Mumble.proto#L363

There is no documentation for if/how the nonce/IV is modified between requests, or if/how the IV is prepended to UDP packets.

From looking at a packet capture of UDP traffic between a Mumble client and Murmur, I can see that there is a single incrementing byte at the beginning of every UDP packet. This isn't mentioned in any documentation.

One major feature of OCB-AES is support for verifying the integrity of the ciphertext using a header and tag. Are these features used at all in Mumble? If so, what should the values be?

Can anyone explain in more detail exactly how the encryption process is implemented in the Mumble protocol?

ianling commented 5 years ago

Is there any documentation of how this is set up?

EP-u-NW commented 4 years ago

Also, which version of OCB is used? I would assume that OCB3 is used, since its the most recent version, but thats just guessing...

Krzmbrzl commented 4 years ago

@EPNW no we are not using OCB3. I don't have a clue about the whole encryption-stuff (for details you'ds have to ask @davidebeatrici) but you can have a look at #3918. Maybe what you find there will be enough to answer your question...

@davidebeatrici as I don't know my way around the encryption stuff could you have a look at the initial post and check that the linked documentation does contain the requested information? Once it does could you please close this issue? :)

EP-u-NW commented 4 years ago

Thank you! My first though after reading #3918 was, that the first version of OCB was used. But then I started looking at the source of Grumble which seem to use "OCB2-AES128". Maybe @mkrautz can clarify why grumble uses this?

Krzmbrzl commented 4 years ago

AFAIK Mkrautz is currently busy doing life, so it will probably take (quite) a while until you get an answer from him :)

ianling commented 4 years ago

@EPNW -- I went through a few different Python encryption libraries trying to find one with a compatible OCB-AES implementation, but I could not get any of them to work with Mumble's implementation. In other words, Mumble could not decrypt my data, and I could not decrypt data coming from Mumble.

When I was trying to implement encryption in my Python Mumble client, I ended up basically just converting the C++ implementation to Python line by line and it worked fine: https://github.com/ianling/mumpy/blob/dev/mumpy/mumblecrypto.py

This leads me to believe that Mumble's implementation of OCB or AES may be incorrect. Grumble appears to implement the encryption in the same way: https://github.com/mumble-voip/grumble/blob/bbb589fb37cc21819834820c7b54665937203d26/pkg/cryptstate/ocb2/ocb2.go

Anyway, I have had a rough draft of a large blog post detailing my experience creating a Mumble client in Python mostly ready to go for over a year now that contains all of the details about how the encryption stuff is handled, just haven't gotten around to posting it. I will try to get that posted soon and then maybe I can try updating this official documentation myself.

Krzmbrzl commented 4 years ago

@ianling from where did you overtake the encryption implementation? Aka where in Mumble's source code is this implemented?

ianling commented 4 years ago

It is implemented here in the official Mumble client: https://github.com/mumble-voip/mumble/blob/c2469ac29cc9761b8d90de958ab37573858db272/src/CryptState.cpp

Krzmbrzl commented 4 years ago

Thanks! :)

EP-u-NW commented 4 years ago

@ianling Thank you! I would be nice if you could post the link here once you published your post, I'm currently working on a dart implementation of mumble and might learn a thing our two from you. Btw what algorithms have you testet? All three variants of OCB?

Johni0702 commented 4 years ago

This leads me to believe that Mumble's implementation of OCB or AES may be incorrect.

I don't think it is. I've tested my implementation against the test vectors from the OCB2 spec and it also works fine with the official mumble server. Afaik Mumble uses OCB2-AES128 (only notable thing is that it doesn't use OCB2's authenticated header feature). IIRC I even implemented my OCB2 primitives based on the spec, only looking at mumble for how it's dealing with the header, nonce, tag, etc. (i.e. this part).

To put it into words: The encrypt/decrypt nonce is incremented by one before each packet is encoded (for the purpose of incrementing, it is treated as little-endian). The first byte of an outgoing encrypted voice packet is the LSB (i.e. the first one / the one you definitely change with each packet) of the encrypt nonce. The receiving end has to infer the remaining 120 bits based on previously received packets (hence why the decrypt method is much more complicated than the encrypt method and also why a resync may be necessary if too many packets are lost). The next three bytes are the first three bytes of the tag which OCB2 produced. The remainder is the original voice packet encrypted with OCB2-AES128 where

(the letters I'm referring to are the inputs to OCB-ENCRYPT on page 6 of https://web.cs.ucdavis.edu/~rogaway/papers/draft-krovetz-ocb-00.txt).

ianling commented 4 years ago

@Johni0702 thanks for your input, I should probably not draw conclusions without doing more testing. It's definitely possible that I was just using the encryption libraries improperly.

EP-u-NW commented 4 years ago

So just to be sure: To decrypt a message from the server, I update my nonce with the first byte of the message (also taking care of out-of-order delivery), then decrypt the message starting at the fifth byte. If the first three bytes of the tag ocb2 produces macthes bytes two, three and four of the received message, everything is fine?

I implemented this but it does not seem to work... I successfully testet my encryption and decryption against the test vectors @Johni0702 mentioned. And since mumble is responding to my udp packages I assume that my encoding (encryption + prefixing bytes) of the messages I send is correct. But the resulting tags of my decryption using the method above never equal the tags in the received message. Is my understaning of the method wrong?

Johni0702 commented 4 years ago

@EPNW Your description sounds correct. Make sure that you're using the correct nonce and that you're correctly updating it, i.e. treating it as little-endian and handling roll over (though even if you didn't handle roll over, unless you're very unlucky, you should still be able to decrypt the first few packets).

If your encryption method is working (and mumble isn't just responding randomly), you can test your implementation against itself, since they're essentially supposed to be the inverse of each other, it should be relatively easy to figure out where it's going wrong.

streaps commented 4 years ago

That OCB2 is used is still not mentioned in the protocol documentation. No wonder most client libraries support TCP tunnelling only.

Krzmbrzl commented 4 years ago

@streaps could you consider updating the docs in the mumble-protocol repository? I think the relevant file is probably this one: https://github.com/mumble-voip/mumble-protocol/blob/master/establishing_connection.rst