Re: [tor-dev] RFC on obfs3 pluggable transport

On Wed, Dec 12, 2012 at 03:13:59AM +0200, George Kadianakis wrote:
I'll copy tor-dev on this email, and not snip things in order that context is mostly preserved. If you think some past snippage should be restored, feel free to forward that as well.
BTW, in my first email, I had tor-assistants CCed, but you stripped it off when you replied, so I didn't add it again :)
Oops; that was unintentional. My bad. But tor-dev is better, anyway.
When Bob "does a point multiplication with Alice's public key", you mean "Bob picks a private key y, and multiplies Alice's public key by y to yield the shared secret". Note that the resulting shared secret (y times Alice's public key) will be in the same group (E or E') that Alice's public key is in. Now what does Bob send to Alice? Bob should be sending y times the generator of the group. Which group? If Bob and Alice are to agree on the shared secret, it has to be the same group Alice used. Otherwise, Alice's computation will necessarily end up different from Bob's (since they'd be in different groups) and the two secrets won't match. So in order for this protocol to work, Bob has to always choose the same group he received as a public key from Alice. But that's now a distinguisher for the protocol: if I'm watching someone I think is running an obfsproxy3 bridge, and I notice that the first 21 bytes he receives on any TCP connection always lies in the same group as the first 21 bytes he sends in response, then I can be pretty confident in my suspicion.
The big difference is that Telex uses *static* DH (and gains forward secrecy by rotating keys): the client comes pre-loaded with (rP, rP') where P and P' are generators of E and E'. The Telex client then randomly picks Q to be either P or P', and randomly picks s, and sends sQ. The Telex station then can tell which group sQ is in, and multiply sQ by r. Conversely, the client uses whichever of rP and rP' corresponds to its choice of Q, and multiplies that by s. Then the secrets match. The important distinction is that in Telex, the client *already knows one public key in each group*. In the above obfsproxy3 proposal, it does not.
I tried to find how the Telex station code does it, but I didn't manage to find the telex-relay code on the Internet :(
Indeed, I don't believe the UMich people have (yet?) published it.
Note that the above protocol assumes that p is very close to a power of 256, but that's true of the RFC 3526 groups 5 and 14 I pointed to.
Yes indeed. - Ian

Ian Goldberg <iang@cs.uwaterloo.ca> writes:
Sounds good. Hey tor-dev, if anyone is interested in the snipped parts of the discussion, send me an email and I will forward them.
Oh you are right. Got it now. Thanks!
Right. The only issue with your trick, is that I'm not looking forward implementing a custom DH key exchange in Python (especially the DH parameter generation and public key validation parts). My current plan is to do some reading and thinking on other key-exchange schemes that might look uniformly random on the wire, and if I can't come up with anything I will start thinking of an implementation plan for your DH over Z_p idea. Thanks!

On Wed, Dec 12, 2012 at 04:52:11AM +0200, George Kadianakis wrote:
You're in luck! You don't get to implement any of those parts! ;-) Write a class UniformDH that has hard-coded constants p (the 1536-bit prime in group 5 of RFC 3526) and g = 2. Compute len = the number of bytes of p = 192. Its init method will pick a uniformly random len-byte string, and convert it to a long called priv. Let flip = (priv % 2) and priv -= flip (so flip is the old low bit of priv, and priv is now even for sure). Compute pub = pow(g,priv,p) and if flip == 1: pub = p - pub. Convert pub to a len-byte string and store it as pubstr. Add a method getpub() which returns pubstr. Add a method getsecret(theirpub) which converts theirpub (a len-byte string) into a long called theirpublong. Compute secret = pow(theirpublog,priv,p) and convert secret into a len-byte string and return that string. That should be it. [You can use Crypto.Util.Number.{long_to_bytes,bytes_to_long} to accomplish the conversions above, if you're allowed to use PyCrypto. For the randomness, os.urandom() is fine.] - Ian

Ian Goldberg <iang@cs.uwaterloo.ca> writes:
You are very right! RFC 3526 did the parameter generation for me, and since we are doing anonymous DH and our threat model doesn't include active attacks there is no point in doing public key validation (Initially, I was worried about attacks like Tor's CVE-2005-2643). This makes things much easier.
Many thanks for the help with the implementation! :)
- Ian

Hi all, I implemented a prototype obfs3 implementation that uses the UniformDH trick. It can be found in the `obfs3_take2` branch of https://git.torproject.org/user/asn/pyobfsproxy.git . gitweb link: https://gitweb.torproject.org/user/asn/pyobfsproxy.git/shortlog/refs/heads/o... Here is the spec and threat model: https://gitweb.torproject.org/user/asn/pyobfsproxy.git/blob/refs/heads/obfs3... https://gitweb.torproject.org/user/asn/pyobfsproxy.git/blob/refs/heads/obfs3... Here is the UniformDH implementation: https://gitweb.torproject.org/user/asn/pyobfsproxy.git/blob/refs/heads/obfs3... https://gitweb.torproject.org/user/asn/pyobfsproxy.git/blob/refs/heads/obfs3... Here is the obfs3 implementation: https://gitweb.torproject.org/user/asn/pyobfsproxy.git/blob/refs/heads/obfs3... My plan is to merge this to master in some days (after it has got more reviewing and testing). Thanks!
participants (2)
-
George Kadianakis
-
Ian Goldberg