Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
167 changes: 159 additions & 8 deletions crates/networking/p2p/discv5/messages.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,16 @@ impl Packet {
<Aes128Ctr64BE as KeyIvInit>::new(dest_id[..16].into(), masking_as_bytes[..].into());

match self {
Packet::Ordinary(_ordinary) => todo!(),
Packet::Ordinary(ordinary) => {
let (mut static_header, mut authdata, encrypted_message) =
ordinary.encode(&nonce, &masking_as_bytes, encrypt_key)?;

cipher.try_apply_keystream(&mut static_header)?;
buf.put_slice(&static_header);
cipher.try_apply_keystream(&mut authdata)?;
buf.put_slice(&authdata);
buf.put_slice(&encrypted_message);
}
Packet::WhoAreYou(who_are_you) => {
who_are_you.encode_header(buf, &mut cipher, nonce)?;
}
Expand Down Expand Up @@ -186,10 +195,56 @@ impl Packet {

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Ordinary {
message: Message,
pub src_id: H256,
pub message: Message,
}

impl Ordinary {
fn encode_authdata(&self, buf: &mut dyn BufMut) -> Result<(), PacketDecodeErr> {
buf.put_slice(self.src_id.as_bytes());
Ok(())
}

/// Encodes the ordinary packet returning the header, authdata and encrypted_message
#[allow(clippy::type_complexity)]
fn encode(
&self,
nonce: &[u8],
masking_iv: &[u8],
encrypt_key: &[u8],
) -> Result<(Vec<u8>, Vec<u8>, Vec<u8>), PacketDecodeErr> {
if encrypt_key.len() < 16 {
return Err(PacketDecodeErr::InvalidSize);
}

let mut authdata = Vec::new();
self.encode_authdata(&mut authdata)?;

let authdata_size: u16 =
u16::try_from(authdata.len()).map_err(|_| PacketDecodeErr::InvalidSize)?;

let mut static_header = Vec::new();
static_header.put_slice(PROTOCOL_ID);
static_header.put_slice(&PROTOCOL_VERSION.to_be_bytes());
static_header.put_u8(0x0);
static_header.put_slice(nonce);
static_header.put_slice(&authdata_size.to_be_bytes());

let mut message = Vec::new();
self.message.encode(&mut message);

let mut message_ad = masking_iv.to_vec();
message_ad.extend_from_slice(&static_header);
message_ad.extend_from_slice(&authdata);

let mut cipher = Aes128Gcm::new(encrypt_key[..16].into());
cipher
.encrypt_in_place(nonce.into(), &message_ad, &mut message)
.map_err(|e| PacketDecodeErr::ChipherError(e.to_string()))?;

Ok((static_header, authdata, message))
}

pub fn decode(
masking_iv: &[u8],
static_header: Vec<u8>,
Expand All @@ -198,6 +253,10 @@ impl Ordinary {
decrypt_key: &[u8],
encrypted_message: &[u8],
) -> Result<Ordinary, PacketDecodeErr> {
if authdata.len() != 32 {
return Err(PacketDecodeErr::InvalidSize);
}

// message = aesgcm_encrypt(initiator-key, nonce, message-pt, message-ad)
// message-pt = message-type || message-data
// message-ad = masking-iv || header
Expand All @@ -208,8 +267,10 @@ impl Ordinary {
let mut message = encrypted_message.to_vec();
Self::decrypt(decrypt_key, nonce, &mut message, message_ad)?;

let src_id = H256::from_slice(&authdata);

let message = Message::decode(&message)?;
Ok(Ordinary { message })
Ok(Ordinary { src_id, message })
}

fn decrypt(
Expand Down Expand Up @@ -847,6 +908,59 @@ mod tests {
assert_eq!(buf, encoded.to_vec());
}

/// Ping handshake message packet (flag 2, with ENR) from https://github.com/ethereum/devp2p/blob/master/discv5/discv5-wire-test-vectors.md
#[test]
fn handshake_packet_with_enr_vector_test_roundtrip() {
let node_b_key = SecretKey::from_byte_array(&hex!(
"66fb62bfbd66b9177a138c1e5cddbe4f7c30c343e94e68df8769459cb1cde628"
))
.unwrap();
let dest_id = node_id(&public_key_from_signing_key(&node_b_key));

let encoded = &hex!(
"00000000000000000000000000000000088b3d4342774649305f313964a39e55ea96c005ad539c8c7560413a7008f16c9e6d2f43bbea8814a546b7409ce783d34c4f53245d08da4bb23698868350aaad22e3ab8dd034f548a1c43cd246be98562fafa0a1fa86d8e7a3b95ae78cc2b988ded6a5b59eb83ad58097252188b902b21481e30e5e285f19735796706adff216ab862a9186875f9494150c4ae06fa4d1f0396c93f215fa4ef524e0ed04c3c21e39b1868e1ca8105e585ec17315e755e6cfc4dd6cb7fd8e1a1f55e49b4b5eb024221482105346f3c82b15fdaae36a3bb12a494683b4a3c7f2ae41306252fed84785e2bbff3b022812d0882f06978df84a80d443972213342d04b9048fc3b1d5fcb1df0f822152eced6da4d3f6df27e70e4539717307a0208cd208d65093ccab5aa596a34d7511401987662d8cf62b139471"
);
let nonce = hex!("ffffffffffffffffffffffff").to_vec();
let read_key = hex!("53b1c075f41876423154e157470c2f48").to_vec();

let packet = Packet::decode(&dest_id, &read_key, encoded).unwrap();
let handshake = match packet {
Packet::Handshake(hs) => hs,
other => panic!("unexpected packet {other:?}"),
};

assert_eq!(
handshake.src_id,
H256::from_slice(&hex!(
"aaaa8419e9f49d0083561b48287df592939a8d19947d8c0ef88f2a4856a69fbb"
))
);
assert_eq!(
handshake.eph_pubkey,
hex!("039a003ba6517b473fa0cd74aefe99dadfdb34627f90fec6362df85803908f53a5").to_vec()
);
assert_eq!(
handshake.message,
Message::Ping(PingMessage {
req_id: hex!("00000001").to_vec(),
enr_seq: 1,
})
);

let record = handshake.record.clone().expect("expected ENR record");
let pairs = record.decode_pairs();
assert_eq!(pairs.id.as_deref(), Some("v4"));
assert!(pairs.secp256k1.is_some());

let masking_iv = u128::from_be_bytes(encoded[..16].try_into().unwrap());
let mut buf = Vec::new();
Packet::Handshake(handshake)
.encode(&mut buf, masking_iv, &nonce, &dest_id, &read_key)
.unwrap();

assert_eq!(buf, encoded.to_vec());
}

#[test]
fn test_encode_whoareyou_packet() {
// # src-node-id = 0xaaaa8419e9f49d0083561b48287df592939a8d19947d8c0ef88f2a4856a69fbb
Expand Down Expand Up @@ -926,11 +1040,6 @@ mod tests {
assert_eq!(packet, expected);
}

#[test]
fn test_encode_ping_message() {
// TODO
}

#[test]
fn test_decode_ping_packet() {
// # src-node-id = 0xaaaa8419e9f49d0083561b48287df592939a8d19947d8c0ef88f2a4856a69fbb
Expand All @@ -943,11 +1052,17 @@ mod tests {
// 00000000000000000000000000000000088b3d4342774649325f313964a39e55
// ea96c005ad52be8c7560413a7008f16c9e6d2f43bbea8814a546b7409ce783d3
// 4c4f53245d08dab84102ed931f66d1492acb308fa1c6715b9d139b81acbdcc

let node_a_key = SecretKey::from_byte_array(&hex!(
"eef77acb6c6a6eebc5b363a475ac583ec7eccdb42b6481424c60f59aa326547f"
))
.unwrap();
let node_b_key = SecretKey::from_byte_array(&hex!(
"66fb62bfbd66b9177a138c1e5cddbe4f7c30c343e94e68df8769459cb1cde628"
))
.unwrap();

let src_id = node_id(&public_key_from_signing_key(&node_a_key));
let dest_id = node_id(&public_key_from_signing_key(&node_b_key));

let encoded = &hex!(
Expand All @@ -957,6 +1072,7 @@ mod tests {
let read_key = [0; 16].to_vec();
let packet = Packet::decode(&dest_id, &read_key, encoded).unwrap();
let expected = Packet::Ordinary(Ordinary {
src_id,
message: Message::Ping(PingMessage {
req_id: hex!("00000001").to_vec(),
enr_seq: 2,
Expand All @@ -966,6 +1082,41 @@ mod tests {
assert_eq!(packet, expected);
}

/// Ping message packet (flag 0) from https://github.com/ethereum/devp2p/blob/master/discv5/discv5-wire-test-vectors.md
#[test]
fn ordinary_ping_packet_vector_test_roundtrip() {
let node_b_key = SecretKey::from_byte_array(&hex!(
"66fb62bfbd66b9177a138c1e5cddbe4f7c30c343e94e68df8769459cb1cde628"
))
.unwrap();
let dest_id = node_id(&public_key_from_signing_key(&node_b_key));

let encoded = &hex!(
"00000000000000000000000000000000088b3d4342774649325f313964a39e55ea96c005ad52be8c7560413a7008f16c9e6d2f43bbea8814a546b7409ce783d34c4f53245d08dab84102ed931f66d1492acb308fa1c6715b9d139b81acbdcc"
);
let nonce = hex!("ffffffffffffffffffffffff").to_vec();
let read_key = [0; 16].to_vec();

let packet = Packet::decode(&dest_id, &read_key, encoded).unwrap();
let expected = Packet::Ordinary(Ordinary {
src_id: H256::from_slice(&hex!(
"aaaa8419e9f49d0083561b48287df592939a8d19947d8c0ef88f2a4856a69fbb"
)),
message: Message::Ping(PingMessage {
req_id: hex!("00000001").to_vec(),
enr_seq: 2,
}),
});
assert_eq!(packet, expected);

let masking_iv = u128::from_be_bytes(encoded[..16].try_into().unwrap());
let mut buf = Vec::new();
packet
.encode(&mut buf, masking_iv, &nonce, &dest_id, &read_key)
.unwrap();
assert_eq!(buf, encoded.to_vec());
}

#[test]
fn ping_packet_codec_roundtrip() {
let pkt = PingMessage {
Expand Down