Skip to content
This repository was archived by the owner on Dec 10, 2022. It is now read-only.

Commit 8b75c57

Browse files
authored
Merge pull request #35 from tox-rs/dht_cookie_request
feat(dht): add CookieRequest & CookieRequestPayload packet parsing
2 parents 1e41101 + f7f21e9 commit 8b75c57

File tree

1 file changed

+162
-1
lines changed

1 file changed

+162
-1
lines changed

src/toxcore/dht_new/packet.rs

+162-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@ pub enum DhtPacket {
5050
NodesRequest(NodesRequest),
5151
/// [`NodesResponse`](./struct.NodesResponse.html) structure.
5252
NodesResponse(NodesResponse),
53-
// TODO: CookieRequest
53+
/// [`CookieRequest`](./struct.CookieRequest.html) structure.
54+
CookieRequest(CookieRequest),
5455
// TODO: CookieResponse
5556
// TODO: CryptoHandshake
5657
// TODO: CryptoData
@@ -89,6 +90,7 @@ impl ToBytes for DhtPacket {
8990
DhtPacket::PingResponse(ref p) => p.to_bytes(buf),
9091
DhtPacket::NodesRequest(ref p) => p.to_bytes(buf),
9192
DhtPacket::NodesResponse(ref p) => p.to_bytes(buf),
93+
DhtPacket::CookieRequest(ref p) => p.to_bytes(buf),
9294
DhtPacket::DhtRequest(ref p) => p.to_bytes(buf),
9395
DhtPacket::LanDiscovery(ref p) => p.to_bytes(buf),
9496
DhtPacket::OnionRequest0(ref p) => p.to_bytes(buf),
@@ -112,6 +114,7 @@ impl FromBytes for DhtPacket {
112114
map!(PingResponse::from_bytes, DhtPacket::PingResponse) |
113115
map!(NodesRequest::from_bytes, DhtPacket::NodesRequest) |
114116
map!(NodesResponse::from_bytes, DhtPacket::NodesResponse) |
117+
map!(CookieRequest::from_bytes, DhtPacket::CookieRequest) |
115118
map!(DhtRequest::from_bytes, DhtPacket::DhtRequest) |
116119
map!(LanDiscovery::from_bytes, DhtPacket::LanDiscovery) |
117120
map!(OnionRequest0::from_bytes, DhtPacket::OnionRequest0) |
@@ -607,6 +610,147 @@ impl FromBytes for NodesResponsePayload {
607610
));
608611
}
609612

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+
610754
/** DHT Request packet struct.
611755
612756
https://zetok.github.io/tox-spec/#dht-request-packets
@@ -1210,6 +1354,15 @@ mod tests {
12101354

12111355
dht_packet_encode_decode!(nodes_response_encode_decode, NodesResponse);
12121356

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+
12131366
encode_decode_test!(
12141367
nat_ping_request_payload_encode_decode,
12151368
DhtRequestPayload::NatPingRequest(NatPingRequest { id: 42 })
@@ -1410,6 +1563,12 @@ mod tests {
14101563
], id: 42 }
14111564
);
14121565

1566+
dht_packet_encrypt_decrypt!(
1567+
cookie_request_payload_encrypt_decrypt,
1568+
CookieRequest,
1569+
CookieRequestPayload { pk: gen_keypair().0, id: 42 }
1570+
);
1571+
14131572
#[test]
14141573
fn dht_request_payload_encrypt_decrypt() {
14151574
let (alice_pk, alice_sk) = gen_keypair();
@@ -1473,6 +1632,8 @@ mod tests {
14731632

14741633
dht_packet_decode_invalid!(nodes_response_decode_invalid, NodesResponse);
14751634

1635+
dht_packet_decode_invalid!(cookie_request_decode_invalid, CookieRequest);
1636+
14761637
#[test]
14771638
fn dht_request_decode_invalid() {
14781639
let (alice_pk, alice_sk) = gen_keypair();

0 commit comments

Comments
 (0)