From 3efca47122696e3ec8ef80e2bad0694eceb71f1d Mon Sep 17 00:00:00 2001 From: David Palm Date: Sat, 1 Jun 2019 19:44:55 +0200 Subject: [PATCH 01/11] Run cargo fix --- util/network-devp2p/src/host.rs | 10 +++++----- util/network-devp2p/src/service.rs | 10 +++++----- util/network-devp2p/tests/tests.rs | 10 +++++----- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/util/network-devp2p/src/host.rs b/util/network-devp2p/src/host.rs index 5f096975178..52c8c4ca74d 100644 --- a/util/network-devp2p/src/host.rs +++ b/util/network-devp2p/src/host.rs @@ -261,17 +261,17 @@ pub struct Host { sessions: Arc>>, discovery: Mutex>>, nodes: RwLock, - handlers: RwLock>>, + handlers: RwLock>>, timers: RwLock>, timer_counter: RwLock, reserved_nodes: RwLock>, stopping: AtomicBool, - filter: Option>, + filter: Option>, } impl Host { /// Create a new instance - pub fn new(mut config: NetworkConfiguration, filter: Option>) -> Result { + pub fn new(mut config: NetworkConfiguration, filter: Option>) -> Result { let mut listen_address = match config.listen_address { None => SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(0, 0, 0, 0), DEFAULT_PORT)), Some(addr) => addr, @@ -976,14 +976,14 @@ impl Host { self.nodes.write().update(node_changes, &*self.reserved_nodes.read()); } - pub fn with_context(&self, protocol: ProtocolId, io: &IoContext, action: F) where F: FnOnce(&NetworkContextTrait) { + pub fn with_context(&self, protocol: ProtocolId, io: &IoContext, action: F) where F: FnOnce(&dyn NetworkContextTrait) { let reserved = { self.reserved_nodes.read() }; let context = NetworkContext::new(io, protocol, None, self.sessions.clone(), &reserved); action(&context); } - pub fn with_context_eval(&self, protocol: ProtocolId, io: &IoContext, action: F) -> T where F: FnOnce(&NetworkContextTrait) -> T { + pub fn with_context_eval(&self, protocol: ProtocolId, io: &IoContext, action: F) -> T where F: FnOnce(&dyn NetworkContextTrait) -> T { let reserved = { self.reserved_nodes.read() }; let context = NetworkContext::new(io, protocol, None, self.sessions.clone(), &reserved); diff --git a/util/network-devp2p/src/service.rs b/util/network-devp2p/src/service.rs index dfacec4be3d..d06122cd26e 100644 --- a/util/network-devp2p/src/service.rs +++ b/util/network-devp2p/src/service.rs @@ -49,12 +49,12 @@ pub struct NetworkService { host: RwLock>>, host_handler: Arc, config: NetworkConfiguration, - filter: Option>, + filter: Option>, } impl NetworkService { /// Starts IO event loop - pub fn new(config: NetworkConfiguration, filter: Option>) -> Result { + pub fn new(config: NetworkConfiguration, filter: Option>) -> Result { let host_handler = Arc::new(HostHandler { public_url: RwLock::new(None) }); let io_service = IoService::::start()?; @@ -71,7 +71,7 @@ impl NetworkService { /// Register a new protocol handler with the event loop. pub fn register_protocol( &self, - handler: Arc, + handler: Arc, protocol: ProtocolId, // version id + packet count versions: &[(u8, u8)] @@ -178,7 +178,7 @@ impl NetworkService { } /// Executes action in the network context - pub fn with_context(&self, protocol: ProtocolId, action: F) where F: FnOnce(&NetworkContext) { + pub fn with_context(&self, protocol: ProtocolId, action: F) where F: FnOnce(&dyn NetworkContext) { let io = IoContext::new(self.io_service.channel(), 0); let host = self.host.read(); if let Some(ref host) = host.as_ref() { @@ -187,7 +187,7 @@ impl NetworkService { } /// Evaluates function in the network context - pub fn with_context_eval(&self, protocol: ProtocolId, action: F) -> Option where F: FnOnce(&NetworkContext) -> T { + pub fn with_context_eval(&self, protocol: ProtocolId, action: F) -> Option where F: FnOnce(&dyn NetworkContext) -> T { let io = IoContext::new(self.io_service.channel(), 0); let host = self.host.read(); host.as_ref().map(|ref host| host.with_context_eval(protocol, &io, action)) diff --git a/util/network-devp2p/tests/tests.rs b/util/network-devp2p/tests/tests.rs index 00f811e4637..5270df6b9c5 100644 --- a/util/network-devp2p/tests/tests.rs +++ b/util/network-devp2p/tests/tests.rs @@ -70,16 +70,16 @@ impl TestProtocol { } impl NetworkProtocolHandler for TestProtocol { - fn initialize(&self, io: &NetworkContext) { + fn initialize(&self, io: &dyn NetworkContext) { io.register_timer(0, Duration::from_millis(10)).unwrap(); } - fn read(&self, _io: &NetworkContext, _peer: &PeerId, packet_id: u8, data: &[u8]) { + fn read(&self, _io: &dyn NetworkContext, _peer: &PeerId, packet_id: u8, data: &[u8]) { assert_eq!(packet_id, 33); self.packet.lock().extend(data); } - fn connected(&self, io: &NetworkContext, peer: &PeerId) { + fn connected(&self, io: &dyn NetworkContext, peer: &PeerId) { assert!(io.peer_client_version(*peer).to_string().contains("Parity")); if self.drop_session { io.disconnect_peer(*peer) @@ -88,12 +88,12 @@ impl NetworkProtocolHandler for TestProtocol { } } - fn disconnected(&self, _io: &NetworkContext, _peer: &PeerId) { + fn disconnected(&self, _io: &dyn NetworkContext, _peer: &PeerId) { self.got_disconnect.store(true, AtomicOrdering::Relaxed); } /// Timer function called after a timeout created with `NetworkContext::timeout`. - fn timeout(&self, _io: &NetworkContext, timer: TimerToken) { + fn timeout(&self, _io: &dyn NetworkContext, timer: TimerToken) { assert_eq!(timer, 0); self.got_timeout.store(true, AtomicOrdering::Relaxed); } From 431eccf359b53681d2f33e39824ddc4368d43240 Mon Sep 17 00:00:00 2001 From: David Palm Date: Sat, 1 Jun 2019 19:45:37 +0200 Subject: [PATCH 02/11] Optimize imports --- util/network-devp2p/src/connection.rs | 28 +++++++----- util/network-devp2p/src/discovery.rs | 33 ++++++++------ util/network-devp2p/src/handshake.rs | 22 +++++---- util/network-devp2p/src/host.rs | 45 +++++++++--------- util/network-devp2p/src/ip_utils.rs | 19 ++++---- util/network-devp2p/src/lib.rs | 66 +++++++++++++-------------- util/network-devp2p/src/node_table.rs | 42 +++++++++-------- util/network-devp2p/src/service.rs | 12 +++-- util/network-devp2p/src/session.rs | 21 +++++---- util/network-devp2p/tests/tests.rs | 8 ++-- 10 files changed, 159 insertions(+), 137 deletions(-) diff --git a/util/network-devp2p/src/connection.rs b/util/network-devp2p/src/connection.rs index ae34ec44cf9..15f601da393 100644 --- a/util/network-devp2p/src/connection.rs +++ b/util/network-devp2p/src/connection.rs @@ -15,26 +15,28 @@ // along with Parity Ethereum. If not, see . use std::collections::VecDeque; +use std::io::{self, Cursor, Read, Write}; use std::net::SocketAddr; use std::sync::atomic::{AtomicBool, Ordering as AtomicOrdering}; use std::time::Duration; + +use bytes::{Buf, BufMut}; +use ethereum_types::{H128, H256, H512}; use hash::{keccak, write_keccak}; -use mio::{Token, Ready, PollOpt}; -use mio::deprecated::{Handler, EventLoop, TryRead, TryWrite}; +use mio::{PollOpt, Ready, Token}; +use mio::deprecated::{EventLoop, Handler, TryRead, TryWrite}; use mio::tcp::*; -use ethereum_types::{H128, H256, H512}; use parity_bytes::*; -use rlp::{Rlp, RlpStream}; -use std::io::{self, Cursor, Read, Write}; -use io::{IoContext, StreamToken}; -use handshake::Handshake; -use rcrypto::blockmodes::*; use rcrypto::aessafe::*; -use rcrypto::symmetriccipher::*; +use rcrypto::blockmodes::*; use rcrypto::buffer::*; +use rcrypto::symmetriccipher::*; +use rlp::{Rlp, RlpStream}; use tiny_keccak::Keccak; -use bytes::{Buf, BufMut}; + use ethkey::crypto; +use handshake::Handshake; +use io::{IoContext, StreamToken}; use network::{Error, ErrorKind}; const ENCRYPTED_HEADER_LEN: usize = 32; @@ -502,12 +504,14 @@ pub fn test_encryption() { mod tests { use std::cmp; use std::collections::VecDeque; - use std::io::{Read, Write, Cursor, ErrorKind, Result, Error}; + use std::io::{Cursor, Error, ErrorKind, Read, Result, Write}; use std::sync::atomic::AtomicBool; - use mio::{Ready}; + use mio::Ready; use parity_bytes::Bytes; + use io::*; + use super::*; pub struct TestSocket { diff --git a/util/network-devp2p/src/discovery.rs b/util/network-devp2p/src/discovery.rs index 7bf8dc62e5e..7c8e4b68445 100644 --- a/util/network-devp2p/src/discovery.rs +++ b/util/network-devp2p/src/discovery.rs @@ -14,21 +14,22 @@ // You should have received a copy of the GNU General Public License // along with Parity Ethereum. If not, see . -use parity_bytes::Bytes; -use std::net::SocketAddr; -use std::collections::{HashSet, HashMap, VecDeque}; +use std::collections::{HashMap, HashSet, VecDeque}; use std::collections::hash_map::Entry; use std::default::Default; +use std::net::SocketAddr; use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH}; -use lru_cache::LruCache; -use hash::keccak; + use ethereum_types::{H256, H520}; +use hash::keccak; +use lru_cache::LruCache; +use parity_bytes::Bytes; use rlp::{Rlp, RlpStream}; -use node_table::*; + +use ethkey::{KeyPair, recover, Secret, sign}; use network::{Error, ErrorKind}; -use ethkey::{Secret, KeyPair, sign, recover}; use network::IpFilter; - +use node_table::*; use PROTOCOL_VERSION; const ADDRESS_BYTES_SIZE: usize = 32; // Size of address type in bytes. @@ -878,15 +879,17 @@ where #[cfg(test)] mod tests { - use super::*; - use std::net::{IpAddr,Ipv4Addr}; - use node_table::{Node, NodeId, NodeEndpoint}; + use std::net::{IpAddr, Ipv4Addr}; + use std::str::FromStr; - use std::str::FromStr; - use rustc_hex::FromHex; - use ethkey::{Random, Generator}; + use rustc_hex::FromHex; - #[test] + use ethkey::{Generator, Random}; + use node_table::{Node, NodeEndpoint, NodeId}; + + use super::*; + + #[test] fn find_node() { let mut nearest = Vec::new(); let node = Node::from_str("enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@127.0.0.1:7770").unwrap(); diff --git a/util/network-devp2p/src/handshake.rs b/util/network-devp2p/src/handshake.rs index 5388318a771..cbaa7218333 100644 --- a/util/network-devp2p/src/handshake.rs +++ b/util/network-devp2p/src/handshake.rs @@ -15,19 +15,21 @@ // along with Parity Ethereum. If not, see . use std::time::Duration; -use rand::random; + +use ethereum_types::{H256, H520}; use hash::write_keccak; use mio::tcp::*; -use ethereum_types::{H256, H520}; use parity_bytes::Bytes; +use rand::random; use rlp::{Rlp, RlpStream}; + use connection::Connection; -use node_table::NodeId; -use io::{IoContext, StreamToken}; -use ethkey::{KeyPair, Public, Secret, recover, sign, Generator, Random}; +use ethkey::{Generator, KeyPair, Public, Random, recover, Secret, sign}; use ethkey::crypto::{ecdh, ecies}; -use network::{Error, ErrorKind}; use host::HostInfo; +use io::{IoContext, StreamToken}; +use network::{Error, ErrorKind}; +use node_table::NodeId; #[derive(PartialEq, Eq, Debug)] enum HandshakeState { @@ -317,12 +319,14 @@ impl Handshake { #[cfg(test)] mod test { - use rustc_hex::FromHex; - use super::*; use ethereum_types::H256; - use io::*; use mio::tcp::TcpStream; + use rustc_hex::FromHex; + use ethkey::Public; + use io::*; + + use super::*; fn check_auth(h: &Handshake, version: u64) { assert_eq!(h.id, "fda1cff674c90c9a197539fe3dfb53086ace64f83ed7c6eabec741f7f381cc803e52ab2cd55d5569bce4347107a310dfd5f88a010cd2ffd1005ca406f1842877".into()); diff --git a/util/network-devp2p/src/host.rs b/util/network-devp2p/src/host.rs index 52c8c4ca74d..a3e466f610c 100644 --- a/util/network-devp2p/src/host.rs +++ b/util/network-devp2p/src/host.rs @@ -14,40 +14,41 @@ // You should have received a copy of the GNU General Public License // along with Parity Ethereum. If not, see . -use std::net::{SocketAddr, SocketAddrV4, Ipv4Addr}; +use std::cmp::{max, min}; use std::collections::{HashMap, HashSet}; +use std::fs; +use std::io::{self, Read, Write}; +use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4}; +use std::ops::*; +use std::path::{Path, PathBuf}; use std::str::FromStr; use std::sync::Arc; use std::sync::atomic::{AtomicBool, Ordering as AtomicOrdering}; -use std::ops::*; -use std::cmp::{min, max}; -use std::path::{Path, PathBuf}; -use std::io::{Read, Write, self}; -use std::fs; use std::time::Duration; -use ethkey::{KeyPair, Secret, Random, Generator}; + +use ethereum_types::H256; use hash::keccak; use mio::*; -use mio::deprecated::{EventLoop}; +use mio::deprecated::EventLoop; use mio::tcp::*; use mio::udp::*; -use ethereum_types::H256; -use rlp::{RlpStream, Encodable}; - -use session::{Session, SessionData}; -use io::*; -use PROTOCOL_VERSION; -use node_table::*; -use network::{NetworkConfiguration, NetworkIoMessage, ProtocolId, PeerId, PacketId}; -use network::{NonReservedPeerMode, NetworkContext as NetworkContextTrait}; -use network::{SessionInfo, Error, ErrorKind, DisconnectReason, NetworkProtocolHandler}; -use discovery::{Discovery, TableUpdates, NodeEntry, MAX_DATAGRAM_SIZE}; -use network::client_version::ClientVersion; -use ip_utils::{map_external_address, select_public_address}; use parity_path::restrict_permissions_owner; use parking_lot::{Mutex, RwLock}; -use network::{ConnectionFilter, ConnectionDirection}; +use rlp::{Encodable, RlpStream}; + use connection::PAYLOAD_SOFT_LIMIT; +use discovery::{Discovery, MAX_DATAGRAM_SIZE, NodeEntry, TableUpdates}; +use ethkey::{Generator, KeyPair, Random, Secret}; +use io::*; +use ip_utils::{map_external_address, select_public_address}; +use network::{NetworkConfiguration, NetworkIoMessage, PacketId, PeerId, ProtocolId}; +use network::{NetworkContext as NetworkContextTrait, NonReservedPeerMode}; +use network::{DisconnectReason, Error, ErrorKind, NetworkProtocolHandler, SessionInfo}; +use network::{ConnectionDirection, ConnectionFilter}; +use network::client_version::ClientVersion; +use node_table::*; +use PROTOCOL_VERSION; +use session::{Session, SessionData}; type Slab = ::slab::Slab; diff --git a/util/network-devp2p/src/ip_utils.rs b/util/network-devp2p/src/ip_utils.rs index 4b8473ceca8..75ac0f5300d 100644 --- a/util/network-devp2p/src/ip_utils.rs +++ b/util/network-devp2p/src/ip_utils.rs @@ -16,13 +16,15 @@ // Based on original work by David Levy https://raw.githubusercontent.com/dlevy47/rust-interfaces -use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; use std::io; -use igd::{PortMappingProtocol, search_gateway_from_timeout}; +use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; use std::time::Duration; -use node_table::NodeEndpoint; + +use igd::{PortMappingProtocol, search_gateway_from_timeout}; use ipnetwork::IpNetwork; +use node_table::NodeEndpoint; + /// Socket address extension for rustc beta. To be replaces with now unstable API pub trait SocketAddrExt { /// Returns true if the address appears to be globally routable. @@ -212,12 +214,13 @@ impl SocketAddrExt for IpAddr { #[cfg(not(any(windows, target_os = "android")))] mod getinterfaces { - use std::{mem, io}; - use libc::{AF_INET, AF_INET6}; - use libc::{getifaddrs, freeifaddrs, ifaddrs, sockaddr, sockaddr_in, sockaddr_in6}; - use std::net::{Ipv4Addr, Ipv6Addr, IpAddr}; + use std::{io, mem}; + use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; + + use libc::{AF_INET, AF_INET6}; + use libc::{freeifaddrs, getifaddrs, ifaddrs, sockaddr, sockaddr_in, sockaddr_in6}; - fn convert_sockaddr(sa: *mut sockaddr) -> Option { + fn convert_sockaddr(sa: *mut sockaddr) -> Option { if sa.is_null() { return None; } let (addr, _) = match i32::from(unsafe { *sa }.sa_family) { diff --git a/util/network-devp2p/src/lib.rs b/util/network-devp2p/src/lib.rs index 3f1999bc6d1..02fe324acf0 100644 --- a/util/network-devp2p/src/lib.rs +++ b/util/network-devp2p/src/lib.rs @@ -60,45 +60,49 @@ //TODO: use Poll from mio #![allow(deprecated)] +extern crate ansi_term; +#[cfg(test)] #[macro_use] +extern crate assert_matches; +extern crate bytes; +extern crate crypto as rcrypto; +#[cfg(test)] +extern crate env_logger; +#[macro_use] +extern crate error_chain; extern crate ethcore_io as io; -extern crate parity_bytes; -extern crate parity_crypto as crypto; +extern crate ethcore_network as network; extern crate ethereum_types; -extern crate parking_lot; -extern crate mio; -extern crate tiny_keccak; -extern crate crypto as rcrypto; -extern crate rand; -extern crate ansi_term; //TODO: remove this -extern crate rustc_hex; -extern crate igd; -extern crate libc; -extern crate slab; extern crate ethkey; -extern crate rlp; -extern crate bytes; -extern crate parity_path; -extern crate ethcore_network as network; +extern crate igd; extern crate ipnetwork; extern crate keccak_hash as hash; -extern crate serde; -extern crate serde_json; -extern crate parity_snappy as snappy; -extern crate lru_cache; - -#[macro_use] -extern crate error_chain; +extern crate libc; #[macro_use] extern crate log; +extern crate lru_cache; +extern crate mio; +extern crate parity_bytes; +extern crate parity_crypto as crypto; +extern crate parity_path; +extern crate parity_snappy as snappy; +extern crate parking_lot; +extern crate rand; +extern crate rlp; +//TODO: remove this +extern crate rustc_hex; +extern crate serde; #[macro_use] extern crate serde_derive; - -#[cfg(test)] -extern crate env_logger; +extern crate serde_json; +extern crate slab; #[cfg(test)] extern crate tempdir; -#[cfg(test)] #[macro_use] -extern crate assert_matches; +extern crate tiny_keccak; + +pub use host::NetworkContext; +pub use io::TimerToken; +pub use node_table::{MAX_NODES_IN_TABLE, NodeId, validate_node_url}; +pub use service::NetworkService; mod host; mod connection; @@ -109,10 +113,4 @@ mod service; mod node_table; mod ip_utils; -pub use service::NetworkService; -pub use host::NetworkContext; - -pub use io::TimerToken; -pub use node_table::{validate_node_url, NodeId, MAX_NODES_IN_TABLE}; - const PROTOCOL_VERSION: u32 = 5; diff --git a/util/network-devp2p/src/node_table.rs b/util/network-devp2p/src/node_table.rs index db51890082d..4324643dc45 100644 --- a/util/network-devp2p/src/node_table.rs +++ b/util/network-devp2p/src/node_table.rs @@ -14,22 +14,24 @@ // You should have received a copy of the GNU General Public License // along with Parity Ethereum. If not, see . -use discovery::{TableUpdates, NodeEntry}; -use ethereum_types::H512; -use ip_utils::*; -use network::{Error, ErrorKind, AllowIP, IpFilter}; -use rlp::{Rlp, RlpStream, DecoderError}; -use serde_json; +use std::{fs, slice}; use std::collections::{HashMap, HashSet}; use std::fmt::{self, Display, Formatter}; use std::hash::{Hash, Hasher}; use std::iter::FromIterator; -use std::net::{SocketAddr, ToSocketAddrs, SocketAddrV4, SocketAddrV6, Ipv4Addr, Ipv6Addr}; +use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs}; use std::path::PathBuf; use std::str::FromStr; -use std::{fs, slice}; use std::time::{self, Duration, SystemTime}; + +use ethereum_types::H512; use rand::{self, Rng}; +use rlp::{DecoderError, Rlp, RlpStream}; +use serde_json; + +use discovery::{NodeEntry, TableUpdates}; +use ip_utils::*; +use network::{AllowIP, Error, ErrorKind, IpFilter}; /// Node public key pub type NodeId = H512; @@ -528,9 +530,9 @@ pub fn validate_node_url(url: &str) -> Option { } mod json { - use super::*; + use super::*; - #[derive(Serialize, Deserialize)] + #[derive(Serialize, Deserialize)] pub struct NodeTable { pub nodes: Vec, } @@ -595,16 +597,18 @@ mod json { #[cfg(test)] mod tests { - use super::*; - use std::net::{SocketAddr, SocketAddrV4, Ipv4Addr}; - use ethereum_types::H512; - use std::thread::sleep; - use std::time::Duration; - use std::str::FromStr; - use tempdir::TempDir; - use ipnetwork::IpNetwork; + use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4}; + use std::str::FromStr; + use std::thread::sleep; + use std::time::Duration; - #[test] + use ethereum_types::H512; + use ipnetwork::IpNetwork; + use tempdir::TempDir; + + use super::*; + + #[test] fn endpoint_parse() { let endpoint = NodeEndpoint::from_str("123.99.55.44:7770"); assert!(endpoint.is_ok()); diff --git a/util/network-devp2p/src/service.rs b/util/network-devp2p/src/service.rs index d06122cd26e..3bf9b1da120 100644 --- a/util/network-devp2p/src/service.rs +++ b/util/network-devp2p/src/service.rs @@ -14,15 +14,17 @@ // You should have received a copy of the GNU General Public License // along with Parity Ethereum. If not, see . -use network::{Error, NetworkConfiguration, NetworkProtocolHandler, NonReservedPeerMode}; -use network::{NetworkContext, PeerId, ProtocolId, NetworkIoMessage}; -use host::Host; -use io::*; -use parking_lot::RwLock; use std::net::SocketAddr; use std::ops::RangeInclusive; use std::sync::Arc; + use ansi_term::Colour; +use parking_lot::RwLock; + +use host::Host; +use io::*; +use network::{Error, NetworkConfiguration, NetworkProtocolHandler, NonReservedPeerMode}; +use network::{NetworkContext, NetworkIoMessage, PeerId, ProtocolId}; use network::ConnectionFilter; struct HostHandler { diff --git a/util/network-devp2p/src/session.rs b/util/network-devp2p/src/session.rs index 6cecaf36104..8087342a15a 100644 --- a/util/network-devp2p/src/session.rs +++ b/util/network-devp2p/src/session.rs @@ -14,25 +14,26 @@ // You should have received a copy of the GNU General Public License // along with Parity Ethereum. If not, see . -use std::{str, io}; -use std::net::SocketAddr; +use std::{io, str}; use std::collections::HashMap; +use std::net::SocketAddr; use std::time::{Duration, Instant}; +use ethereum_types::H256; use mio::*; -use mio::deprecated::{Handler, EventLoop}; +use mio::deprecated::{EventLoop, Handler}; use mio::tcp::*; -use ethereum_types::H256; -use rlp::{Rlp, RlpStream, EMPTY_LIST_RLP}; -use connection::{EncryptedConnection, Packet, Connection, MAX_PAYLOAD_SIZE}; +use rlp::{EMPTY_LIST_RLP, Rlp, RlpStream}; +use snappy; + +use connection::{Connection, EncryptedConnection, MAX_PAYLOAD_SIZE, Packet}; use handshake::Handshake; +use host::*; use io::{IoContext, StreamToken}; -use network::{Error, ErrorKind, DisconnectReason, SessionInfo, ProtocolId, PeerCapabilityInfo}; -use network::SessionCapabilityInfo; +use network::{DisconnectReason, Error, ErrorKind, PeerCapabilityInfo, ProtocolId, SessionInfo}; use network::client_version::ClientVersion; -use host::*; +use network::SessionCapabilityInfo; use node_table::NodeId; -use snappy; // Timeout must be less than (interval - 1). const PING_TIMEOUT: Duration = Duration::from_secs(60); diff --git a/util/network-devp2p/tests/tests.rs b/util/network-devp2p/tests/tests.rs index 5270df6b9c5..74094cc46f2 100644 --- a/util/network-devp2p/tests/tests.rs +++ b/util/network-devp2p/tests/tests.rs @@ -22,15 +22,17 @@ extern crate ethkey; extern crate parity_bytes; extern crate parking_lot; -use std::sync::atomic::{AtomicBool, Ordering as AtomicOrdering}; use std::sync::Arc; +use std::sync::atomic::{AtomicBool, Ordering as AtomicOrdering}; use std::thread; use std::time::*; -use parking_lot::Mutex; + use parity_bytes::Bytes; +use parking_lot::Mutex; + use ethcore_network::*; use ethcore_network_devp2p::NetworkService; -use ethkey::{Random, Generator}; +use ethkey::{Generator, Random}; use io::TimerToken; pub struct TestProtocol { From 95a958d86d8ddf4ac17149e12029d03d69a645b6 Mon Sep 17 00:00:00 2001 From: David Palm Date: Mon, 3 Jun 2019 07:18:50 +0200 Subject: [PATCH 03/11] compiles --- Cargo.lock | 20 ----- util/network-devp2p/Cargo.toml | 35 +++++---- util/network-devp2p/src/connection.rs | 106 +++++++++++++------------- util/network-devp2p/src/lib.rs | 2 +- 4 files changed, 71 insertions(+), 92 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4054c601771..ed5ddf2b8ca 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1112,7 +1112,6 @@ dependencies = [ "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "rlp 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1572,11 +1571,6 @@ dependencies = [ "byteorder 1.2.6 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "gcc" -version = "0.3.55" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "generic-array" version = "0.9.0" @@ -3545,18 +3539,6 @@ name = "rprompt" version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "rust-crypto" -version = "0.2.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "rustc-demangle" version = "0.1.9" @@ -4756,7 +4738,6 @@ dependencies = [ "checksum futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)" = "49e7653e374fe0d0c12de4250f0bdb60680b8c80eed558c5c7538eec9c89e21b" "checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4" "checksum fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" -"checksum gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)" = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" "checksum generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c0f28c2f5bfb5960175af447a2da7c18900693738343dc896ffbcabd9839592" "checksum generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef25c5683767570c2bbd7deba372926a55eaae9982d7726ee2a1050239d45b9d" "checksum getopts 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "0a7292d30132fb5424b354f5dc02512a86e4c516fe544bb7a25e7f266951b797" @@ -4919,7 +4900,6 @@ dependencies = [ "checksum rlp 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "16d1effe9845d54f90e7be8420ee49e5c94623140b97ee4bc6fb5bfddb745720" "checksum rpassword 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b273c91bd242ca03ad6d71c143b6f17a48790e61f21a6c78568fa2b6774a24a4" "checksum rprompt 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1601f32bc5858aae3cbfa1c645c96c4d820cc5c16be0194f089560c00b6eb625" -"checksum rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)" = "f76d05d3993fd5f4af9434e8e436db163a12a9d40e1a58a726f27a01dfd12a2a" "checksum rustc-demangle 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "bcfe5b13211b4d78e5c2cadfebd7769197d95c639c35a50057eb4c05de811395" "checksum rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0ceb8ce7a5e520de349e1fa172baeba4a9e8d5ef06c47471863530bc4972ee1e" "checksum rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "403bb3a286107a04825a5f82e1270acc1e14028d3d554d7a1e08914549575ab8" diff --git a/util/network-devp2p/Cargo.toml b/util/network-devp2p/Cargo.toml index 3059cc100ba..dc321ee89c8 100644 --- a/util/network-devp2p/Cargo.toml +++ b/util/network-devp2p/Cargo.toml @@ -7,34 +7,33 @@ version = "1.12.0" authors = ["Parity Technologies "] [dependencies] -log = "0.4" -mio = "0.6.8" -bytes = "0.4" -rand = "0.4" -tiny-keccak = "1.4" -rust-crypto = "0.2.34" -slab = "0.2" -igd = "0.7" -libc = "0.2.7" -parking_lot = "0.7" ansi_term = "0.10" -rustc-hex = "1.0" +bytes = "0.4" +error-chain = { version = "0.12", default-features = false } ethcore-io = { path = "../io", features = ["mio"] } -parity-bytes = "0.1" -parity-crypto = "0.4.0" ethcore-network = { path = "../network" } ethereum-types = "0.4" ethkey = { path = "../../accounts/ethkey" } -rlp = { version = "0.3.0", features = ["ethereum"] } -parity-path = "0.1" +igd = "0.7" ipnetwork = "0.12.6" keccak-hash = "0.1" +libc = "0.2.7" +log = "0.4" +lru-cache = "0.1" +mio = "0.6.8" +parity-bytes = "0.1" +parity-crypto = "0.4.0" +parity-path = "0.1" parity-snappy = "0.1" +parking_lot = "0.7" +rand = "0.4" +rlp = { version = "0.3.0", features = ["ethereum"] } +rustc-hex = "1.0" serde = "1.0" -serde_json = "1.0" serde_derive = "1.0" -error-chain = { version = "0.12", default-features = false } -lru-cache = "0.1" +serde_json = "1.0" +slab = "0.2" +tiny-keccak = "1.4" [dev-dependencies] env_logger = "0.5" diff --git a/util/network-devp2p/src/connection.rs b/util/network-devp2p/src/connection.rs index 15f601da393..dd1fceafd1d 100644 --- a/util/network-devp2p/src/connection.rs +++ b/util/network-devp2p/src/connection.rs @@ -27,10 +27,7 @@ use mio::{PollOpt, Ready, Token}; use mio::deprecated::{EventLoop, Handler, TryRead, TryWrite}; use mio::tcp::*; use parity_bytes::*; -use rcrypto::aessafe::*; -use rcrypto::blockmodes::*; -use rcrypto::buffer::*; -use rcrypto::symmetriccipher::*; +use crypto::aes::{AesCtr256, AesEcb256}; use rlp::{Rlp, RlpStream}; use tiny_keccak::Keccak; @@ -279,11 +276,11 @@ pub struct EncryptedConnection { /// Underlying tcp connection pub connection: Connection, /// Egress data encryptor - encoder: CtrMode, + encoder: AesCtr256, /// Ingress data decryptor - decoder: CtrMode, + decoder: AesCtr256, /// Ingress data decryptor - mac_encoder: EcbEncryptor>, + mac_encoder_key: Bytes, /// MAC for egress data egress_mac: Keccak, /// MAC for ingress data @@ -296,6 +293,7 @@ pub struct EncryptedConnection { payload_len: usize, } +const NULL_IV : [u8; 16] = [0;16]; impl EncryptedConnection { /// Create an encrypted connection out of the handshake. pub fn new(handshake: &mut Handshake) -> Result { @@ -315,21 +313,20 @@ impl EncryptedConnection { keccak(&key_material).copy_to(&mut key_material[32..64]); keccak(&key_material).copy_to(&mut key_material[32..64]); - let iv = vec![0u8; 16]; - let encoder = CtrMode::new(AesSafe256Encryptor::new(&key_material[32..64]), iv); - let iv = vec![0u8; 16]; - let decoder = CtrMode::new(AesSafe256Encryptor::new(&key_material[32..64]), iv); - - keccak(&key_material).copy_to(&mut key_material[32..64]); - let mac_encoder = EcbEncryptor::new(AesSafe256Encryptor::new(&key_material[32..64]), NoPadding); + // TODO: clarify this: ecdh::agree creates a **NEW** secret right? + // Using a 0 IV with CTR is fine as long as the same IV is never reused with the same key. This is not the case here. + let encoder = AesCtr256::new(&key_material[32..64], &NULL_IV)?; + let decoder = AesCtr256::new(&key_material[32..64], &NULL_IV)?; + keccak(&key_material).copy_to(&mut key_material[32..64]); // Create a new key for the mac encoding here? Why re-use the key material from above? + let mac_encoder_key = key_material[32..64].to_vec(); // TODO: store array let mut egress_mac = Keccak::new_keccak256(); - let mut mac_material = H256::from_slice(&key_material[32..64]) ^ handshake.remote_nonce; + let mut mac_material = &H256::from_slice(&key_material[32..64]) ^ &handshake.remote_nonce; // TODO: check that this is ok egress_mac.update(&mac_material); egress_mac.update(if handshake.originated { &handshake.auth_cipher } else { &handshake.ack_cipher }); let mut ingress_mac = Keccak::new_keccak256(); - mac_material = H256::from_slice(&key_material[32..64]) ^ handshake.nonce; + mac_material = &H256::from_slice(&key_material[32..64]) ^ &handshake.nonce; ingress_mac.update(&mac_material); ingress_mac.update(if handshake.originated { &handshake.ack_cipher } else { &handshake.auth_cipher }); @@ -339,7 +336,7 @@ impl EncryptedConnection { connection, encoder, decoder, - mac_encoder, + mac_encoder_key, egress_mac, ingress_mac, read_state: EncryptedConnectionState::Header, @@ -357,47 +354,48 @@ impl EncryptedConnection { if len > MAX_PAYLOAD_SIZE { bail!(ErrorKind::OversizedPacket); } + header.append_raw(&[(len >> 16) as u8, (len >> 8) as u8, len as u8], 1); header.append_raw(&[0xc2u8, 0x80u8, 0x80u8], 1); - //TODO: get rid of vectors here + let padding = (16 - (len % 16)) % 16; + + let mut packet = vec![0u8; 32 + len + padding + 16]; let mut header = header.out(); - let padding = (16 - (payload.len() % 16)) % 16; header.resize(16, 0u8); - - let mut packet = vec![0u8; 32 + payload.len() + padding + 16]; - self.encoder.encrypt(&mut RefReadBuffer::new(&header), &mut RefWriteBuffer::new(&mut packet), false).expect("Invalid length or padding"); - EncryptedConnection::update_mac(&mut self.egress_mac, &mut self.mac_encoder, &packet[0..16]); - self.egress_mac.clone().finalize(&mut packet[16..32]); - self.encoder.encrypt(&mut RefReadBuffer::new(payload), &mut RefWriteBuffer::new(&mut packet[32..(32 + len)]), padding == 0).expect("Invalid length or padding"); + let header_len = header.len(); + &mut packet[..header_len].copy_from_slice(&mut header); + self.encoder.encrypt(&mut packet[..header_len])?; + EncryptedConnection::update_mac(&mut self.egress_mac, &self.mac_encoder_key, &packet[..header_len])?; + self.egress_mac.clone().finalize(&mut packet[header_len..32]); + &mut packet[32..32 + len].copy_from_slice(payload); + self.encoder.encrypt(&mut packet[32..32 + len])?; if padding != 0 { - let pad = [0u8; 16]; - self.encoder.encrypt(&mut RefReadBuffer::new(&pad[0..padding]), &mut RefWriteBuffer::new(&mut packet[(32 + len)..(32 + len + padding)]), true).expect("Invalid length or padding"); + self.encoder.encrypt(&mut packet[(32 + len)..(32 + len + padding)])?; } self.egress_mac.update(&packet[32..(32 + len + padding)]); - EncryptedConnection::update_mac(&mut self.egress_mac, &mut self.mac_encoder, &[0u8; 0]); + EncryptedConnection::update_mac(&mut self.egress_mac, &self.mac_encoder_key, &[0u8; 0])?; self.egress_mac.clone().finalize(&mut packet[(32 + len + padding)..]); self.connection.send(io, packet); + Ok(()) } /// Decrypt and authenticate an incoming packet header. Prepare for receiving payload. - fn read_header(&mut self, header: &[u8]) -> Result<(), Error> { + fn read_header(&mut self, mut header: Bytes) -> Result<(), Error> { if header.len() != ENCRYPTED_HEADER_LEN { return Err(ErrorKind::Auth.into()); } - EncryptedConnection::update_mac(&mut self.ingress_mac, &mut self.mac_encoder, &header[0..16]); + EncryptedConnection::update_mac(&mut self.ingress_mac, &self.mac_encoder_key, &header[0..16])?; let mac = &header[16..]; let mut expected = H256::new(); self.ingress_mac.clone().finalize(&mut expected); if mac != &expected[0..16] { return Err(ErrorKind::Auth.into()); } + self.decoder.decrypt(&mut header[..16])?; - let mut hdec = H128::new(); - self.decoder.decrypt(&mut RefReadBuffer::new(&header[0..16]), &mut RefWriteBuffer::new(&mut hdec), false).expect("Invalid length or padding"); - - let length = ((((hdec[0] as u32) << 8) + (hdec[1] as u32)) << 8) + (hdec[2] as u32); - let header_rlp = Rlp::new(&hdec[3..6]); + let length = ((((header[0] as u32) << 8) + (header[1] as u32)) << 8) + (header[2] as u32); + let header_rlp = Rlp::new(&header[3..6]); let protocol_id = header_rlp.val_at::(0)?; self.payload_len = length as usize; @@ -406,46 +404,46 @@ impl EncryptedConnection { let padding = (16 - (length % 16)) % 16; let full_length = length + padding + 16; + self.connection.expect(full_length as usize); Ok(()) } /// Decrypt and authenticate packet payload. - fn read_payload(&mut self, payload: &[u8]) -> Result { + fn read_payload(&mut self, mut payload: Bytes) -> Result { let padding = (16 - (self.payload_len % 16)) % 16; let full_length = self.payload_len + padding + 16; if payload.len() != full_length { return Err(ErrorKind::Auth.into()); } self.ingress_mac.update(&payload[0..payload.len() - 16]); - EncryptedConnection::update_mac(&mut self.ingress_mac, &mut self.mac_encoder, &[0u8; 0]); + EncryptedConnection::update_mac(&mut self.ingress_mac, &self.mac_encoder_key, &[0u8; 0])?; + let mac = &payload[(payload.len() - 16)..]; let mut expected = H128::new(); self.ingress_mac.clone().finalize(&mut expected); if mac != &expected[..] { return Err(ErrorKind::Auth.into()); } - - let mut packet = vec![0u8; self.payload_len]; - self.decoder.decrypt(&mut RefReadBuffer::new(&payload[0..self.payload_len]), &mut RefWriteBuffer::new(&mut packet), false).expect("Invalid length or padding"); - let mut pad_buf = [0u8; 16]; - self.decoder.decrypt(&mut RefReadBuffer::new(&payload[self.payload_len..(payload.len() - 16)]), &mut RefWriteBuffer::new(&mut pad_buf), false).expect("Invalid length or padding"); + self.decoder.decrypt(&mut payload[..self.payload_len + padding])?; Ok(Packet { protocol: self.protocol_id, - data: packet + data: payload }) } /// Update MAC after reading or writing any data. - fn update_mac(mac: &mut Keccak, mac_encoder: &mut EcbEncryptor>, seed: &[u8]) { + fn update_mac(mac: &mut Keccak, mac_encoder_key: &[u8], seed: &[u8]) -> Result<(), Error> { let mut prev = H128::new(); mac.clone().finalize(&mut prev); let mut enc = H128::new(); - mac_encoder.encrypt(&mut RefReadBuffer::new(&prev), &mut RefWriteBuffer::new(&mut enc), true).expect("Error updating MAC"); - mac_encoder.reset(); + &mut enc[..].copy_from_slice(&prev); + let mac_encoder = AesEcb256::new(mac_encoder_key)?; + mac_encoder.encrypt(&mut enc)?; enc = enc ^ if seed.is_empty() { prev } else { H128::from_slice(seed) }; mac.update(&enc); + Ok(()) } /// Readable IO handler. Tracker receive status and returns decoded packet if available. @@ -453,7 +451,7 @@ impl EncryptedConnection { io.clear_timer(self.connection.token)?; if let EncryptedConnectionState::Header = self.read_state { if let Some(data) = self.connection.readable()? { - self.read_header(&data)?; + self.read_header(data)?; io.register_timer(self.connection.token, RECEIVE_PAYLOAD)?; } }; @@ -462,7 +460,7 @@ impl EncryptedConnection { Some(data) => { self.read_state = EncryptedConnectionState::Header; self.connection.expect(ENCRYPTED_HEADER_LEN); - Ok(Some(self.read_payload(&data)?)) + Ok(Some(self.read_payload(data)?)) }, None => Ok(None) } @@ -490,13 +488,15 @@ pub fn test_encryption() { let mut got = H128::new(); - let mut encoder = EcbEncryptor::new(AesSafe256Encryptor::new(&key), NoPadding); - encoder.encrypt(&mut RefReadBuffer::new(&before), &mut RefWriteBuffer::new(&mut got), true).unwrap(); - encoder.reset(); + let encoder = AesEcb256::new(&key).unwrap(); + got.copy_from_slice(&before); + encoder.encrypt(&mut got).unwrap(); assert_eq!(got, after); + + let encoder = AesEcb256::new(&key).unwrap(); got = H128::new(); - encoder.encrypt(&mut RefReadBuffer::new(&before2), &mut RefWriteBuffer::new(&mut got), true).unwrap(); - encoder.reset(); + got.copy_from_slice(&before2); + encoder.encrypt(&mut got).unwrap(); assert_eq!(got, after2); } diff --git a/util/network-devp2p/src/lib.rs b/util/network-devp2p/src/lib.rs index 02fe324acf0..b61cfe66f84 100644 --- a/util/network-devp2p/src/lib.rs +++ b/util/network-devp2p/src/lib.rs @@ -64,7 +64,7 @@ extern crate ansi_term; #[cfg(test)] #[macro_use] extern crate assert_matches; extern crate bytes; -extern crate crypto as rcrypto; +//extern crate crypto as rcrypto; #[cfg(test)] extern crate env_logger; #[macro_use] From 66f365945bd59e7ae293afbcc71937719eb8e15c Mon Sep 17 00:00:00 2001 From: David Palm Date: Mon, 3 Jun 2019 07:23:39 +0200 Subject: [PATCH 04/11] cleanup --- util/network-devp2p/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/util/network-devp2p/src/lib.rs b/util/network-devp2p/src/lib.rs index b61cfe66f84..c54b03d322e 100644 --- a/util/network-devp2p/src/lib.rs +++ b/util/network-devp2p/src/lib.rs @@ -64,7 +64,6 @@ extern crate ansi_term; #[cfg(test)] #[macro_use] extern crate assert_matches; extern crate bytes; -//extern crate crypto as rcrypto; #[cfg(test)] extern crate env_logger; #[macro_use] From be06f5716c92bc9c029f6b9b8d611cde507379e7 Mon Sep 17 00:00:00 2001 From: David Palm Date: Mon, 3 Jun 2019 14:29:15 +0200 Subject: [PATCH 05/11] Use Secret to store mac-key Truncate payload properly --- util/network-devp2p/src/connection.rs | 68 ++++++++++++++------------- 1 file changed, 35 insertions(+), 33 deletions(-) diff --git a/util/network-devp2p/src/connection.rs b/util/network-devp2p/src/connection.rs index dd1fceafd1d..e09a76d096d 100644 --- a/util/network-devp2p/src/connection.rs +++ b/util/network-devp2p/src/connection.rs @@ -31,7 +31,7 @@ use crypto::aes::{AesCtr256, AesEcb256}; use rlp::{Rlp, RlpStream}; use tiny_keccak::Keccak; -use ethkey::crypto; +use ethkey::{crypto, Secret}; use handshake::Handshake; use io::{IoContext, StreamToken}; use network::{Error, ErrorKind}; @@ -166,7 +166,7 @@ impl GenericConnection { /// Low level tcp connection pub type Connection = GenericConnection; -impl Connection { +impl Connection { /// Create a new connection with given id and socket. pub fn new(token: StreamToken, socket: TcpStream) -> Connection { Connection { @@ -280,7 +280,8 @@ pub struct EncryptedConnection { /// Ingress data decryptor decoder: AesCtr256, /// Ingress data decryptor - mac_encoder_key: Bytes, +// mac_encoder_key: [u8; 32], + mac_encoder_key: Secret, /// MAC for egress data egress_mac: Keccak, /// MAC for ingress data @@ -313,20 +314,20 @@ impl EncryptedConnection { keccak(&key_material).copy_to(&mut key_material[32..64]); keccak(&key_material).copy_to(&mut key_material[32..64]); - // TODO: clarify this: ecdh::agree creates a **NEW** secret right? + // TODO: clarify this: ecdh::agree creates a **NEW** secret right? And AesCtr256 keeps an internal counter, right? // Using a 0 IV with CTR is fine as long as the same IV is never reused with the same key. This is not the case here. let encoder = AesCtr256::new(&key_material[32..64], &NULL_IV)?; let decoder = AesCtr256::new(&key_material[32..64], &NULL_IV)?; - keccak(&key_material).copy_to(&mut key_material[32..64]); // Create a new key for the mac encoding here? Why re-use the key material from above? - let mac_encoder_key = key_material[32..64].to_vec(); // TODO: store array + keccak(&key_material).copy_to(&mut key_material[32..64]); + let mac_encoder_key: Secret = Secret::from_slice(&key_material[32..64]).expect("can create Secret from 32 bytes; qed"); let mut egress_mac = Keccak::new_keccak256(); - let mut mac_material = &H256::from_slice(&key_material[32..64]) ^ &handshake.remote_nonce; // TODO: check that this is ok + let mut mac_material = H256::from_slice(&key_material[32..64]) ^ handshake.remote_nonce; egress_mac.update(&mac_material); egress_mac.update(if handshake.originated { &handshake.auth_cipher } else { &handshake.ack_cipher }); let mut ingress_mac = Keccak::new_keccak256(); - mac_material = &H256::from_slice(&key_material[32..64]) ^ &handshake.nonce; + mac_material = H256::from_slice(&key_material[32..64]) ^ handshake.nonce; ingress_mac.update(&mac_material); ingress_mac.update(if handshake.originated { &handshake.ack_cipher } else { &handshake.auth_cipher }); @@ -426,6 +427,7 @@ impl EncryptedConnection { return Err(ErrorKind::Auth.into()); } self.decoder.decrypt(&mut payload[..self.payload_len + padding])?; + payload.truncate(self.payload_len); Ok(Packet { protocol: self.protocol_id, data: payload @@ -433,7 +435,7 @@ impl EncryptedConnection { } /// Update MAC after reading or writing any data. - fn update_mac(mac: &mut Keccak, mac_encoder_key: &[u8], seed: &[u8]) -> Result<(), Error> { + fn update_mac(mac: &mut Keccak, mac_encoder_key: &Secret, seed: &[u8]) -> Result<(), Error> { let mut prev = H128::new(); mac.clone().finalize(&mut prev); let mut enc = H128::new(); @@ -476,30 +478,6 @@ impl EncryptedConnection { } } -#[test] -pub fn test_encryption() { - use ethereum_types::{H256, H128}; - use std::str::FromStr; - let key = H256::from_str("2212767d793a7a3d66f869ae324dd11bd17044b82c9f463b8a541a4d089efec5").unwrap(); - let before = H128::from_str("12532abaec065082a3cf1da7d0136f15").unwrap(); - let before2 = H128::from_str("7e99f682356fdfbc6b67a9562787b18a").unwrap(); - let after = H128::from_str("89464c6b04e7c99e555c81d3f7266a05").unwrap(); - let after2 = H128::from_str("85c070030589ef9c7a2879b3a8489316").unwrap(); - - let mut got = H128::new(); - - let encoder = AesEcb256::new(&key).unwrap(); - got.copy_from_slice(&before); - encoder.encrypt(&mut got).unwrap(); - assert_eq!(got, after); - - let encoder = AesEcb256::new(&key).unwrap(); - got = H128::new(); - got.copy_from_slice(&before2); - encoder.encrypt(&mut got).unwrap(); - assert_eq!(got, after2); -} - #[cfg(test)] mod tests { use std::cmp; @@ -654,6 +632,30 @@ mod tests { IoContext::new(IoChannel::disconnected(), 0) } + #[test] + pub fn test_encryption() { + use ethereum_types::{H256, H128}; + use std::str::FromStr; + let key = H256::from_str("2212767d793a7a3d66f869ae324dd11bd17044b82c9f463b8a541a4d089efec5").unwrap(); + let before = H128::from_str("12532abaec065082a3cf1da7d0136f15").unwrap(); + let before2 = H128::from_str("7e99f682356fdfbc6b67a9562787b18a").unwrap(); + let after = H128::from_str("89464c6b04e7c99e555c81d3f7266a05").unwrap(); + let after2 = H128::from_str("85c070030589ef9c7a2879b3a8489316").unwrap(); + + let mut got = H128::new(); + + let encoder = AesEcb256::new(&key).unwrap(); + got.copy_from_slice(&before); + encoder.encrypt(&mut got).unwrap(); + assert_eq!(got, after); + + let encoder = AesEcb256::new(&key).unwrap(); + got = H128::new(); + got.copy_from_slice(&before2); + encoder.encrypt(&mut got).unwrap(); + assert_eq!(got, after2); + } + #[test] fn connection_expect() { let mut connection = TestConnection::new(); From 9634be3e6e56a88a09d41dc0d47caa42281e7983 Mon Sep 17 00:00:00 2001 From: David Palm Date: Mon, 3 Jun 2019 14:34:11 +0200 Subject: [PATCH 06/11] cleanup --- util/network-devp2p/src/connection.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/util/network-devp2p/src/connection.rs b/util/network-devp2p/src/connection.rs index e09a76d096d..821efdbd6d9 100644 --- a/util/network-devp2p/src/connection.rs +++ b/util/network-devp2p/src/connection.rs @@ -166,7 +166,7 @@ impl GenericConnection { /// Low level tcp connection pub type Connection = GenericConnection; -impl Connection { +impl Connection { /// Create a new connection with given id and socket. pub fn new(token: StreamToken, socket: TcpStream) -> Connection { Connection { @@ -280,7 +280,6 @@ pub struct EncryptedConnection { /// Ingress data decryptor decoder: AesCtr256, /// Ingress data decryptor -// mac_encoder_key: [u8; 32], mac_encoder_key: Secret, /// MAC for egress data egress_mac: Keccak, From 1e680712d19dcde4e6729b3446a6fa87452a7499 Mon Sep 17 00:00:00 2001 From: David Palm Date: Mon, 3 Jun 2019 15:39:13 +0200 Subject: [PATCH 07/11] Reorg imports --- util/network-devp2p/src/discovery.rs | 14 ++++----- util/network-devp2p/src/handshake.rs | 35 ++++++++++++--------- util/network-devp2p/src/host.rs | 45 ++++++++++++++------------- util/network-devp2p/src/node_table.rs | 22 ++++++------- 4 files changed, 61 insertions(+), 55 deletions(-) diff --git a/util/network-devp2p/src/discovery.rs b/util/network-devp2p/src/discovery.rs index 5ffdf1036df..2777505b3a9 100644 --- a/util/network-devp2p/src/discovery.rs +++ b/util/network-devp2p/src/discovery.rs @@ -879,17 +879,17 @@ where #[cfg(test)] mod tests { - use std::net::{IpAddr, Ipv4Addr}; - use std::str::FromStr; + use std::net::{IpAddr, Ipv4Addr}; + use std::str::FromStr; - use rustc_hex::FromHex; + use rustc_hex::FromHex; - use ethkey::{Generator, Random}; - use node_table::{Node, NodeEndpoint, NodeId}; + use ethkey::{Generator, Random}; + use node_table::{Node, NodeEndpoint, NodeId}; - use super::*; + use super::*; - #[test] + #[test] fn find_node() { let mut nearest = Vec::new(); let node = Node::from_str("enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@127.0.0.1:7770").unwrap(); diff --git a/util/network-devp2p/src/handshake.rs b/util/network-devp2p/src/handshake.rs index e07b609b1a4..aee73d0e8b6 100644 --- a/util/network-devp2p/src/handshake.rs +++ b/util/network-devp2p/src/handshake.rs @@ -15,19 +15,21 @@ // along with Parity Ethereum. If not, see . use std::time::Duration; -use rand::random; + +use ethereum_types::{H256, H520}; use hash::write_keccak; use mio::tcp::*; -use ethereum_types::{H256, H520}; use parity_bytes::Bytes; +use rand::random; use rlp::{Rlp, RlpStream}; + use connection::Connection; -use node_table::NodeId; -use io::{IoContext, StreamToken}; -use ethkey::{KeyPair, Public, Secret, recover, sign, Generator, Random}; +use ethkey::{Generator, KeyPair, Public, Random, recover, Secret, sign}; use ethkey::crypto::{ecdh, ecies}; -use network::{Error, ErrorKind}; use host::HostInfo; +use io::{IoContext, StreamToken}; +use network::{Error, ErrorKind}; +use node_table::NodeId; #[derive(PartialEq, Eq, Debug)] enum HandshakeState { @@ -318,15 +320,18 @@ impl Handshake { #[cfg(test)] mod test { - use rustc_hex::FromHex; - use super::*; - use ethereum_types::{H256, H512}; - use io::*; - use mio::tcp::TcpStream; - use ethkey::Public; - use std::str::FromStr; - - fn check_auth(h: &Handshake, version: u64) { + use std::str::FromStr; + + use ethereum_types::{H256, H512}; + use mio::tcp::TcpStream; + use rustc_hex::FromHex; + + use ethkey::Public; + use io::*; + + use super::*; + + fn check_auth(h: &Handshake, version: u64) { assert_eq!( h.id, H512::from_str("fda1cff674c90c9a197539fe3dfb53086ace64f83ed7c6eabec741f7f381cc803e52ab2cd55d5569bce4347107a310dfd5f88a010cd2ffd1005ca406f1842877").unwrap(), diff --git a/util/network-devp2p/src/host.rs b/util/network-devp2p/src/host.rs index 0383aa99349..cf9f6ac5b38 100644 --- a/util/network-devp2p/src/host.rs +++ b/util/network-devp2p/src/host.rs @@ -14,41 +14,42 @@ // You should have received a copy of the GNU General Public License // along with Parity Ethereum. If not, see . -use std::net::{SocketAddr, SocketAddrV4, Ipv4Addr}; +use std::cmp::{max, min}; use std::collections::{HashMap, HashSet}; +use std::fs; +use std::io::{self, Read, Write}; +use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4}; +use std::ops::*; +use std::path::{Path, PathBuf}; use std::str::FromStr; use std::sync::Arc; use std::sync::atomic::{AtomicBool, Ordering as AtomicOrdering}; -use std::ops::*; -use std::cmp::{min, max}; -use std::path::{Path, PathBuf}; -use std::io::{Read, Write, self}; -use std::fs; use std::time::Duration; -use ethkey::{KeyPair, Secret, Random, Generator}; + +use ethereum_types::H256; use hash::keccak; use mio::*; -use mio::deprecated::{EventLoop}; +use mio::deprecated::EventLoop; use mio::tcp::*; use mio::udp::*; -use ethereum_types::H256; -use rlp::{RlpStream, Encodable}; +use parity_path::restrict_permissions_owner; +use parking_lot::{Mutex, RwLock}; +use rlp::{Encodable, RlpStream}; use rustc_hex::ToHex; -use session::{Session, SessionData}; +use connection::PAYLOAD_SOFT_LIMIT; +use discovery::{Discovery, MAX_DATAGRAM_SIZE, NodeEntry, TableUpdates}; +use ethkey::{Generator, KeyPair, Random, Secret}; use io::*; -use PROTOCOL_VERSION; -use node_table::*; -use network::{NetworkConfiguration, NetworkIoMessage, ProtocolId, PeerId, PacketId}; -use network::{NonReservedPeerMode, NetworkContext as NetworkContextTrait}; -use network::{SessionInfo, Error, ErrorKind, DisconnectReason, NetworkProtocolHandler}; -use discovery::{Discovery, TableUpdates, NodeEntry, MAX_DATAGRAM_SIZE}; -use network::client_version::ClientVersion; use ip_utils::{map_external_address, select_public_address}; -use parity_path::restrict_permissions_owner; -use parking_lot::{Mutex, RwLock}; -use network::{ConnectionFilter, ConnectionDirection}; -use connection::PAYLOAD_SOFT_LIMIT; +use network::{NetworkConfiguration, NetworkIoMessage, PacketId, PeerId, ProtocolId}; +use network::{NetworkContext as NetworkContextTrait, NonReservedPeerMode}; +use network::{DisconnectReason, Error, ErrorKind, NetworkProtocolHandler, SessionInfo}; +use network::{ConnectionDirection, ConnectionFilter}; +use network::client_version::ClientVersion; +use node_table::*; +use PROTOCOL_VERSION; +use session::{Session, SessionData}; type Slab = ::slab::Slab; diff --git a/util/network-devp2p/src/node_table.rs b/util/network-devp2p/src/node_table.rs index ed5d4d6ebd7..739babfe0a7 100644 --- a/util/network-devp2p/src/node_table.rs +++ b/util/network-devp2p/src/node_table.rs @@ -530,9 +530,9 @@ pub fn validate_node_url(url: &str) -> Option { } mod json { - use super::*; + use super::*; - #[derive(Serialize, Deserialize)] + #[derive(Serialize, Deserialize)] pub struct NodeTable { pub nodes: Vec, } @@ -597,18 +597,18 @@ mod json { #[cfg(test)] mod tests { - use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4}; - use std::str::FromStr; - use std::thread::sleep; - use std::time::Duration; + use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4}; + use std::str::FromStr; + use std::thread::sleep; + use std::time::Duration; - use ethereum_types::H512; - use ipnetwork::IpNetwork; - use tempdir::TempDir; + use ethereum_types::H512; + use ipnetwork::IpNetwork; + use tempdir::TempDir; - use super::*; + use super::*; - #[test] + #[test] fn endpoint_parse() { let endpoint = NodeEndpoint::from_str("123.99.55.44:7770"); assert!(endpoint.is_ok()); From f190a63ada26673abb93e7bc546e6fe3d0229234 Mon Sep 17 00:00:00 2001 From: David Palm Date: Tue, 4 Jun 2019 09:04:57 +0200 Subject: [PATCH 08/11] brwchk hand waving --- util/network-devp2p/src/connection.rs | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/util/network-devp2p/src/connection.rs b/util/network-devp2p/src/connection.rs index bed6a7051e7..cdf1835caab 100644 --- a/util/network-devp2p/src/connection.rs +++ b/util/network-devp2p/src/connection.rs @@ -31,7 +31,7 @@ use crypto::aes::{AesCtr256, AesEcb256}; use rlp::{Rlp, RlpStream}; use tiny_keccak::Keccak; -use ethkey::crypto; +use ethkey::{crypto, Secret}; use handshake::Handshake; use io::{IoContext, StreamToken}; use network::{Error, ErrorKind}; @@ -389,11 +389,13 @@ impl EncryptedConnection { return Err(ErrorKind::Auth.into()); } EncryptedConnection::update_mac(&mut self.ingress_mac, &self.mac_encoder_key, &header[0..16])?; - let mac = &header[16..]; - let mut expected = H256::zero(); - self.ingress_mac.clone().finalize(expected.as_bytes_mut()); - if mac != &expected[0..16] { - return Err(ErrorKind::Auth.into()); + { + let mac = &header[16..]; + let mut expected = H256::zero(); + self.ingress_mac.clone().finalize(expected.as_bytes_mut()); + if mac != &expected[0..16] { + return Err(ErrorKind::Auth.into()); + } } self.decoder.decrypt(&mut header[..16])?; @@ -422,11 +424,13 @@ impl EncryptedConnection { self.ingress_mac.update(&payload[0..payload.len() - 16]); EncryptedConnection::update_mac(&mut self.ingress_mac, &self.mac_encoder_key, &[0u8; 0])?; - let mac = &payload[(payload.len() - 16)..]; - let mut expected = H128::default(); - self.ingress_mac.clone().finalize(expected.as_bytes_mut()); - if mac != &expected[..] { - return Err(ErrorKind::Auth.into()); + { + let mac = &payload[(payload.len() - 16)..]; + let mut expected = H128::default(); + self.ingress_mac.clone().finalize(expected.as_bytes_mut()); + if mac != &expected[..] { + return Err(ErrorKind::Auth.into()); + } } self.decoder.decrypt(&mut payload[..self.payload_len + padding])?; payload.truncate(self.payload_len); From 0ae675b2a1788ee97f84227d7327a1ad6f0aa45d Mon Sep 17 00:00:00 2001 From: David Palm Date: Fri, 14 Jun 2019 19:17:31 +0200 Subject: [PATCH 09/11] Review feedback --- util/network-devp2p/src/connection.rs | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/util/network-devp2p/src/connection.rs b/util/network-devp2p/src/connection.rs index cdf1835caab..8557068b3be 100644 --- a/util/network-devp2p/src/connection.rs +++ b/util/network-devp2p/src/connection.rs @@ -315,8 +315,10 @@ impl EncryptedConnection { let key_material_keccak = keccak(&key_material); (&mut key_material[32..64]).copy_from_slice(key_material_keccak.as_bytes()); - // TODO: clarify this: ecdh::agree creates a **NEW** secret right? And AesCtr256 keeps an internal counter, right? - // Using a 0 IV with CTR is fine as long as the same IV is never reused with the same key. This is not the case here. + // Using a 0 IV with CTR is fine as long as the same IV is never reused with the same key. + // This is the case here: ecdh creates a new secret which will be the symmetric key used + // only for this session the 0 IV is only use once with this secret, so we are in the case + // of same IV use for different key. let encoder = AesCtr256::new(&key_material[32..64], &NULL_IV)?; let decoder = AesCtr256::new(&key_material[32..64], &NULL_IV)?; let key_material_keccak = keccak(&key_material); @@ -352,6 +354,7 @@ impl EncryptedConnection { /// Send a packet pub fn send_packet(&mut self, io: &IoContext, payload: &[u8]) -> Result<(), Error> where Message: Send + Clone + Sync + 'static { + const HEADER_LEN: usize = 16; let mut header = RlpStream::new(); let len = payload.len(); if len > MAX_PAYLOAD_SIZE { @@ -362,14 +365,13 @@ impl EncryptedConnection { header.append_raw(&[0xc2u8, 0x80u8, 0x80u8], 1); let padding = (16 - (len % 16)) % 16; - let mut packet = vec![0u8; 32 + len + padding + 16]; + let mut packet = vec![0u8; 16 + 16 + len + padding + 16]; let mut header = header.out(); - header.resize(16, 0u8); - let header_len = header.len(); - &mut packet[..header_len].copy_from_slice(&mut header); - self.encoder.encrypt(&mut packet[..header_len])?; - EncryptedConnection::update_mac(&mut self.egress_mac, &self.mac_encoder_key, &packet[..header_len])?; - self.egress_mac.clone().finalize(&mut packet[header_len..32]); + header.resize(HEADER_LEN, 0u8); + &mut packet[..HEADER_LEN].copy_from_slice(&mut header); + self.encoder.encrypt(&mut packet[..HEADER_LEN])?; + EncryptedConnection::update_mac(&mut self.egress_mac, &self.mac_encoder_key, &packet[..HEADER_LEN])?; + self.egress_mac.clone().finalize(&mut packet[HEADER_LEN..32]); &mut packet[32..32 + len].copy_from_slice(payload); self.encoder.encrypt(&mut packet[32..32 + len])?; if padding != 0 { From e4e00c90d0a213136cd229b5b79da7ed917aeed6 Mon Sep 17 00:00:00 2001 From: David Palm Date: Mon, 17 Jun 2019 15:11:23 +0200 Subject: [PATCH 10/11] whitespace --- util/network-devp2p/src/connection.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/util/network-devp2p/src/connection.rs b/util/network-devp2p/src/connection.rs index 592b79d6132..3e612282f64 100644 --- a/util/network-devp2p/src/connection.rs +++ b/util/network-devp2p/src/connection.rs @@ -321,8 +321,8 @@ impl EncryptedConnection { // of same IV use for different key. let encoder = AesCtr256::new(&key_material[32..64], &NULL_IV)?; let decoder = AesCtr256::new(&key_material[32..64], &NULL_IV)?; - let key_material_keccak = keccak(&key_material); - (&mut key_material[32..64]).copy_from_slice(key_material_keccak.as_bytes()); + let key_material_keccak = keccak(&key_material); + (&mut key_material[32..64]).copy_from_slice(key_material_keccak.as_bytes()); let mac_encoder_key: Secret = Secret::from_slice(&key_material[32..64]).expect("can create Secret from 32 bytes; qed"); let mut egress_mac = Keccak::new_keccak256(); From b2e51bb752d253539ce354923ac9cd2fcb31fbb5 Mon Sep 17 00:00:00 2001 From: David Palm Date: Mon, 17 Jun 2019 15:19:44 +0200 Subject: [PATCH 11/11] error chain is dead --- util/network-devp2p/src/connection.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/network-devp2p/src/connection.rs b/util/network-devp2p/src/connection.rs index 3e612282f64..ef9e74311b3 100644 --- a/util/network-devp2p/src/connection.rs +++ b/util/network-devp2p/src/connection.rs @@ -431,7 +431,7 @@ impl EncryptedConnection { let mut expected = H128::default(); self.ingress_mac.clone().finalize(expected.as_bytes_mut()); if mac != &expected[..] { - return Err(ErrorKind::Auth); + return Err(Error::Auth); } } self.decoder.decrypt(&mut payload[..self.payload_len + padding])?;