< jonasschnelli>
I think the BIP151 proposed handshake requires some overhaul
< jonasschnelli>
Non ideal is two simultaneous message push during encack
< jonasschnelli>
The current flow is...
< jonasschnelli>
1. requesting peer asks for encryption sends "encint"
< sipa>
before or after version/verack?
< jonasschnelli>
2. remote peer give its "encack",.. but then require to ask also for an "encinit" for the other-way communication (sends two messages the same time)
< jonasschnelli>
sipa: thats another topic
< jonasschnelli>
3. requesting peeer sends its "encack" and a "version" message (one unencrypted, one encrypted)
< jonasschnelli>
sipa: right now, my implementation sends it before the version... which is also not ideal.. means not really backward compatible
< sipa>
my preference would to throw it all away, and just start with a completely new protocol, not embedded in the old one; if you get disconnected when trying the encrypted proto, mark the peer as not supporting encryption, and retry another peer
< sipa>
and have a service flag for encryption
< jonasschnelli>
sipa: I came to the same conclusion...
< jonasschnelli>
But in oder to "see" the service flag, you need to talk with the legacy protocol... or do you mean more for addman/dns seeds, etc.?
< sipa>
well you learn the IP of a peer whomewhere
< sipa>
generally that somewhere has service flags
< jonasschnelli>
Yes. Right...
< sipa>
if the service flag says encryption supported, you try an encrypted connection
< jonasschnelli>
The handshake could just be a pubkey from both sides (eventually a checksum)
< jonasschnelli>
Maybe the handshake could be: (peer A) -> <pubkey|cipher|4byte_hash_checksum>, (peer B) <- <pubkey|4byte_hash_checksum>
< jonasschnelli>
sipa: for encryption both (incoming / outgoing) channel, would it make sense to do... (peer A) -> <pubkey|cipher|4byte_hash_checksum> (peer B) <- <pubkey|pubkey|4byte_hash_checksum> (peer A) -> <pubkey|cipher|4byte_hash_checksum>?
< sipa>
encryption setup can by symmetric, i think
< jonasschnelli>
sipa: you mean only one negotiation?
< sipa>
yes
< jonasschnelli>
I asked myself what the reason was for both direction encryption...
< jonasschnelli>
(two secrets)
< sipa>
for authentication it makes sense to split it up
< jonasschnelli>
yes. that is another thing..
< sipa>
also for embedding it in the old protocol, perhaps splitting up made sense
< sipa>
because you have an asynchronous thing to embed it into
< sipa>
but if there is an entirely new protocol, not so much
< jonasschnelli>
What do you mean with "asynchronous thing". The uncontrollable timing of messages?
< sipa>
yes, you need a well-identifiable point when encryption starts for both directions
< sipa>
gmaxwell: opinions?
< jonasschnelli>
Yes. That is currently a problem in the implementation
< jonasschnelli>
Currently, the second encack will enable the encryption,... since it's before the version, no other messages should interfere
< gmaxwell>
I like handshakes that just send pubkeys because they're harder to DPI match.
< jonasschnelli>
but sending the encack along with the version message (two PushMessage in the same codeblock, one plan, the other encrypted) result in things not working as it should
< jonasschnelli>
gmaxwell: but do we need two ECDH handshakes for both com directions?
< jonasschnelli>
IMHO: (peer A) -> <pubkey|cipher|4byte_hash_checksum>, (peer B) <- <pubkey|4byte_hash_checksum> should be enough and no communication should happend before this handshake is complete in the new p2p protocol
< gmaxwell>
You need one ECDH, but that requires two messages.
< gmaxwell>
why even send cipher and checksum?
< jonasschnelli>
gmaxwell: BIP151 currently require that both peers initiate a ECDH handshake. There are two secrets (one for incomming one for outgoind encryption)
< gmaxwell>
Well there is no reason to do that.
< jonasschnelli>
Okay... :/
< sipa>
in the old embedded protocol it was necessaey because it would be hard to coordinate the encryption switchover point otherwise
< sipa>
if you start with a completely new protocol i don't think there is any reason to not just do a single negotiation
< jonasschnelli>
Yes. But the question then would be, is the second encryption handshake partially encrypted since one channel is "ready"?
< gmaxwell>
You can have simply: Client connects, sends a 32 byte pubkey. Server responds with its 32 byte pubkey, and an encrypted stream.
< jonasschnelli>
gmaxwell: agree. What do you think by adding one byte for a possible cipherscheme upgrade (first message only)?
< jonasschnelli>
(peer A) -> <pubkey|cipher_1BYTE|4byte_hash_checksum>, (peer B) <- <pubkey|4byte_hash_checksum>
< jonasschnelli>
4byte checksum required? or a crc? or nothing and detect it via wrong shared secret?
< gmaxwell>
well that cipher can't be encrypted or authenticated.
< gmaxwell>
If the shared secret is wrong auth will fail on the first message. So I don't see any reason for a checksum.
< gmaxwell>
Also just sending as little as possible makes it maximally hard to DPI match the traffic.
< jonasschnelli>
Yes. Agree, a week cipher attack would be possible,.. better drop that
< gmaxwell>
Which shouldn't be a primary goal, but it's nice if we can have it for nearly free.
< jonasschnelli>
I guess DPI could identify two 33byte packages (you wrote 32byte pubkey above, incorrect?) followed by a package of "versionmessage"-length?
< gmaxwell>
jonasschnelli: we could signal ciphers, but in the server to client direction, where it could be encrypted and authenticated with the shared secret.
< gmaxwell>
it would be best to use 32 byte pubkeys, which are close to uniform. The 33 byte encoding is really identifyable.
< sipa>
jonasschnelli: just drop the 02/03 first byte of the pubkey
< sipa>
and assume it's always 02
< gmaxwell>
whats sipa says.
< jonasschnelli>
ack
< sipa>
i have a writeup on how to do ECDH over secp256k1 in a completely unidentifiable way
< sipa>
but it's pretty complicated and not worth it imho
< gmaxwell>
There are techniques to encode keys which are closer to uniform, but it's unclear if its worth the complexity.
< jonasschnelli>
derive emphemeral keys until pubkey start with 02?
< gmaxwell>
Esp since the send 32 bytes each way pattern is pretty identiable.
< sipa>
jonasschnelli: just negate your key if it has a 03 pubkey
< jonasschnelli>
ack
< sipa>
the negation will be a 02 pubkey
< gmaxwell>
jonasschnelli: if K starts with 03 then -K is the 02 version.
< jonasschnelli>
I guess that code change would belong into the secp256k1 sources?
< gmaxwell>
at least with this there are no fixed bytes to match on, which at least kills the dumbest DPI.
< gmaxwell>
in any case, once you have a shared session key you can use hashing to get keys for encrypt and auth in each direction.
< gmaxwell>
(and for a session identifier that can get shown in RPC and which the later auth stuff will act on)
< jonasschnelli>
Yes. I already added the HKDF derived session ID via RPC to allow detecting an MITM
< jonasschnelli>
gmaxwell: but would two encryption key for each direction be required?
< gmaxwell>
Yes. there are attacks otherwise.
< jonasschnelli>
Do you mind give me a hint where I can read that up?
< gmaxwell>
just generate them like H(shared_secret||direction||enc_or_auth) e.g. H(secret||0||0) or similar.
< jonasschnelli>
Yup. Will do...
< sipa>
where 0 is the side that connected, and 1 is the side that accepted the connection, e.g.
< gmaxwell>
jonasschnelli: we use a stream cipher _ANY_ reuse of the secret is fatal because an attacker can xor the two ciphertexts and learn the xor of the messages.
< jonasschnelli>
I guess this is the never reuse nonce&key? Right? And we can't control the sequence number (==nonce) in a bidirectional/async protocol?
< gmaxwell>
jonasschnelli: well I assume our sequence number is just starting at zero in each direction. You could hard partition the sequence space for each direction and be okay, but that seems about as complex as just derriving different values for each direction entirely, and more failure prone.
< jonasschnelli>
I see. Yes. Makes sense.
< jonasschnelli>
I'm going to write an overhaul of BIP151 (I hope nobody complain since it initial draft has been published via the BIPS long long ago). I know Armory has a complete implementation and they may not like the fact that they need to rewrite some parts
< jonasschnelli>
But I guess the changes are not too significant
< gmaxwell>
if someone complaints, you can just make a new BIP number... and they can stay using the old one: after all, they weren't talking to us with it anyways.
< jonasschnelli>
Right,...
< jonasschnelli>
gmaxwell: if the ciphertype (which we just dropped) in the handshake request would be part of the encryption and authentication key, wouldn't this mean its not attackable?
< jonasschnelli>
Like H(shared_secret||direction||enc_or_auth||ciphertype)
< gmaxwell>
depends on how you handle failure...
< gmaxwell>
I mean if we only implement 1 on day one, then anyone trying to use 2 will expect it to fail and then need to retry.
< gmaxwell>
so by just blocking 2 you can force the use of 1.
< jonasschnelli>
good point
< gmaxwell>
I assume if we change ciphers it would just be to something totally different, probably also at that point adding post-quantum key argreement like the hybrid above.
< jonasschnelli>
Yes. I see that and I agree adding the 1byte ciphertype seems a bit pointless
< gmaxwell>
it's just kind of unfortunate that AES uses less power on hardware that has it, but is otherwise really slow.
< jonasschnelli>
sipa, gmaxwell: if we negate K in case of an ODD pubkey (0x03), don't we reduce the possible keyspace and therefore the bits of security?
< sipa>
jonasschnelli: at worst, it's a 1 bit security loss
< sipa>
jonasschnelli: ECDSA does the same internally, btw
< sipa>
the public nonce is encoded in the signature with only its x coordinate
< gmaxwell>
jonasschnelli: there is no reduction in any case, because 0x02 vs 0x02 would be visible in public in any case.
< gmaxwell>
sipa: maybe we should consider merging in RLWE, there is a small, tidy, BSD licensed C implementation. The motivation is that for encrypted communication there is an incentive for an attacker to log all the traffic and then years later, when ECDH in secp256k1 is weakened, go and crack past logged connections.
< gmaxwell>
the hybrid proposal I linked to just runs RLWE and ECDH in parallel and hashes them both into the shared secret.
< gmaxwell>
jonasschnelli: I forget now, how does your proposal handle rotating the symmetric keys? are they updated with hashing after some fixed interval?