<div dir="ltr">Apologies if this idea was already raised before and shot down ...<br><br>For most of the handshake patterns, the API between the application and the Noise protocol library is pretty simple.  On the sending side, the application hands a payload to the library and the library hands back a sequence of bytes ready to transmit.  On the receiving side, the application hands a sequence of bytes to the library and the library hands back a payload (or an error).<br><br>The odd one out is Noise Pipes.  The application now has to perform an additional dance with packet types and a potential change of protocol half-way through the process.  During this, the initiator and responder may be reversed, adding more complexity to the application to figure out which CipherState is which for data transport.<br><br>Another concern I have is that the protocol reveals if a fallback has occurred or not in the sequence of packets that are exchanged.  Some systems may not want to reveal to passive surveillance that a key change has occurred, or that the initiator is currently ignorant of the responder's key and thus a ripe target for an active MITM.<br><br>I was wondering if it was possible to create a "hidden fallback" pattern that encompasses IK, XX, and XXfallback in one pattern.<br><br>Here's a quick attempt at such a thing (which I haven't completely analysed for security).  There are two new token codes "dhes-fallback" and "dhee-fallback" which I'll define below.<br><br>Noise_XXhiddenfallback(s, rs):<br>    <- s (optional)<br>    ...<br>    -> e, dhes-fallback<br>    <- e, dhee-fallback, s, dhse<br>    -> s, dhse, dhss<br><br>There are three cases of interest:<br><br>1. "s" is already known to the initiator and it is correct.<br>2. "s" is already known to the initiator and it is incorrect.<br>3. "s" is not known to the initiator (and is therefore incorrect).<br><br>I'll handle cases 1 and 2 first.<br><br>WriteMessage() is modified to include:<br><br>* For "dhes-fallback":<br>  - Save the current chaining key.<br>  - Call MixKey(DH(e, rs))<br>  - Appends EncryptAndHash(empty) to the buffer.<br>  - Do not perform EncryptAndHash(payload).  The payload must be empty.<br>* For "dhee-fallback":<br>  - Call MixKey(DH(e, re))<br>  - Appends EncryptAndHash(empty) to the buffer.<br><br>ReadMessage() is modified to include:<br><br>* For "dhes-fallback":<br>  - Save the current chaining key.<br>  - Call MixKey(DH(s, re))<br>  - Call DecryptAndHash() on an empty sequence (MAC value only).<br>  - If the MAC check fails, then restore the previous chaining key.<br>  - Whether the MAC check succeeds or not, the MixHash() part of DecryptAndHash() must still be done.<br>  - Do not perform DecryptAndHash(payload).  The message must end here.<br>* For "dhee-fallback":<br>  - Call MixKey(e, re).<br>  - Call DecryptAndHash() on an empty sequence (MAC value only).<br>  - If the MAC check is successful, then the initiator had the correct key and the handshake proceeds normally.<br>  - If the MAC check failed, then restore the previously saved chaining key and call MixKey(DH(e, re)) again.<br>  - Whether the MAC check succeeds or not, the MixHash() part of DecryptAndHash() must still be done.<br><br>Essentially, the effect of "dhes-fallback" on the chaining key is undone if the initiator has the wrong "s" value for the responder.  However, the incorrect MAC values are still mixed into the handshake hash to prevent the fallback from being spoofed by a MITM.<br><br>For pattern correctness, "dhes-fallback" must be the last token in its sequence and the corresponding message payload must be empty.  Any initiator certificates that need to be sent can be added to the final packet when the initiator's "s" value is sent.<br><br>To make the fallback truly hidden, ReadMessage() must take care to process the "dhes-fallback" and "dhee-fallback" tokens in constant time.  It should be possible to use constant-time conditional swaps to take care of this.<br><br>The above deals with cases 1 and 2.  Case 3 is where the initiator did not have a saved public key for the responder.  In this case, the initiator generates a random keypair and uses that public key as the stand-in for the responder's "s" during the first packet.  Essentially, the initiator manufactures an incorrect key and then case 3 is identical to case 2.<br><br>One last thing: "XXhiddenfallback" is a bit of a mouthful.  "XF"?  "XH"?<br><br>Any thoughts?<br><br>Cheers,<br><br>Rhys.<br><br></div>