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}