[messaging] RFC: async NaCl relay

Max Skibinsky max at skibinsky.com
Tue Dec 22 03:40:39 PST 2015

Ben, thank you for reading the doc in such great detail. all great questions.

> 1) I'd suggest simplifying the first two interactions to the following (to minimise stored state on the server)
> Alice does a GET to /sessions and receives {difficulty, verify_token}
> Alice does POST to /sessions/[verify_token] with diff_nonce if needed, and receives r_sess_pk

This is an intriguing idea. On first pass I don’t see any obvious
attack weaknesses introduced by this, will run this by Yevgeniy to
double check. I assume server verification function you meant should
be something like concat(nonce, timestamp, verify_token, HMAC(
concat(nonce, timestamp, verify_token)) ? difficulty is constant
value, so it doesn’t add much to verification. what needs to be
verified is POW nonce joining recent timestamp with given
verify_token. Relay still will need to cache verify_token while
handshake is in progress, yet that’s one token less than current

One potential issue (need to think more): now POW will be dependent on
timestamp (which can *not* be removed in this case; contrast with
current ver where client_token plays the role of static id of client
request) - at some difficulty setting weaker clients may not finish
POW in time to complete the handshake.

> 2) All of the encryption work in the second phase seems to imply you don't trust the TLS layer? Otherwise you would just send messages signed by the a_comm_pk to the server. If you really don't trust the TLS layer, you need to have the relay send a long term public key in the first message, and the client should store it and use it in key derivation (TOFU style).

I do trust TLS, but what I have doubts about is an average hobbyist
ability to configure a tight TLS deployment. Practically, there will
be two distinct use cases: “professional” relays deployed by vendors
like us, and hobbyists relay deployed for “friends and family”.

For professional deployment, TLS is fine and cert pinning should work.
Yet I prefer not to leave hobbyist self-deployment relay completely
unprotected - zax nacl-based session should provide her with a basic
level of protection.

If I understand correctly what you are suggesting:
- create long-term identity for relay itself
- let no-TLS relay owners use that identity to verify their own
self-deployed relay?
- first message from relay will be effectively an "advertisement" of
that self-made cert?

> 3) What is the reason to use H2 instead of just a single hash iteration?

afaik double hashing was created as protection against length
extension attacks. Ferguson & Schneier first suggested Hdbl(m) =
h(h(m) || m) in [1]. Yevgeniy had been researching security of such
constructs in [2] - they analyzed and proved that sha256(sha256( 0^32
|| msg)) has strong security, so we followed his recommendation.

[1] Cryptography Engineering: Design Principles and Practical Applications
[2] http://cs.nyu.edu/~dodis/ps/h-of-h.pdf

> 4) What is the reason to use the hash of the public key as the address?

Initial motivation was an excellent suggestion by Tao (thanks Greg) to
hide long term identity key from public routers/loggers that service
the request for no-TLS node. Later, we realized it brings another
interesting benefit. If endpoint secret key is compromised but keyring
with guest public keys is not recovered then attacker still can not
recover incoming messages. He will get ’from: HPK’ but has no public
keys to restore from HPKs and decrypt crypto_box. In other words if
a_comm_sk is leaked the damage is partial; full contents of keyring is
also required to read incoming communications and match identities -
zax roster of HPKs in redis (and 'from' fields in download packets)
won't help attacking these.

That opens up an interesting option for endpoints to “go dark” by
selectively or completely deleting entries from personal keyring to
protect their counter-parties.

> 5) Why use encryption of a secret as the ZKP of a_comm_pk? A signature would be the more conventional route.

That is indeed a gnarly part, good catch. Main reason is the limit of
a library we had to work with. Nacl uses different key formats for
encryption (crypto_box) and signatures (crypto_sign). We based our web
stack on nacl-js, which doesn’t yet support for conversion between
these 2 types. So the judgment call was to either create
unproven/untested code that will do sophisticated key converstion, or
accept slightly bizzare structuring of the protocol, but keep all
execution paths 100% within proven nacl functions. The latter seemed
like significantly less risky choice.

> 6) I'd suggest considering also being able to use verify_token from 1 above in the upload command (maybe as a 'fast upload' command). It simplifies dumb send-only clients (don't have an HPK, may not need asymmetric crypto implementations).

Am i undersanding correctly that “send only” client would be an
endpoint _without_ its own HPK, but who can message another HPK? Any
specific use cases for such “send only” clients? I’m a bit warry about
allowing this: if they don’t have own HPK, they are effecitively
becoming unlimited “anon” users, and zax can not verify anything about
them before accepting communications. Maybe you have specific use
cases in mind that would allow to make requirements a bit tighter and
avoid wide open case of “any anon” => HPK communications?

- max

More information about the Messaging mailing list