@@ -50,7 +50,8 @@ pub enum DhtPacket {
50
50
NodesRequest ( NodesRequest ) ,
51
51
/// [`NodesResponse`](./struct.NodesResponse.html) structure.
52
52
NodesResponse ( NodesResponse ) ,
53
- // TODO: CookieRequest
53
+ /// [`CookieRequest`](./struct.CookieRequest.html) structure.
54
+ CookieRequest ( CookieRequest ) ,
54
55
// TODO: CookieResponse
55
56
// TODO: CryptoHandshake
56
57
// TODO: CryptoData
@@ -89,6 +90,7 @@ impl ToBytes for DhtPacket {
89
90
DhtPacket :: PingResponse ( ref p) => p. to_bytes ( buf) ,
90
91
DhtPacket :: NodesRequest ( ref p) => p. to_bytes ( buf) ,
91
92
DhtPacket :: NodesResponse ( ref p) => p. to_bytes ( buf) ,
93
+ DhtPacket :: CookieRequest ( ref p) => p. to_bytes ( buf) ,
92
94
DhtPacket :: DhtRequest ( ref p) => p. to_bytes ( buf) ,
93
95
DhtPacket :: LanDiscovery ( ref p) => p. to_bytes ( buf) ,
94
96
DhtPacket :: OnionRequest0 ( ref p) => p. to_bytes ( buf) ,
@@ -112,6 +114,7 @@ impl FromBytes for DhtPacket {
112
114
map!( PingResponse :: from_bytes, DhtPacket :: PingResponse ) |
113
115
map!( NodesRequest :: from_bytes, DhtPacket :: NodesRequest ) |
114
116
map!( NodesResponse :: from_bytes, DhtPacket :: NodesResponse ) |
117
+ map!( CookieRequest :: from_bytes, DhtPacket :: CookieRequest ) |
115
118
map!( DhtRequest :: from_bytes, DhtPacket :: DhtRequest ) |
116
119
map!( LanDiscovery :: from_bytes, DhtPacket :: LanDiscovery ) |
117
120
map!( OnionRequest0 :: from_bytes, DhtPacket :: OnionRequest0 ) |
@@ -607,6 +610,147 @@ impl FromBytes for NodesResponsePayload {
607
610
) ) ;
608
611
}
609
612
613
+ /** CookieRequest packet struct.
614
+ According to https://zetok.github.io/tox-spec/#net-crypto
615
+
616
+ CookieRequest packet (145 bytes):
617
+
618
+ [uint8_t 24]
619
+ [Sender's DHT Public key (32 bytes)]
620
+ [Random nonce (24 bytes)]
621
+ [Encrypted message containing:
622
+ [Sender's real public key (32 bytes)]
623
+ [padding (32 bytes)]
624
+ [uint64_t echo id (must be sent back untouched in cookie response)]
625
+ ]
626
+
627
+ Serialized form:
628
+
629
+ Length | Content
630
+ ------ | ------
631
+ `1` | `0x18`
632
+ `32` | DHT Public Key
633
+ `24` | Random nonce
634
+ `88` | Encrypted CookieRequestPayload
635
+
636
+ */
637
+ #[ derive( Clone , Debug , Eq , PartialEq ) ]
638
+ pub struct CookieRequest {
639
+ /// DHT public key
640
+ pub pk : PublicKey ,
641
+ /// Random nonce
642
+ pub nonce : Nonce ,
643
+ /// Encrypted payload of CookieRequest
644
+ pub payload : Vec < u8 > ,
645
+ }
646
+
647
+ impl ToBytes for CookieRequest {
648
+ fn to_bytes < ' a > ( & self , buf : ( & ' a mut [ u8 ] , usize ) ) -> Result < ( & ' a mut [ u8 ] , usize ) , GenError > {
649
+ do_gen ! ( buf,
650
+ gen_be_u8!( 0x18 ) >>
651
+ gen_slice!( self . pk. as_ref( ) ) >>
652
+ gen_slice!( self . nonce. as_ref( ) ) >>
653
+ gen_slice!( self . payload. as_slice( ) )
654
+ )
655
+ }
656
+ }
657
+
658
+ impl FromBytes for CookieRequest {
659
+ named ! ( from_bytes<CookieRequest >, do_parse!(
660
+ tag!( "\x18 " ) >>
661
+ pk: call!( PublicKey :: from_bytes) >>
662
+ nonce: call!( Nonce :: from_bytes) >>
663
+ payload: take!( 88 ) >>
664
+ ( CookieRequest { pk, nonce, payload: payload. to_vec( ) } )
665
+ ) ) ;
666
+ }
667
+
668
+ impl CookieRequest {
669
+ /// Create `CookieRequest` from `CookieRequestPayload` encrypting in with `shared_key`
670
+ pub fn new ( shared_secret : & PrecomputedKey , pk : & PublicKey , payload : CookieRequestPayload ) -> CookieRequest {
671
+ let nonce = & gen_nonce ( ) ;
672
+ let mut buf = [ 0 ; 88 ] ;
673
+ let ( _, size) = payload. to_bytes ( ( & mut buf, 0 ) ) . unwrap ( ) ;
674
+ let payload = seal_precomputed ( & buf[ ..size] , nonce, shared_secret) ;
675
+
676
+ CookieRequest {
677
+ pk : * pk,
678
+ nonce : * nonce,
679
+ payload : payload,
680
+ }
681
+ }
682
+ /** Decrypt payload with symmetric key and try to parse it as `CookieRequestPayload`.
683
+
684
+ Returns `Error` in case of failure:
685
+
686
+ - fails to decrypt
687
+ - fails to parse `CookieRequestPayload`
688
+ */
689
+ pub fn get_payload ( & self , own_secret_key : & SecretKey ) -> Result < CookieRequestPayload , Error > {
690
+ let decrypted = open ( & self . payload , & self . nonce , & self . pk , own_secret_key)
691
+ . map_err ( |e| {
692
+ debug ! ( "Decrypting CookieRequest failed!" ) ;
693
+ Error :: new ( ErrorKind :: Other ,
694
+ format ! ( "CookieRequest decrypt error: {:?}" , e) )
695
+ } ) ?;
696
+ match CookieRequestPayload :: from_bytes ( & decrypted) {
697
+ IResult :: Incomplete ( e) => {
698
+ error ! ( target: "Dht" , "CookieRequestPayload return deserialize error: {:?}" , e) ;
699
+ Err ( Error :: new ( ErrorKind :: Other ,
700
+ format ! ( "CookieRequestPayload return deserialize error: {:?}" , e) ) )
701
+ } ,
702
+ IResult :: Error ( e) => {
703
+ error ! ( target: "Dht" , "CookieRequestPayload return deserialize error: {:?}" , e) ;
704
+ Err ( Error :: new ( ErrorKind :: Other ,
705
+ format ! ( "CookieRequestPayload return deserialize error: {:?}" , e) ) )
706
+ } ,
707
+ IResult :: Done ( _, payload) => {
708
+ Ok ( payload)
709
+ }
710
+ }
711
+ }
712
+ }
713
+
714
+ /** CookieRequestPayload packet struct.
715
+
716
+ Serialized form:
717
+
718
+ Length | Contents
719
+ ----------- | --------
720
+ `32` | Sender's real public key
721
+ `32` | Padding (zeros)
722
+ `8` | Request ID in BigEndian
723
+
724
+ Serialized form should be put in the encrypted part of `CookieRequest` packet.
725
+ */
726
+ #[ derive( Clone , Debug , Eq , PartialEq ) ]
727
+ pub struct CookieRequestPayload {
728
+ /// Sender's real public key
729
+ pub pk : PublicKey ,
730
+ /// Request id
731
+ pub id : u64 ,
732
+ }
733
+
734
+ impl ToBytes for CookieRequestPayload {
735
+ fn to_bytes < ' a > ( & self , buf : ( & ' a mut [ u8 ] , usize ) ) -> Result < ( & ' a mut [ u8 ] , usize ) , GenError > {
736
+ do_gen ! ( buf,
737
+ gen_slice!( self . pk. as_ref( ) ) >>
738
+ gen_slice!( & [ 0 ; 32 ] ) >> // padding
739
+ gen_be_u64!( self . id)
740
+ )
741
+ }
742
+ }
743
+
744
+ impl FromBytes for CookieRequestPayload {
745
+ named ! ( from_bytes<CookieRequestPayload >, do_parse!(
746
+ pk: call!( PublicKey :: from_bytes) >>
747
+ take!( 32 ) >> // padding
748
+ id: be_u64 >>
749
+ eof!( ) >>
750
+ ( CookieRequestPayload { pk, id } )
751
+ ) ) ;
752
+ }
753
+
610
754
/** DHT Request packet struct.
611
755
612
756
https://zetok.github.io/tox-spec/#dht-request-packets
@@ -1210,6 +1354,15 @@ mod tests {
1210
1354
1211
1355
dht_packet_encode_decode ! ( nodes_response_encode_decode, NodesResponse ) ;
1212
1356
1357
+ encode_decode_test ! (
1358
+ cookie_request_encode_decode,
1359
+ DhtPacket :: CookieRequest ( CookieRequest {
1360
+ pk: gen_keypair( ) . 0 ,
1361
+ nonce: gen_nonce( ) ,
1362
+ payload: vec![ 42 ; 88 ] ,
1363
+ } )
1364
+ ) ;
1365
+
1213
1366
encode_decode_test ! (
1214
1367
nat_ping_request_payload_encode_decode,
1215
1368
DhtRequestPayload :: NatPingRequest ( NatPingRequest { id: 42 } )
@@ -1410,6 +1563,12 @@ mod tests {
1410
1563
] , id: 42 }
1411
1564
) ;
1412
1565
1566
+ dht_packet_encrypt_decrypt ! (
1567
+ cookie_request_payload_encrypt_decrypt,
1568
+ CookieRequest ,
1569
+ CookieRequestPayload { pk: gen_keypair( ) . 0 , id: 42 }
1570
+ ) ;
1571
+
1413
1572
#[ test]
1414
1573
fn dht_request_payload_encrypt_decrypt ( ) {
1415
1574
let ( alice_pk, alice_sk) = gen_keypair ( ) ;
@@ -1473,6 +1632,8 @@ mod tests {
1473
1632
1474
1633
dht_packet_decode_invalid ! ( nodes_response_decode_invalid, NodesResponse ) ;
1475
1634
1635
+ dht_packet_decode_invalid ! ( cookie_request_decode_invalid, CookieRequest ) ;
1636
+
1476
1637
#[ test]
1477
1638
fn dht_request_decode_invalid ( ) {
1478
1639
let ( alice_pk, alice_sk) = gen_keypair ( ) ;
0 commit comments