disco_rs/
handshake.rs

1/*
2    Copyright David Huseby, All Rights Reserved.
3    SPDX-License-Identifier: Apache-2.0
4*/
5use crate::{
6    channel::{ChannelDuplex, ChannelRole, ChannelState},
7    error::{Error, ParamError},
8    Result,
9};
10use core::{
11    fmt::{Display, Error as FmtError, Formatter},
12    str::FromStr,
13};
14use serde::{Deserialize, Serialize};
15
16/// Identifiers for the different keys referenced in handshake scripts
17#[derive(PartialEq, Copy, Clone, Debug, Deserialize, Serialize)]
18pub enum HandshakeData {
19    /// Local ephemeral public key
20    Epub,
21    /// Local ephemeral secret key
22    Esec,
23    /// Payload data
24    Payload,
25    /// Prologue data
26    Prologue,
27    /// Pre-shared key
28    Psk,
29    /// Remote ephemeral public key
30    Re,
31    /// Remote static public key
32    Rs,
33    /// Local static public key
34    Spub,
35    /// Local static secret key
36    Ssec,
37}
38
39/// Different operations to perform in handshake scripts, see ยง5 of
40/// https://www.discocrypto.com/disco.html
41#[derive(PartialEq, Copy, Clone, Debug, Deserialize, Serialize)]
42pub enum HandshakeOp {
43    /// Start a message
44    Start,
45    /// Generate a new key pair
46    GenKey,
47    /// Get the handshake hash
48    GetHandshakeHash,
49    /// Does an AD(data)
50    MixHash(HandshakeData),
51    /// Does a KEY(key) and sets is_keyed to true
52    MixKey(HandshakeData),
53    /// Does an KEY(ECDH(key, key)) and sets is_keyed to true
54    MixKeyDh(HandshakeData, HandshakeData),
55    /// Does either a send_CLR(data) or send_ENC(data) + send_MAX(16) depending on is_keyed
56    EncryptAndHash(HandshakeData),
57    /// Does either a recv_CLR(data) or recv_ENC(data) + recv_MAC(16) depending on is_keyed
58    DecryptAndHash(HandshakeData),
59    /// Stop marks the end of one side's state changes
60    Stop,
61    /// End the handshake process and split into send/recv states
62    Split,
63}
64
65/// The state of the handshake so that this is resumable
66#[derive(PartialEq, Clone, Debug, Deserialize, Serialize)]
67pub struct HandshakeState {
68    /// The handshake operations
69    handshake: Handshake,
70    /// The index to the next handshake operation
71    index: usize,
72    /// The channel role
73    role: ChannelRole,
74    /// The channel duplex mode
75    duplex: ChannelDuplex,
76}
77
78/// HandshakeState impl
79impl HandshakeState {
80    /// construct a new handshake state from a list of operations
81    pub fn new(pattern: Handshake, role: &ChannelRole, duplex: &ChannelDuplex) -> Self {
82        HandshakeState {
83            handshake: pattern,
84            index: 0,
85            role: role.clone(),
86            duplex: duplex.clone(),
87        }
88    }
89}
90
91/// ChannelState trait impl
92impl ChannelState for HandshakeState {
93    /// get the channel role
94    fn role(&self) -> &ChannelRole {
95        &self.role
96    }
97    /// get the channel duplex
98    fn duplex(&self) -> &ChannelDuplex {
99        &self.duplex
100    }
101    /// reset the channel state
102    fn reset(&mut self) -> Result<()> {
103        self.index = 0;
104        Ok(())
105    }
106}
107
108/// Make it easy walk through the steps of the state machine
109impl Iterator for HandshakeState {
110    type Item = HandshakeOp;
111
112    fn next(&mut self) -> Option<Self::Item> {
113        let pattern = self.handshake.get_pattern(&self.role);
114        if self.index < pattern.len() {
115            let op = pattern[self.index];
116            self.index += 1;
117            Some(op)
118        } else {
119            None
120        }
121    }
122}
123
124/// The handshake patterns we support for now
125#[derive(PartialEq, Copy, Clone, Debug, Deserialize, Serialize)]
126pub enum Handshake {
127    /// One-way, no static key for initiator
128    N,
129    /// One-way, static key for initiator known to responder
130    K,
131    /// One-way, static key for initiator is transmitted to responder
132    X,
133    /// One-way, no static key for initiator, pre-shared key (i.e. passphrase, biometric, etc)
134    Npsk0,
135    /// One-way, static key for initiator known to responder, pre-shared key (i.e. passphrase, biometric, etc)
136    Kpsk0,
137    /// One-way, static key for initiator is transmitted to responder, pre-shared key (i.e. passphrase, biometric, etc)
138    Xpsk1,
139    /// No static keys for either the initiator or responder
140    NN,
141    /// Both sides know each other's static public keys
142    KK,
143    /// Both sides transmit their keys
144    XX,
145    /// Initiator transmits their static public key immediately
146    IK,
147    /// Initiator transmits their ephemeral and static public key immediately
148    IX,
149    /// No static key for the initiator, reponder key known
150    NK,
151    /// No static key for the initiator, responder transmits key
152    NX,
153    /// Initiator transmits key and knows responders key, deferred
154    XK1,
155    /// Initiator and responder know each other's keys, deferred
156    KK1,
157    /// Initiator and responder know a pre-shared key
158    NNpsk2,
159}
160
161// From the Noise Extension: Disco specification, the meaning of the operations
162// in the following handshake patterns are as follows:
163//
164// InitSymmetric(protocol_name): calls InitializeStrobe(protocol_name) to do
165// protocol separation.
166//
167// MixKey(key_data): calls KEY(key_data), sets is_keyed to true.
168//
169// MixHashDh(local, remote): calls AD(ECDH(local, remote)), sets is_keyed to true.
170//
171// MixHash(data): calls AD(data).
172//
173// GetHandshakeHash(): calls PRF(32) to get the handshake hash used for channel
174// binding as per the Noise spec (section 11.2).
175//
176// EncryptAndHash(data): if isKeyed is true, then calls send_ENC(data) followed by
177// send_MAC(16). if isKeyed is false, then calls send_CLR(data).
178//
179// DecryptAndHash(data): if isKeyed is true, then calls recv_ENC(data) followed by
180// recv_MAC(16). if isKeyed is false, then calls recv_CLR(data).
181//
182// Split(): clones the strobe state into two copies of the state. calls
183// meta_AD("initiator") on initiator state and meta_AD("responder") on the
184// responder state. The initiator's outbound state is its initiator state and
185// their inbound state is its responder state. The responder's outbound state
186// is its responder state and their inbound state is its initiator state. calls
187// RATCHET(16) on both states. returns both states.
188//
189impl Handshake {
190    /// Return the appropriate HandshakeState
191    pub fn get_pattern(&self, role: &ChannelRole) -> &[HandshakeOp] {
192        use ChannelRole::*;
193        use HandshakeData::*;
194        use HandshakeOp::*;
195
196        match self {
197            // N_Strobe Session Setup
198            // ========================
199            // NOTE: This is the equivalent to libsodium's sealed boxes. This session type is
200            // designed to anonymously send messages to a recipient given their public key. Only
201            // the recipient can decrypt these messages using their private key. While the
202            // recipient can verify the integrity of the message, they cannot verify the identity
203            // of the sender.
204            //
205            // Initiator                            Responder
206            //
207            //                      <- s
208            //                      ...
209            //
210            // +-- init()                           +-- init()
211            // | e = NULL                           | e = NULL
212            // | s = NULL                           | s = Responder's static key pair
213            // | re = NULL                          | re = NULL
214            // | rs = Responder's static pub key    | rs = NULL
215            // |                                    |
216            // | InitSymmetric("Noise_N...")        | InitSymmetric("Noise_N...")
217            // | MixHash(prologue)                  | MixHash(prologue)
218            // | MixHash(rs)                        | MixHash(s.pub)
219            //
220            // +-- send_message()
221            // | e = GenKey()
222            // | EncryptAndHash(e.pub)
223            // | MixKeyDh(e.sec, rs)
224            // | EncryptAndHash(payload)
225            // | Split()
226            //
227            //                      -> e, es, (payload)
228            //
229            //                                      +-- recv_message()
230            //                                      | re = DecryptAndHash()
231            //                                      | MixKeyDh(s.sec, re)
232            //                                      | payload = DecryptAndHash()
233            //                                      | Split()
234            Handshake::N => {
235                match role {
236                    Initiator => &[
237                        /* init */
238                        Start,
239                        MixHash(Prologue),
240                        MixHash(Rs),
241                        /* send */
242                        GenKey,
243                        EncryptAndHash(Epub),
244                        MixKeyDh(Esec, Rs),
245                        EncryptAndHash(Payload),
246                        GetHandshakeHash,
247                        Split,
248                    ],
249                    Responder => &[
250                        /* init */
251                        Start,
252                        MixHash(Prologue),
253                        MixHash(Spub),
254                        /* recv */
255                        DecryptAndHash(Re),
256                        MixKeyDh(Ssec, Re),
257                        DecryptAndHash(Payload),
258                        GetHandshakeHash,
259                        Split,
260                    ],
261                }
262            }
263            // K_Strobe Session Setup
264            // ========================
265            // NOTE: This session type is the equivalent to libsodium's authenticated encryption.
266            // This variant in particular assumes that the sender and recipient have already
267            // executed a key exchange out-of-band prior to this session's creation.
268            //
269            // Initiator                            Responder
270            //
271            //                      -> s
272            //                      <- s
273            //                      ...
274            //
275            // +-- init()                           +-- init()
276            // | e = NULL                           | e = NULL
277            // | s = Initiator's static key pair    | s = Responder's static key pair
278            // | re = NULL                          | re = NULL
279            // | rs = Responder's static pub key    | rs = Initiator's static pub key
280            // |                                    |
281            // | InitSymmetric("Noise_K...")        | InitSymmetric("Noise_K...")
282            // | MixHash(prologue)                  | MixHash(prologue)
283            // | MixHash(s.pub)                     | MixHash(rs)
284            // | MixHash(rs)                        | MixHash(s.pub)
285            //
286            // +-- send_message()
287            // | e = GenKey()
288            // | EncryptAndHash(e.pub)
289            // | MixKeyDh(e.sec, rs)
290            // | MixKeyDh(s.sec, rs)
291            // | EncryptAndHash(payload)
292            // | Split()
293            //
294            //                      -> e, es, ss, (payload)
295            //
296            //                                      +-- recv_message()
297            //                                      | re = DecryptAndHash()
298            //                                      | MixKeyDh(s.sec, re)
299            //                                      | MixKeyDh(s.sec, rs)
300            //                                      | payload = DecryptAndHash()
301            //                                      | Split()
302            Handshake::K => {
303                match role {
304                    Initiator => &[
305                        /* init */
306                        Start,
307                        MixHash(Prologue),
308                        MixHash(Spub),
309                        MixHash(Rs),
310                        /* send */
311                        GenKey,
312                        EncryptAndHash(Epub),
313                        MixKeyDh(Esec, Rs),
314                        MixKeyDh(Ssec, Rs),
315                        EncryptAndHash(Payload),
316                        GetHandshakeHash,
317                        Split,
318                    ],
319                    Responder => &[
320                        /* init */
321                        Start,
322                        MixHash(Prologue),
323                        MixHash(Rs),
324                        MixHash(Spub),
325                        /* recv */
326                        DecryptAndHash(Re),
327                        MixKeyDh(Ssec, Re),
328                        MixKeyDh(Ssec, Rs),
329                        DecryptAndHash(Payload),
330                        GetHandshakeHash,
331                        Split,
332                    ],
333                }
334            }
335            // X_Strobe Session Setup
336            // ========================
337            // NOTE: This session type is the equivalent to libsodium's authenticated encryption.
338            // This particular session does not require the sender and recipient to have exchanged
339            // keys prior to the session. Only the sender needs to know the recipient's public key
340            // because the sender ends their's in the message, encrypted.
341            //
342            // Initiator                            Responder
343            //
344            //                      <- s
345            //                      ...
346            //
347            // +-- init()                           +-- init()
348            // | e = NULL                           | e = NULL
349            // | s = Initiator's static key pair    | s = Responder's static key pair
350            // | re = NULL                          | re = NULL
351            // | rs = Responder's static pub key    | rs = NULL
352            // |                                    |
353            // | InitSymmetric("Noise_X...")        | InitSymmetric("Noise_X...")
354            // | MixHash(prologue)                  | MixHash(prologue)
355            // | MixHash(rs)                        | MixHash(s.pub)
356            //
357            // +-- send_message()
358            // | e = GenKey()
359            // | EncryptAndHash(e.pub)
360            // | MixKeyDh(e.sec, rs)
361            // | EncryptAndHash(s.pub)
362            // | MixKeyDh(s.sec, rs)
363            // | EncryptAndHash(payload)
364            // | Split()
365            //
366            //                      -> e, es, s, ss, (payload)
367            //
368            //                                      +-- recv_message()
369            //                                      | re = DecryptAndHash()
370            //                                      | MixKeyDh(s.sec, re)
371            //                                      | rs = DecryptAndHash()
372            //                                      | MixKeyDh(s.sec, rs)
373            //                                      | payload = DecryptAndHash()
374            //                                      | split()
375            Handshake::X => {
376                match role {
377                    Initiator => &[
378                        /* init */
379                        Start,
380                        MixHash(Prologue),
381                        MixHash(Rs),
382                        /* send */
383                        GenKey,
384                        EncryptAndHash(Epub),
385                        MixKeyDh(Esec, Rs),
386                        EncryptAndHash(Spub),
387                        MixKeyDh(Ssec, Rs),
388                        EncryptAndHash(Payload),
389                        GetHandshakeHash,
390                        Split,
391                    ],
392                    Responder => &[
393                        /* init */
394                        Start,
395                        MixHash(Prologue),
396                        MixHash(Spub),
397                        /* recv */
398                        DecryptAndHash(Re),
399                        MixKeyDh(Ssec, Re),
400                        DecryptAndHash(Rs),
401                        MixKeyDh(Ssec, Rs),
402                        DecryptAndHash(Payload),
403                        GetHandshakeHash,
404                        Split,
405                    ],
406                }
407            }
408            // Npsk0_Strobe Session Setup
409            // ========================
410            // NOTE: This is the equivalent to libsodium's sealed boxes. This session type is
411            // designed to anonymously send messages to a recipient given their public key. Only
412            // the recipient can decrypt these messages using their private key. While the
413            // recipient can verify the integrity of the message, they cannot verify the identity
414            // of the sender.
415            //
416            // Initiator                            Responder
417            //
418            //                      <- s
419            //                      ...
420            //
421            // +-- init()                           +-- init()
422            // | e = NULL                           | e = NULL
423            // | s = NULL                           | s = Responder's static key pair
424            // | re = NULL                          | re = NULL
425            // | rs = Responder's static pub key    | rs = NULL
426            // | psk = pre-shared key value         | psk = pre-shared key value
427            // |                                    |
428            // | InitSymmetric("Noise_Npsk0...")    | InitSymmetric("Noise_Npsk0...")
429            // | MixHash(prologue)                  | MixHash(prologue)
430            // | MixHash(rs)                        | MixHash(s.pub)
431            //
432            // +-- send_message()
433            // | e = GenKey()
434            // | EncryptAndHash(e.pub)
435            // | MixKeyDh(e.sec, rs)
436            // | EncryptAndHash(payload)
437            // | Split()
438            //
439            //                      -> psk, e, es, (payload)
440            //
441            //                                      +-- recv_message()
442            //                                      | re = DecryptAndHash()
443            //                                      | MixKeyDh(s.sec, re)
444            //                                      | payload = DecryptAndHash()
445            //                                      | Split()
446            Handshake::Npsk0 => {
447                match role {
448                    Initiator => &[
449                        /* init */
450                        Start,
451                        MixHash(Prologue),
452                        MixHash(Rs),
453                        /* send */
454                        MixKey(Psk),
455                        GenKey,
456                        EncryptAndHash(Epub),
457                        MixKeyDh(Esec, Rs),
458                        EncryptAndHash(Payload),
459                        GetHandshakeHash,
460                        Split,
461                    ],
462                    Responder => &[
463                        /* init */
464                        Start,
465                        MixHash(Prologue),
466                        MixHash(Spub),
467                        /* recv */
468                        MixKey(Psk),
469                        DecryptAndHash(Re),
470                        MixKeyDh(Ssec, Re),
471                        DecryptAndHash(Payload),
472                        GetHandshakeHash,
473                        Split,
474                    ],
475                }
476            }
477            // Kpsk0_Strobe Session Setup
478            // ========================
479            // NOTE: This session type is the equivalent to libsodium's authenticated encryption.
480            // This variant in particular assumes that the sender and recipient have already
481            // executed a key exchange out-of-band prior to this session's creation.
482            //
483            // Initiator                            Responder
484            //
485            //                      -> s
486            //                      <- s
487            //                      ...
488            //
489            // +-- init()                           +-- init()
490            // | e = NULL                           | e = NULL
491            // | s = Initiator's static key pair    | s = Responder's static key pair
492            // | re = NULL                          | re = NULL
493            // | rs = Responder's static pub key    | rs = Initiator's static pub key
494            // | psk = pre-shared key value         | psk = pre-shared key value
495            // |                                    |
496            // | InitSymmetric("Noise_Kpsk0...")    | InitSymmetric("Noise_Kpsk0...")
497            // | MixHash(prologue)                  | MixHash(prologue)
498            // | MixHash(s.pub)                     | MixHash(rs)
499            // | MixHash(rs)                        | MixHash(s.pub)
500            //
501            // +-- send_message()
502            // | e = GenKey()
503            // | EncryptAndHash(e.pub)
504            // | MixKeyDh(e.sec, rs)
505            // | MixKeyDh(s.sec, rs)
506            // | EncryptAndHash(payload)
507            // | Split()
508            //
509            //                      -> psk, e, es, ss, (payload)
510            //
511            //                                      +-- recv_message()
512            //                                      | re = DecryptAndHash()
513            //                                      | MixKeyDh(s.sec, re)
514            //                                      | MixKeyDh(s.sec, rs)
515            //                                      | payload = DecryptAndHash()
516            //                                      | Split()
517            Handshake::Kpsk0 => {
518                match role {
519                    Initiator => &[
520                        /* init */
521                        Start,
522                        MixHash(Prologue),
523                        MixHash(Spub),
524                        MixHash(Rs),
525                        /* send */
526                        MixKey(Psk),
527                        GenKey,
528                        EncryptAndHash(Epub),
529                        MixKeyDh(Esec, Rs),
530                        MixKeyDh(Ssec, Rs),
531                        EncryptAndHash(Payload),
532                        GetHandshakeHash,
533                        Split,
534                    ],
535                    Responder => &[
536                        /* init */
537                        Start,
538                        MixHash(Prologue),
539                        MixHash(Rs),
540                        MixHash(Spub),
541                        /* recv */
542                        MixKey(Psk),
543                        DecryptAndHash(Re),
544                        MixKeyDh(Ssec, Re),
545                        MixKeyDh(Ssec, Rs),
546                        DecryptAndHash(Payload),
547                        GetHandshakeHash,
548                        Split,
549                    ],
550                }
551            }
552            // Xpsk1_Strobe Session Setup
553            // ========================
554            // NOTE: This session type is the equivalent to libsodium's authenticated encryption.
555            // This particular session does not require the sender and recipient to have exchanged
556            // keys prior to the session. Only the sender needs to know the recipient's public key
557            // because the sender ends their's in the message, encrypted.
558            //
559            // Initiator                            Responder
560            //
561            //                      <- s
562            //                      ...
563            //
564            // +-- init()                           +-- init()
565            // | e = NULL                           | e = NULL
566            // | s = Initiator's static key pair    | s = Responder's static key pair
567            // | re = NULL                          | re = NULL
568            // | rs = Responder's static pub key    | rs = NULL
569            // | psk = pre-shared key value         | psk = pre-shared key value
570            // |                                    |
571            // | InitSymmetric("Noise_Xpsk1...")    | InitSymmetric("Noise_Xpsk1...")
572            // | MixHash(prologue)                  | MixHash(prologue)
573            // | MixHash(rs)                        | MixHash(s.pub)
574            //
575            // +-- send_message()
576            // | e = GenKey()
577            // | EncryptAndHash(e.pub)
578            // | MixKeyDh(e.sec, rs)
579            // | EncryptAndHash(s.pub)
580            // | MixKeyDh(s.sec, rs)
581            // | EncryptAndHash(payload)
582            // | Split()
583            //
584            //                      -> e, es, s, ss, psk, (payload)
585            //
586            //                                      +-- recv_message()
587            //                                      | re = DecryptAndHash()
588            //                                      | MixKeyDh(s.sec, re)
589            //                                      | rs = DecryptAndHash()
590            //                                      | MixKeyDh(s.sec, rs)
591            //                                      | payload = DecryptAndHash()
592            //                                      | split()
593            Handshake::Xpsk1 => {
594                match role {
595                    Initiator => &[
596                        /* init */
597                        Start,
598                        MixHash(Prologue),
599                        MixHash(Rs),
600                        /* send */
601                        GenKey,
602                        EncryptAndHash(Epub),
603                        MixKeyDh(Esec, Rs),
604                        EncryptAndHash(Spub),
605                        MixKeyDh(Ssec, Rs),
606                        MixKey(Psk),
607                        EncryptAndHash(Payload),
608                        GetHandshakeHash,
609                        Split,
610                    ],
611                    Responder => &[
612                        /* init */
613                        Start,
614                        MixHash(Prologue),
615                        MixHash(Spub),
616                        /* recv */
617                        DecryptAndHash(Re),
618                        MixKeyDh(Ssec, Re),
619                        DecryptAndHash(Rs),
620                        MixKeyDh(Ssec, Rs),
621                        MixKey(Psk),
622                        DecryptAndHash(Payload),
623                        GetHandshakeHash,
624                        Split,
625                    ],
626                }
627            }
628            // NN_Strobe Session Setup
629            // =======================
630            //
631            // Initiator                            Responder
632            //
633            // +-- init()                           +-- init()
634            // | e = NULL                           | e = NULL
635            // | s = NULL                           | s = NULL
636            // | re = NULL                          | re = NULL
637            // | rs = NULL                          | rs = NULL
638            // |                                    |
639            // | InitSymmetric("Noise_NN...")       | InitSymmetric("Noise_NN...")
640            // | MixHash(prologue)                  | MixHash(prologue)
641            //
642            // +-- send_message()
643            // | e = GenKey()
644            // | EncryptAndHash(e.pub)
645            // | EncryptAndHash(payload)
646            //
647            //                      -> e, (payload)
648            //
649            //                                      +-- recv_message()
650            //                                      | re = DecryptAndHash()
651            //                                      | payload = DecryptAndHash()
652            //
653            //                                      +-- send_message()
654            //                                      | e = GenKey()
655            //                                      | EncryptAndHash(e.pub)
656            //                                      | MixKeyDh(e.sec, re)
657            //                                      | EncryptAndHash(payload)
658            //                                      | Split()
659            //
660            //                      <- e, ee, (payload)
661            //
662            // +-- recv_message()
663            // | re = DecryptAndHash()
664            // | MixKeyDh(e.sec, re)
665            // | payload = DecryptAndHash()
666            // | Split()
667            //
668            Handshake::NN => {
669                match role {
670                    Initiator => &[
671                        /* init */
672                        Start,
673                        MixHash(Prologue),
674                        /* send */
675                        GenKey,
676                        EncryptAndHash(Epub),
677                        EncryptAndHash(Payload),
678                        Stop,
679                        /* recv */
680                        Start,
681                        DecryptAndHash(Re),
682                        MixKeyDh(Esec, Re),
683                        DecryptAndHash(Payload),
684                        GetHandshakeHash,
685                        Split,
686                    ],
687                    Responder => &[
688                        /* init */
689                        Start,
690                        MixHash(Prologue),
691                        /* recv */
692                        DecryptAndHash(Re),
693                        DecryptAndHash(Payload),
694                        Stop,
695                        /* send */
696                        Start,
697                        GenKey,
698                        EncryptAndHash(Epub),
699                        MixKeyDh(Esec, Re),
700                        EncryptAndHash(Payload),
701                        GetHandshakeHash,
702                        Split,
703                    ],
704                }
705            }
706            // KK_Strobe Session Setup
707            // ========================
708            //
709            // Initiator                            Responder
710            //
711            //                      -> s
712            //                      <- s
713            //                      ...
714            //
715            // +-- init()                           +-- init()
716            // | e = NULL                           | e = NULL
717            // | s = Initiator's static key pair    | s = Responder's static key pair
718            // | re = NULL                          | re = NULL
719            // | rs = Responder's static pub key    | rs = Initiator's static pub key
720            // |                                    |
721            // | InitSymmetric("Noise_KK...")       | InitSymmetric("Noise_KK...")
722            // | MixHash(prologue)                  | MixHash(prologue)
723            // | MixHash(s.pub)                     | MixHash(rs)
724            // | MixHash(rs)                        | MixHash(s.pub)
725            //
726            // +-- send_message()
727            // | e = GenKey()
728            // | EncryptAndHash(e.pub)
729            // | MixKeyDh(e.sec, rs)
730            // | MixKeyDh(s.sec, rs)
731            // | EncryptAndHash(payload)
732            //
733            //                      -> e, es, ss, (payload)
734            //
735            //                                      +-- recv_message()
736            //                                      | re = DecryptAndHash()
737            //                                      | MixKeyDh(s.sec, re)
738            //                                      | MixKeyDh(s.sec, rs)
739            //                                      | payload = DecryptAndHash()
740            //
741            //                                      +-- send_message()
742            //                                      | e = GenKey()
743            //                                      | EncryptAndHash(e.pub)
744            //                                      | MixKeyDh(e.sec, re)
745            //                                      | MixKeyDh(s.sec, re)
746            //                                      | EncryptAndHash(payload)
747            //                                      | Split()
748            //
749            //                      <- e, ee, se, (payload)
750            //
751            // +-- recv_message()
752            // | re = DecryptAndHash()
753            // | MixKeyDh(e.sec, re))
754            // | MixKeyDh(e.sec, rs))
755            // | payload = DecryptAndHash()
756            // | Split()
757            Handshake::KK => {
758                match role {
759                    Initiator => &[
760                        /* init */
761                        Start,
762                        MixHash(Prologue),
763                        MixHash(Spub),
764                        MixHash(Rs),
765                        /* send */
766                        GenKey,
767                        EncryptAndHash(Epub),
768                        MixKeyDh(Esec, Rs),
769                        MixKeyDh(Ssec, Rs),
770                        EncryptAndHash(Payload),
771                        Stop,
772                        /* recv */
773                        Start,
774                        DecryptAndHash(Re),
775                        MixKeyDh(Esec, Re),
776                        MixKeyDh(Esec, Rs),
777                        DecryptAndHash(Payload),
778                        GetHandshakeHash,
779                        Split,
780                    ],
781                    Responder => &[
782                        /* init */
783                        Start,
784                        MixHash(Prologue),
785                        MixHash(Rs),
786                        MixHash(Spub),
787                        /* recv */
788                        DecryptAndHash(Re),
789                        MixKeyDh(Ssec, Re),
790                        MixKeyDh(Ssec, Rs),
791                        DecryptAndHash(Payload),
792                        Stop,
793                        /* send */
794                        Start,
795                        GenKey,
796                        EncryptAndHash(Epub),
797                        MixKeyDh(Esec, Re),
798                        MixKeyDh(Ssec, Re),
799                        EncryptAndHash(Payload),
800                        GetHandshakeHash,
801                        Split,
802                    ],
803                }
804            }
805            // XX_Strobe Session Setup
806            // =======================
807            //
808            // Initiator                            Responder
809            //
810            // +-- init()                           +-- init()
811            // | e = NULL                           | e = NULL
812            // | s = Initiator's static key pair    | s = Responder's static key pair
813            // | re = NULL                          | re = NULL
814            // | rs = NULL                          | rs = NULL
815            // |                                    |
816            // | InitSymmetric("Noise_XX...")       | InitSymmetric("Noise_XX...")
817            // | MixHash(prologue)                  | MixHash(prologue)
818            //
819            // +-- send_message()
820            // | e = GenKey()
821            // | EncryptAndHash(e.pub)
822            // | MixHash(e.pub)
823            // | EncryptAndHash(payload)
824            //
825            //                      -> e, (payload)
826            //
827            //                                      +-- recv_message()
828            //                                      | re = DecryptAndHash()
829            //                                      | MixHash(re)
830            //                                      | payload = DecryptAndHash()
831            //
832            //                                      +-- send_message()
833            //                                      | e = GenKey()
834            //                                      | EncryptAndHash(e.pub)
835            //                                      | MixHash(e.pub)
836            //                                      | MixKeyDh(e.sec, re)
837            //                                      | EncryptAndHash(s.pub)
838            //                                      | MixKeyDh(s.sec, re)
839            //                                      | EncryptAndHash(payload)
840            //
841            //                      <- e, ee, s, es, (payload)
842            //
843            // +-- recv_message()
844            // | re = DecryptAndHash()
845            // | MixHash(re)
846            // | MixKeyDh(e.sec, re)
847            // | rs = DecryptAndHash()
848            // | MixKeyDh(e.sec, rs)
849            // | payload = DecryptAndHash()
850            //
851            // +-- send_message()
852            // | EncryptAndHash(s.pub)
853            // | MixKeyDh(s.sec, re)
854            // | EncryptAndHash(payload)
855            // | Split()
856            //
857            //                      -> s, se, (payload)
858            //
859            //                                      +-- recv_message()
860            //                                      | rs = DecryptAndHash()
861            //                                      | MixKeyDh(s.sec, rs)
862            //                                      | payload = DecryptAndHash()
863            //                                      | Split()
864            Handshake::XX => {
865                match role {
866                    Initiator => &[
867                        /* init */
868                        Start,
869                        MixHash(Prologue),
870                        /* send */
871                        GenKey,
872                        EncryptAndHash(Epub),
873                        EncryptAndHash(Payload),
874                        Stop,
875                        /* recv */
876                        Start,
877                        DecryptAndHash(Re),
878                        MixKeyDh(Esec, Re),
879                        DecryptAndHash(Rs),
880                        MixKeyDh(Esec, Rs),
881                        DecryptAndHash(Payload),
882                        Stop,
883                        /* send */
884                        Start,
885                        EncryptAndHash(Spub),
886                        MixKeyDh(Ssec, Rs),
887                        EncryptAndHash(Payload),
888                        GetHandshakeHash,
889                        Split,
890                    ],
891                    Responder => &[
892                        /* init */
893                        Start,
894                        MixHash(Prologue),
895                        /* recv */
896                        DecryptAndHash(Re),
897                        DecryptAndHash(Payload),
898                        Stop,
899                        /* send */
900                        Start,
901                        GenKey,
902                        EncryptAndHash(Epub),
903                        MixKeyDh(Esec, Re),
904                        EncryptAndHash(Spub),
905                        MixKeyDh(Ssec, Re),
906                        EncryptAndHash(Payload),
907                        Stop,
908                        /* recv */
909                        Start,
910                        DecryptAndHash(Rs),
911                        MixKeyDh(Ssec, Rs),
912                        DecryptAndHash(Payload),
913                        GetHandshakeHash,
914                        Split,
915                    ],
916                }
917            }
918            // IK_Strobe Session Setup
919            // =======================
920            //
921            // Initiator                            Responder
922            //
923            //                      <- s
924            //                      ...
925            //
926            // +-- init()                           +-- init()
927            // | e = NULL                           | e = NULL
928            // | s = Initiator's static key pair    | s = Responder's static key pair
929            // | re = NULL                          | re = NULL
930            // | rs = Responder's static pub key    | rs = NULL
931            // |                                    |
932            // | InitSymmetric("Noise_IK...")       | InitSymmetric("Noise_IK...")
933            // | MixHash(prologue)                  | MixHash(prologue)
934            // | MixHash(rs)                        | MixHash(s.pub)
935            //
936            // +-- send_message()
937            // | e = GenKey()
938            // | EncryptAndHash(e.pub)
939            // | MixKeyDh(e.sec, rs)
940            // | EncryptAndHash(s.pub)
941            // | MixKeyDh(s.sec, rs)
942            // | EncryptAndHash(payload)
943            //
944            //                      -> e, es, s, ss, (payload)
945            //
946            //                                      +-- recv_message()
947            //                                      | re = DecryptAndHash()
948            //                                      | MixKeyDh(s.sec, re)
949            //                                      | rs = DecryptAndHash()
950            //                                      | MixKeyDh(s.sec, rs)
951            //                                      | payload = DecryptAndHash()
952            //
953            //                                      +-- send_message()
954            //                                      | e = GenKey()
955            //                                      | EncryptAndHash(e.pub)
956            //                                      | MixKeyDh(e.sec, re)
957            //                                      | MixKeyDh(e.sec, rs)
958            //                                      | EncryptAndHash(payload)
959            //                                      | Split()
960            //
961            //                      <- e, ee, se, (payload)
962            //
963            // +-- recv_message()
964            // | re = DecryptAndHash()
965            // | MixKeyDh(e.sec, re)
966            // | MixKeyDh(s.sec, re)
967            // | payload = DecryptAndHash()
968            // | Split()
969            //
970            Handshake::IK => {
971                match role {
972                    Initiator => &[
973                        /* init */
974                        Start,
975                        MixHash(Prologue),
976                        MixHash(Rs),
977                        /* send */
978                        GenKey,
979                        EncryptAndHash(Epub),
980                        MixKeyDh(Esec, Rs),
981                        EncryptAndHash(Spub),
982                        MixKeyDh(Ssec, Rs),
983                        EncryptAndHash(Payload),
984                        Stop,
985                        /* recv */
986                        Start,
987                        DecryptAndHash(Re),
988                        MixKeyDh(Esec, Re),
989                        MixKeyDh(Esec, Rs),
990                        DecryptAndHash(Payload),
991                        GetHandshakeHash,
992                        Split,
993                    ],
994                    Responder => &[
995                        /* init */
996                        Start,
997                        MixHash(Prologue),
998                        MixHash(Spub),
999                        /* recv */
1000                        DecryptAndHash(Re),
1001                        MixKeyDh(Ssec, Re),
1002                        DecryptAndHash(Rs),
1003                        MixKeyDh(Ssec, Rs),
1004                        DecryptAndHash(Payload),
1005                        Stop,
1006                        /* send */
1007                        Start,
1008                        GenKey,
1009                        EncryptAndHash(Epub),
1010                        MixKeyDh(Esec, Re),
1011                        MixKeyDh(Ssec, Re),
1012                        EncryptAndHash(Payload),
1013                        GetHandshakeHash,
1014                        Split,
1015                    ],
1016                }
1017            }
1018            // IX_Strobe Session Setup
1019            // =======================
1020            //
1021            // Initiator                            Responder
1022            //
1023            // +-- init()                           +-- init()
1024            // | e = NULL                           | e = NULL
1025            // | s = Initiator's static key pair    | s = Responder's static key pair
1026            // | re = NULL                          | re = NULL
1027            // | rs = NULL                          | rs = NULL
1028            // |                                    |
1029            // | InitSymmetric("Noise_IX...")       | InitSymmetric("Noise_IX...")
1030            // | MixHash(prologue)                  | MixHash(prologue)
1031            //
1032            // +-- send_message()
1033            // | e = GenKey()
1034            // | EncryptAndHash(e.pub)
1035            // | EncryptAndHash(s.pub)
1036            // | EncryptAndHash(payload)
1037            //
1038            //                      -> e, s, (payload)
1039            //
1040            //                                      +-- recv_message()
1041            //                                      | re = DecryptAndHash()
1042            //                                      | rs = DecryptAndHash()
1043            //                                      | payload = DecryptAndHash()
1044            //
1045            //                                      +-- send_message()
1046            //                                      | e = GenKey()
1047            //                                      | EncryptAndHash(e.pub)
1048            //                                      | MixKeyDh(e.sec, re)
1049            //                                      | MixKeyDh(e.sec, rs)
1050            //                                      | EncryptAndHash(s.pub)
1051            //                                      | MixKeyDh(s.sec, re)
1052            //                                      | EncryptAndHash(payload)
1053            //                                      | Split()
1054            //
1055            //                      <- e, ee, se, s, es, (payload)
1056            //
1057            // +-- recv_message()
1058            // | re = DecryptAndHash()
1059            // | MixKeyDh(e.sec, re)
1060            // | MixKeyDh(s.sec, re)
1061            // | rs = DecryptAndHash()
1062            // | MixKeyDh(e.sec, rs)
1063            // | payload = DecryptAndHash()
1064            // | Split()
1065            //
1066            Handshake::IX => {
1067                match role {
1068                    Initiator => &[
1069                        /* init */
1070                        Start,
1071                        MixHash(Prologue),
1072                        /* send */
1073                        GenKey,
1074                        EncryptAndHash(Epub),
1075                        EncryptAndHash(Spub),
1076                        EncryptAndHash(Payload),
1077                        Stop,
1078                        /* recv */
1079                        Start,
1080                        DecryptAndHash(Re),
1081                        MixKeyDh(Esec, Re),
1082                        MixKeyDh(Ssec, Re),
1083                        DecryptAndHash(Rs),
1084                        MixKeyDh(Esec, Rs),
1085                        DecryptAndHash(Payload),
1086                        GetHandshakeHash,
1087                        Split,
1088                    ],
1089                    Responder => &[
1090                        /* init */
1091                        Start,
1092                        MixHash(Prologue),
1093                        /* recv */
1094                        DecryptAndHash(Re),
1095                        DecryptAndHash(Rs),
1096                        DecryptAndHash(Payload),
1097                        Stop,
1098                        /* send */
1099                        Start,
1100                        GenKey,
1101                        EncryptAndHash(Epub),
1102                        MixKeyDh(Esec, Re),
1103                        MixKeyDh(Esec, Rs),
1104                        EncryptAndHash(Spub),
1105                        MixKeyDh(Ssec, Re),
1106                        EncryptAndHash(Payload),
1107                        GetHandshakeHash,
1108                        Split,
1109                    ],
1110                }
1111            }
1112            // NK_Strobe Session Setup
1113            // =======================
1114            //
1115            // Initiator                            Responder
1116            //
1117            //                      <- s
1118            //                      ...
1119            //
1120            // +-- init()                           +-- init()
1121            // | e = NULL                           | e = NULL
1122            // | s = NULL                           | s = Responder's static key pair
1123            // | re = NULL                          | re = NULL
1124            // | rs = Responder's static pub key    | rs = NULL
1125            // |                                    |
1126            // | InitSymmetric("Noise_NK...")       | InitSymmetric("Noise_NK...")
1127            // | MixHash(prologue)                  | MixHash(prologue)
1128            // | MixHash(rs)                        | MixHash(s.pub)
1129            //
1130            // +-- send_message()
1131            // | e = GenKey()
1132            // | EncryptAndHash(e.pub)
1133            // | MixKeyDh(e.sec, rs)
1134            // | EncryptAndHash(payload)
1135            //
1136            //                      -> e, es, (payload)
1137            //
1138            //                                      +-- recv_message()
1139            //                                      | re = DecryptAndHash()
1140            //                                      | MixKeyDh(s.sec, re)
1141            //                                      | payload = DecryptAndHash()
1142            //
1143            //                                      +-- send_message()
1144            //                                      | e = GenKey()
1145            //                                      | EncryptAndHash(e.pub)
1146            //                                      | MixKeyDh(e.sec, re)
1147            //                                      | EncryptAndHash(payload)
1148            //                                      | Split()
1149            //
1150            //                      <- e, ee, (payload)
1151            //
1152            // +-- recv_message()
1153            // | re = DecryptAndHash()
1154            // | MixKeyDh(e.sec, re))
1155            // | payload = DecryptAndHash()
1156            // | Split()
1157            //
1158            Handshake::NK => {
1159                match role {
1160                    Initiator => &[
1161                        /* init */
1162                        Start,
1163                        MixHash(Prologue),
1164                        MixHash(Rs),
1165                        /* send */
1166                        GenKey,
1167                        EncryptAndHash(Epub),
1168                        MixKeyDh(Esec, Rs),
1169                        EncryptAndHash(Payload),
1170                        Stop,
1171                        /* recv */
1172                        Start,
1173                        DecryptAndHash(Re),
1174                        MixKeyDh(Esec, Re),
1175                        DecryptAndHash(Payload),
1176                        GetHandshakeHash,
1177                        Split,
1178                    ],
1179                    Responder => &[
1180                        /* init */
1181                        Start,
1182                        MixHash(Prologue),
1183                        MixHash(Spub),
1184                        /* recv */
1185                        DecryptAndHash(Re),
1186                        MixKeyDh(Ssec, Re),
1187                        DecryptAndHash(Payload),
1188                        Stop,
1189                        /* send */
1190                        Start,
1191                        GenKey,
1192                        EncryptAndHash(Epub),
1193                        MixKeyDh(Esec, Re),
1194                        EncryptAndHash(Payload),
1195                        GetHandshakeHash,
1196                        Split,
1197                    ],
1198                }
1199            }
1200            // NX_Strobe Session Setup
1201            // =======================
1202            //
1203            // Initiator                            Responder
1204            //
1205            // +-- init()                           +-- init()
1206            // | e = NULL                           | e = NULL
1207            // | s = NULL                           | s = Responder's static key pair
1208            // | re = NULL                          | re = NULL
1209            // | rs = NULL                          | rs = NULL
1210            // |                                    |
1211            // | InitSymmetric("Noise_NX...")       | InitSymmetric("Noise_NX...")
1212            // | MixHash(prologue)                  | MixHash(prologue)
1213            //
1214            // +-- send_message()
1215            // | e = GenKey()
1216            // | EncryptAndHash(e.pub)
1217            // | EncryptAndHash(payload)
1218            //
1219            //                      -> e, (payload)
1220            //
1221            //                                      +-- recv_message()
1222            //                                      | re = DecryptAndHash()
1223            //                                      | payload = DecryptAndHash()
1224            //
1225            //                                      +-- send_message()
1226            //                                      | e = GenKey()
1227            //                                      | EncryptAndHash(e.pub)
1228            //                                      | MixKeyDh(e.sec, re)
1229            //                                      | EncryptAndHash(s.pub)
1230            //                                      | MixKeyDh(s.sec, re)
1231            //                                      | EncryptAndHash(payload)
1232            //                                      | Split()
1233            //
1234            //                      <- e, ee, s, es, (payload)
1235            //
1236            // +-- recv_message()
1237            // | re = DecryptAndHash()
1238            // | MixKeyDh(e.sec, re)
1239            // | rs = DecryptAndHash()
1240            // | MixKeyDh(e.sec, rs)
1241            // | payload = DecryptAndHash()
1242            // | Split()
1243            //
1244            Handshake::NX => {
1245                match role {
1246                    Initiator => &[
1247                        /* init */
1248                        Start,
1249                        MixHash(Prologue),
1250                        /* send */
1251                        GenKey,
1252                        EncryptAndHash(Epub),
1253                        EncryptAndHash(Payload),
1254                        Stop,
1255                        /* recv */
1256                        Start,
1257                        DecryptAndHash(Re),
1258                        MixKeyDh(Esec, Re),
1259                        DecryptAndHash(Rs),
1260                        MixKeyDh(Esec, Rs),
1261                        DecryptAndHash(Payload),
1262                        GetHandshakeHash,
1263                        Split,
1264                    ],
1265                    Responder => &[
1266                        /* init */
1267                        Start,
1268                        MixHash(Prologue),
1269                        /* recv */
1270                        DecryptAndHash(Re),
1271                        DecryptAndHash(Payload),
1272                        Stop,
1273                        /* send */
1274                        Start,
1275                        GenKey,
1276                        EncryptAndHash(Epub),
1277                        MixKeyDh(Esec, Re),
1278                        EncryptAndHash(Spub),
1279                        MixKeyDh(Ssec, Re),
1280                        EncryptAndHash(Payload),
1281                        GetHandshakeHash,
1282                        Split,
1283                    ],
1284                }
1285            }
1286            // XK1_Strobe Session Setup
1287            // ========================
1288            //
1289            // Initiator                            Responder
1290            //
1291            //                      <- s
1292            //                      ...
1293            //
1294            // +-- init()                           +-- init()
1295            // | e = NULL                           | e = NULL
1296            // | s = Initiator's static key pair    | s = Responder's static key pair
1297            // | re = NULL                          | re = NULL
1298            // | rs = Responder's static pub key    | rs = NULL
1299            // |                                    |
1300            // | InitSymmetric("Noise_XK1...")      | InitSymmetric("Noise_XK1...")
1301            // | MixHash(prologue)                  | MixHash(prologue)
1302            // | MixHash(rs)                        | MixHash(s.pub)
1303            //
1304            // +-- send_message()
1305            // | e = GenKey()
1306            // | EncryptAndHash(e.pub)
1307            // | EncryptAndHash(payload)
1308            //
1309            //                      -> e, (payload)
1310            //
1311            //                                      +-- recv_message()
1312            //                                      | re = DecryptAndHash()
1313            //                                      | payload = DecryptAndHash()
1314            //
1315            //                                      +-- send_message()
1316            //                                      | e = GenKey()
1317            //                                      | EncryptAndHash(e.pub)
1318            //                                      | MixKeyDh(e.sec, re)
1319            //                                      | MixKeyDh(s.sec, re)
1320            //                                      | EncryptAndHash(payload)
1321            //
1322            //                      <- e, ee, es, (payload)
1323            //
1324            // +-- recv_message()
1325            // | re = DecryptAndHash()
1326            // | MixKeyDh(e.sec, re)
1327            // | MixKeyDh(e.sec, rs)
1328            // | payload = DecryptAndHash()
1329            //
1330            // +-- send_message()
1331            // | EncryptAndHash(s.pub)
1332            // | MixKeyDh(s.sec, re)
1333            // | EncryptAndHash(payload)
1334            // | Split()
1335            //
1336            //                      -> s, se, (payload)
1337            //
1338            //                                      +-- recv_message()
1339            //                                      | rs = DecryptAndHash()
1340            //                                      | MixKeyDh(e.sec, rs)
1341            //                                      | payload = DecryptAndHash()
1342            //                                      | Split()
1343            //
1344            Handshake::XK1 => {
1345                match role {
1346                    Initiator => &[
1347                        /* init */
1348                        Start,
1349                        MixHash(Prologue),
1350                        MixHash(Rs),
1351                        /* send */
1352                        GenKey,
1353                        EncryptAndHash(Epub),
1354                        EncryptAndHash(Payload),
1355                        Stop,
1356                        /* recv */
1357                        Start,
1358                        DecryptAndHash(Re),
1359                        MixKeyDh(Esec, Re),
1360                        MixKeyDh(Esec, Rs),
1361                        DecryptAndHash(Payload),
1362                        Stop,
1363                        /* send */
1364                        Start,
1365                        EncryptAndHash(Spub),
1366                        MixKeyDh(Ssec, Re),
1367                        EncryptAndHash(Payload),
1368                        GetHandshakeHash,
1369                        Split,
1370                    ],
1371                    Responder => &[
1372                        /* init */
1373                        Start,
1374                        MixHash(Prologue),
1375                        MixHash(Spub),
1376                        /* recv */
1377                        DecryptAndHash(Re),
1378                        DecryptAndHash(Payload),
1379                        Stop,
1380                        /* send */
1381                        Start,
1382                        GenKey,
1383                        EncryptAndHash(Epub),
1384                        MixKeyDh(Esec, Re),
1385                        MixKeyDh(Ssec, Re),
1386                        EncryptAndHash(Payload),
1387                        Stop,
1388                        /* recv */
1389                        Start,
1390                        DecryptAndHash(Rs),
1391                        MixKeyDh(Esec, Rs),
1392                        DecryptAndHash(Payload),
1393                        GetHandshakeHash,
1394                        Split,
1395                    ],
1396                }
1397            }
1398            // KK1_Strobe Session Setup
1399            // ========================
1400            //
1401            // Initiator                            Responder
1402            //
1403            //                      -> s
1404            //                      <- s
1405            //                      ...
1406            //
1407            // +-- init()                           +-- init()
1408            // | e = NULL                           | e = NULL
1409            // | s = Initiator's static key pair    | s = Responder's static key pair
1410            // | re = NULL                          | re = NULL
1411            // | rs = Responder's static pub key    | rs = Initiator's static pub key
1412            // |                                    |
1413            // | InitSymmetric("Noise_KK1...")      | InitSymmetric("Noise_KK1...")
1414            // | MixHash(prologue)                  | MixHash(prologue)
1415            // | MixHash(s.pub)                     | MixHash(rs)
1416            // | MixHash(rs)                        | MixHash(s.pub)
1417            //
1418            // +-- send_message()
1419            // | e = GenKey
1420            // | EncryptAndHash(e.pub)
1421            // | EncryptAndHash(payload)
1422            //
1423            //                      -> e, (payload)
1424            //
1425            //                                      +-- recv_message()
1426            //                                      | re = DecryptAndHash()
1427            //                                      | payload = DecryptAndHash()
1428            //
1429            //                                      +-- send_message()
1430            //                                      | e = GenKey()
1431            //                                      | EncryptAndHash(e.pub)
1432            //                                      | MixKeyDh(e.sec, re)
1433            //                                      | MixKeyDh(s.sec, re)
1434            //                                      | MixKeyDh(e.sec, rs)
1435            //                                      | EncryptAndHash(payload)
1436            //                                      | Split()
1437            //
1438            //                      <- e, ee, se, es, (payload)
1439            //
1440            // +-- recv_message()
1441            // | re = DecryptAndHash()
1442            // | MixKeyDh(e.sec, re)
1443            // | MixKeyDh(e.sec, rs)
1444            // | MixKeyDh(s.sec, re)
1445            // | payload = DecryptAndHash()
1446            // | Split()
1447            //
1448            Handshake::KK1 => {
1449                match role {
1450                    Initiator => &[
1451                        /* init */
1452                        Start,
1453                        MixHash(Prologue),
1454                        MixHash(Spub),
1455                        MixHash(Rs),
1456                        /* send */
1457                        GenKey,
1458                        EncryptAndHash(Epub),
1459                        EncryptAndHash(Payload),
1460                        Stop,
1461                        /* recv */
1462                        Start,
1463                        DecryptAndHash(Re),
1464                        MixKeyDh(Esec, Re),
1465                        MixKeyDh(Esec, Rs),
1466                        MixKeyDh(Ssec, Re),
1467                        DecryptAndHash(Payload),
1468                        GetHandshakeHash,
1469                        Split,
1470                    ],
1471                    Responder => &[
1472                        /* init */
1473                        Start,
1474                        MixHash(Prologue),
1475                        MixHash(Rs),
1476                        MixHash(Spub),
1477                        /* recv */
1478                        DecryptAndHash(Re),
1479                        DecryptAndHash(Payload),
1480                        Stop,
1481                        /* send */
1482                        Start,
1483                        GenKey,
1484                        EncryptAndHash(Epub),
1485                        MixKeyDh(Esec, Re),
1486                        MixKeyDh(Ssec, Re),
1487                        MixKeyDh(Esec, Rs),
1488                        EncryptAndHash(Payload),
1489                        GetHandshakeHash,
1490                        Split,
1491                    ],
1492                }
1493            }
1494            // NNpsk2_Strobe Session Setup
1495            // =======================
1496            //
1497            // Initiator                            Responder
1498            //
1499            // +-- init()                           +-- init()
1500            // | e = NULL                           | e = NULL
1501            // | s = NULL                           | s = NULL
1502            // | re = NULL                          | re = NULL
1503            // | rs = NULL                          | rs = NULL
1504            // | psk = pre-shared key value         | psk = pre-shared key value
1505            // |                                    |
1506            // | InitSymmetric("Noise_NNpsk2...")   | InitSymmetric("Noise_NNpsk2...")
1507            // | MixHash(prologue)                  | MixHash(prologue)
1508            //
1509            // +-- send_message()
1510            // | e = GenKey()
1511            // | EncryptAndHash(e.pub)
1512            // | EncryptAndHash(payload)
1513            //
1514            //                      -> e, (payload)
1515            //
1516            //                                      +-- recv_message()
1517            //                                      | re = DecryptAndHash()
1518            //                                      | payload = DecryptAndHash()
1519            //
1520            //                                      +-- send_message()
1521            //                                      | e = GenKey()
1522            //                                      | EncryptAndHash(e.pub)
1523            //                                      | MixKeyDh(e.sec, re)
1524            //                                      | MixKey(psk)
1525            //                                      | EncryptAndHash(payload)
1526            //                                      | Split()
1527            //
1528            //                      <- e, ee, psk, (payload)
1529            //
1530            // +-- recv_message()
1531            // | re = DecryptAndHash()
1532            // | MixKeyDh(e.sec, re)
1533            // | MixKey(psk)
1534            // | payload = DecryptAndHash()
1535            // | Split()
1536            //
1537            Handshake::NNpsk2 => {
1538                match role {
1539                    Initiator => &[
1540                        /* init */
1541                        Start,
1542                        MixHash(Prologue),
1543                        /* send */
1544                        GenKey,
1545                        EncryptAndHash(Epub),
1546                        EncryptAndHash(Payload),
1547                        Stop,
1548                        /* recv */
1549                        Start,
1550                        DecryptAndHash(Re),
1551                        MixKeyDh(Esec, Re),
1552                        MixKey(Psk),
1553                        DecryptAndHash(Payload),
1554                        GetHandshakeHash,
1555                        Split,
1556                    ],
1557                    Responder => &[
1558                        /* init */
1559                        Start,
1560                        MixHash(Prologue),
1561                        /* recv */
1562                        DecryptAndHash(Re),
1563                        DecryptAndHash(Payload),
1564                        Stop,
1565                        /* send */
1566                        Start,
1567                        GenKey,
1568                        EncryptAndHash(Epub),
1569                        MixKeyDh(Esec, Re),
1570                        MixKey(Psk),
1571                        EncryptAndHash(Payload),
1572                        GetHandshakeHash,
1573                        Split,
1574                    ],
1575                }
1576            }
1577        }
1578    }
1579
1580    /// True if handshake pattern requires local static key
1581    pub fn needs_local_static_key(&self, role: &ChannelRole) -> bool {
1582        use ChannelRole::*;
1583        use Handshake::*;
1584        match role {
1585            Initiator => match self {
1586                N | Npsk0 | NN | NK | NX | NNpsk2 => false,
1587                K | X | Kpsk0 | Xpsk1 | KK | XX | IK | IX | XK1 | KK1 => true,
1588            },
1589            Responder => match self {
1590                N | Npsk0 | NN | NNpsk2 => false,
1591                K | X | Kpsk0 | Xpsk1 | KK | XX | IK | IX | NK | NX | XK1 | KK1 => true,
1592            },
1593        }
1594    }
1595
1596    /// True if handshake pattern requires remote static public key before the handshake
1597    pub fn needs_remote_static_key(&self, role: &ChannelRole) -> bool {
1598        use ChannelRole::*;
1599        use Handshake::*;
1600        match role {
1601            Initiator => match self {
1602                N | K | X | Npsk0 | Kpsk0 | Xpsk1 | KK | IK | NK | XK1 | KK1 => true,
1603                IX | NN | XX | NX | NNpsk2 => false,
1604            },
1605            Responder => match self {
1606                K | Kpsk0 | KK | KK1 => true,
1607                N | X | Npsk0 | Xpsk1 | NN | XX | IK | IX | NK | NX | XK1 | NNpsk2 => false,
1608            },
1609        }
1610    }
1611
1612    /// True if the handshake pattern and my role requires me to mix my static pub key
1613    pub fn mix_local_static_key(&self, role: &ChannelRole) -> bool {
1614        use ChannelRole::*;
1615        use Handshake::*;
1616        match role {
1617            Initiator => match self {
1618                K | Kpsk0 | KK | KK1 => true,
1619                N | X | Npsk0 | Xpsk1 | NN | XX | IK | IX | NK | NX | XK1 | NNpsk2 => false,
1620            },
1621            Responder => match self {
1622                N | K | X | Npsk0 | Kpsk0 | Xpsk1 | KK | IK | NK | XK1 | KK1 => true,
1623                NN | XX | IX | NX | NNpsk2 => false,
1624            },
1625        }
1626    }
1627
1628    /// True if the handshake pattern and my role requires me to mix the remote static pub key
1629    pub fn mix_remote_static_key(&self, role: &ChannelRole) -> bool {
1630        use ChannelRole::*;
1631        use Handshake::*;
1632        match role {
1633            Initiator => match self {
1634                N | K | X | Npsk0 | Kpsk0 | Xpsk1 | KK | IK | NK | XK1 | KK1 => true,
1635                NN | XX | IX | NX | NNpsk2 => false,
1636            },
1637            Responder => match self {
1638                K | Kpsk0 | KK | KK1 => true,
1639                N | X | Npsk0 | Xpsk1 | NN | XX | IK | IX | NK | NX | XK1 | NNpsk2 => false,
1640            },
1641        }
1642    }
1643
1644    /// True if the handshake pattern requires a pre-shared key before the handshake
1645    pub fn needs_pre_shared_key(&self, _role: &ChannelRole) -> bool {
1646        use Handshake::*;
1647        match self {
1648            Npsk0 | Kpsk0 | Xpsk1 | NNpsk2 => true,
1649            _ => false,
1650        }
1651    }
1652
1653    /// True if handshake pattern defers the local DH operation
1654    pub fn local_dh_is_deferred(&self, role: &ChannelRole) -> bool {
1655        use ChannelRole::*;
1656        use Handshake::*;
1657        match role {
1658            Initiator => false,
1659            Responder => match self {
1660                N | K | X | Npsk0 | Kpsk0 | Xpsk1 | NN | KK | XX | IK | IX | NK | NX | NNpsk2 => {
1661                    false
1662                }
1663                XK1 | KK1 => true,
1664            },
1665        }
1666    }
1667
1668    /// True if handshake pattern defers the remote DH operation
1669    pub fn remote_dh_is_deferred(&self, role: &ChannelRole) -> bool {
1670        use ChannelRole::*;
1671        use Handshake::*;
1672        match role {
1673            Initiator => match self {
1674                N | K | X | Npsk0 | Kpsk0 | Xpsk1 | NN | KK | XX | IK | IX | NK | NX | NNpsk2 => {
1675                    false
1676                }
1677                XK1 | KK1 => true,
1678            },
1679            Responder => false,
1680        }
1681    }
1682}
1683
1684impl FromStr for Handshake {
1685    type Err = Error;
1686
1687    fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
1688        use self::Handshake::*;
1689        match s {
1690            "N" => Ok(N),
1691            "K" => Ok(K),
1692            "X" => Ok(X),
1693            "Npsk0" => Ok(Npsk0),
1694            "Kpsk0" => Ok(Kpsk0),
1695            "Xpsk1" => Ok(Xpsk1),
1696            "NN" => Ok(NN),
1697            "KK" => Ok(KK),
1698            "XX" => Ok(XX),
1699            "IK" => Ok(IK),
1700            "IX" => Ok(IX),
1701            "NK" => Ok(NK),
1702            "NX" => Ok(NX),
1703            "XK1" => Ok(XK1),
1704            "KK1" => Ok(KK1),
1705            "NNpsk2" => Ok(NNpsk2),
1706            _ => Err(Error::Param(ParamError::InvalidHandshake)),
1707        }
1708    }
1709}
1710
1711impl Display for Handshake {
1712    fn fmt(&self, f: &mut Formatter<'_>) -> std::result::Result<(), FmtError> {
1713        use self::Handshake::*;
1714        match self {
1715            N => write!(f, "N"),
1716            K => write!(f, "K"),
1717            X => write!(f, "X"),
1718            Npsk0 => write!(f, "Npsk0"),
1719            Kpsk0 => write!(f, "Kpsk0"),
1720            Xpsk1 => write!(f, "Xpsk1"),
1721            NN => write!(f, "NN"),
1722            KK => write!(f, "KK"),
1723            XX => write!(f, "XX"),
1724            IK => write!(f, "IK"),
1725            IX => write!(f, "IX"),
1726            NK => write!(f, "NK"),
1727            NX => write!(f, "NX"),
1728            XK1 => write!(f, "XK1"),
1729            KK1 => write!(f, "KK1"),
1730            NNpsk2 => write!(f, "NNpsk2"),
1731        }
1732    }
1733}