diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 5ce3c88af..29658b811 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -14,7 +14,7 @@ jobs: os: [ubuntu-latest, macos-latest, windows-latest] rust: - stable - - 1.44.0 + - 1.48.0 steps: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 diff --git a/README.md b/README.md index 6f909812f..64f1472bb 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ issue / pull request should be filled on the reference repository. [CONTRIBUTING.md](/CONTRIBUTING.md). ## Building -Fairly simple. First, install [Rust] >= 1.44.0 and a C compiler ([Build Tools +Fairly simple. First, install [Rust] >= 1.48.0 and a C compiler ([Build Tools for Visual Studio][VSBuild] on Windows, GCC or Clang on other platforms). Then you can build the debug version with diff --git a/tox_binary_io/src/sodium.rs b/tox_binary_io/src/sodium.rs index 936074f25..bdd3b27e3 100644 --- a/tox_binary_io/src/sodium.rs +++ b/tox_binary_io/src/sodium.rs @@ -1,6 +1,4 @@ -use nom::named; - -use nom::{map_opt, take}; +use nom::{map_opt, named, take}; use sodiumoxide::crypto::box_::{ PublicKey, @@ -11,7 +9,6 @@ use sodiumoxide::crypto::box_::{ NONCEBYTES }; -use sodiumoxide::crypto::hash::{sha256, sha512}; use sodiumoxide::crypto::secretbox; use super::FromBytes; @@ -46,18 +43,10 @@ impl FromBytes for secretbox::Nonce { named!(from_bytes, map_opt!(take!(secretbox::NONCEBYTES), secretbox::Nonce::from_slice)); } -impl FromBytes for sha256::Digest { - named!(from_bytes, map_opt!(take!(sha256::DIGESTBYTES), sha256::Digest::from_slice)); -} - -impl FromBytes for sha512::Digest { - named!(from_bytes, map_opt!(take!(sha512::DIGESTBYTES), sha512::Digest::from_slice)); -} - #[cfg(test)] mod tests { use super::*; - + #[test] fn public_key_parse_bytes_test() { let bytes = [42; PUBLICKEYBYTES]; diff --git a/tox_core/Cargo.toml b/tox_core/Cargo.toml index c06666b54..843ff5d33 100644 --- a/tox_core/Cargo.toml +++ b/tox_core/Cargo.toml @@ -32,6 +32,7 @@ lru = "0.6" bitflags = "1.0" itertools = "0.10" rand = "0.8" +sha2 = "0.9" [dependencies.tokio] version = "1.0" diff --git a/tox_core/src/dht/server/mod.rs b/tox_core/src/dht/server/mod.rs index 708491e44..1b26a8893 100644 --- a/tox_core/src/dht/server/mod.rs +++ b/tox_core/src/dht/server/mod.rs @@ -2414,12 +2414,11 @@ mod tests { let response = unpack!(packet, Packet::OnionResponse3); let response = unpack!(response.payload, InnerOnionResponse::OnionAnnounceResponse); let payload = response.get_payload(&precomp).unwrap(); - let ping_id = sha256::Digest(payload.ping_id_or_pk); // announce node let payload = OnionAnnounceRequestPayload { - ping_id, + ping_id: payload.ping_id_or_pk, search_pk: gen_keypair().0, data_pk: gen_keypair().0, sendback_data: 42 diff --git a/tox_core/src/onion/client/mod.rs b/tox_core/src/onion/client/mod.rs index 305a8c68c..da8d81c6e 100644 --- a/tox_core/src/onion/client/mod.rs +++ b/tox_core/src/onion/client/mod.rs @@ -27,7 +27,7 @@ use tox_packet::ip_port::*; use crate::onion::client::errors::*; use crate::onion::client::onion_path::*; use crate::onion::client::paths_pool::*; -use crate::onion::onion_announce::INITIAL_PING_ID; +use crate::onion::onion_announce::{PingId, INITIAL_PING_ID}; use tox_packet::onion::*; use tox_packet::packed_node::*; use crate::relay::client::Connections as TcpConnections; @@ -169,7 +169,7 @@ struct OnionNode { /// Path used to send packets to this node. path_id: OnionPathId, /// Ping id that should be used to announce to this node. - ping_id: Option, + ping_id: Option, /// Data `PublicKey` that should be used to send data packets to our friend /// through this node. data_pk: Option, @@ -268,7 +268,7 @@ struct AnnouncePacketData<'a> { impl<'a> AnnouncePacketData<'a> { /// Create `InnerOnionAnnounceRequest`. The request is a search request if /// pind_id is 0 and an announce request otherwise. - fn request(&self, node_pk: &PublicKey, ping_id: Option, request_id: u64) -> InnerOnionAnnounceRequest { + fn request(&self, node_pk: &PublicKey, ping_id: Option, request_id: u64) -> InnerOnionAnnounceRequest { let payload = OnionAnnounceRequestPayload { ping_id: ping_id.unwrap_or(INITIAL_PING_ID), search_pk: self.search_pk, @@ -286,7 +286,7 @@ impl<'a> AnnouncePacketData<'a> { self.request(node_pk, None, request_id) } /// Create `InnerOnionAnnounceRequest` for an announce request. - pub fn announce_request(&self, node_pk: &PublicKey, ping_id: sha256::Digest, request_id: u64) -> InnerOnionAnnounceRequest { + pub fn announce_request(&self, node_pk: &PublicKey, ping_id: PingId, request_id: u64) -> InnerOnionAnnounceRequest { self.request(node_pk, Some(ping_id), request_id) } } @@ -469,7 +469,7 @@ impl OnionClient { let (ping_id, data_pk) = if payload.announce_status == AnnounceStatus::Found { (None, Some(PublicKey(payload.ping_id_or_pk))) } else { - (Some(sha256::Digest(payload.ping_id_or_pk)), None) + (Some(payload.ping_id_or_pk), None) }; let now = clock_now(); @@ -1021,7 +1021,7 @@ mod tests { keys: [gen_keypair().0, gen_keypair().0, gen_keypair().0], path_type: OnionPathType::Udp, }; - let ping_id = sha256::hash(&[1, 2, 3]); + let ping_id = [42; 32]; let data_pk = gen_keypair().0; let new_now = now + Duration::from_secs(1); let other_onion_node = OnionNode { @@ -1228,7 +1228,7 @@ mod tests { // The sender should be added to close nodes let onion_node = state.announce_list.get_node(&real_pk, &sender_pk).unwrap(); assert_eq!(onion_node.path_id, path.id()); - assert_eq!(onion_node.ping_id, Some(sha256::Digest(ping_id))); + assert_eq!(onion_node.ping_id, Some(ping_id)); assert_eq!(onion_node.data_pk, None); assert_eq!(onion_node.announce_status, AnnounceStatus::Announced); @@ -1920,7 +1920,7 @@ mod tests { state.paths_pool.path_nodes.put(node); } - let ping_id = sha256::hash(&[1, 2, 3]); + let ping_id = [42; 32]; let now = Instant::now(); let mut nodes_key_by_addr = HashMap::new(); @@ -2064,7 +2064,7 @@ mod tests { saddr, path_id: path.id(), // regardless of this ping_id search requests should contain 0 - ping_id: Some(sha256::hash(&[1, 2, 3])), + ping_id: Some([42; 32]), data_pk: None, unsuccessful_pings: 0, added_time: now, diff --git a/tox_core/src/onion/onion_announce.rs b/tox_core/src/onion/onion_announce.rs index 03fa50547..388737994 100644 --- a/tox_core/src/onion/onion_announce.rs +++ b/tox_core/src/onion/onion_announce.rs @@ -4,6 +4,8 @@ use std::io::{ErrorKind, Error}; use std::net::{IpAddr, SocketAddr}; use std::time::{Duration, Instant, SystemTime}; +use sha2::{Digest, Sha256}; +use sha2::digest::generic_array::typenum::marker_traits::Unsigned; use tox_binary_io::*; use tox_crypto::*; @@ -11,6 +13,9 @@ use crate::time::*; use tox_packet::onion::*; use crate::dht::kbucket::Distance; +/// The type of onion ping ID which is SHA256 hash. +pub type PingId = [u8; ::OutputSize::USIZE]; + /// Number of secret random bytes to make onion ping id unique for each node. pub const SECRET_BYTES_SIZE: usize = 32; @@ -28,7 +33,7 @@ pub const PING_ID_TIMEOUT: Duration = Duration::from_secs(300); pub const ONION_ANNOUNCE_TIMEOUT: Duration = Duration::from_secs(300); /// Create onion ping id filled with zeros. -pub const INITIAL_PING_ID: sha256::Digest = sha256::Digest([0; sha256::DIGESTBYTES]); +pub const INITIAL_PING_ID: PingId = [0; ::OutputSize::USIZE]; /** Entry that corresponds to announced onion node. @@ -137,11 +142,11 @@ impl OnionPingData { so this hash remains unchanged for `PING_ID_TIMEOUT`. */ - pub fn ping_id(&self) -> sha256::Digest { + pub fn ping_id(&self) -> PingId { let mut buf = [0; ONION_PING_DATA_SIZE]; // can not fail since buf has enough length self.to_bytes((&mut buf, 0)).unwrap(); - sha256::hash(&buf) + Sha256::digest(&buf).into() } } @@ -176,7 +181,7 @@ impl OnionAnnounce { so this hash remains unchanged for `PING_ID_TIMEOUT`. */ - fn ping_id(&self, time: SystemTime, pk: PublicKey, ip_addr: IpAddr, port: u16) -> sha256::Digest { + fn ping_id(&self, time: SystemTime, pk: PublicKey, ip_addr: IpAddr, port: u16) -> PingId { let data = OnionPingData { secret_bytes: self.secret_bytes, time, @@ -286,10 +291,10 @@ impl OnionAnnounce { if entry.data_pk != payload.data_pk { // failed to find ourselves with same long term pk but different data pk // weird case, should we remove it? - (AnnounceStatus::Failed, ping_id_2.0) + (AnnounceStatus::Failed, ping_id_2) } else { // successfully announced ourselves - (AnnounceStatus::Announced, ping_id_2.0) + (AnnounceStatus::Announced, ping_id_2) } } else { // requested node is found by its long term pk @@ -297,7 +302,7 @@ impl OnionAnnounce { } } else { // requested node not found or failed to announce - (AnnounceStatus::Failed, ping_id_2.0) + (AnnounceStatus::Failed, ping_id_2) } } diff --git a/tox_crypto/src/lib.rs b/tox_crypto/src/lib.rs index 4300c1497..fcd00395a 100644 --- a/tox_crypto/src/lib.rs +++ b/tox_crypto/src/lib.rs @@ -4,7 +4,6 @@ pub use sodiumoxide::randombytes::randombytes_into; pub use sodiumoxide::crypto::box_::*; -pub use sodiumoxide::crypto::hash::{sha256, sha512}; pub use sodiumoxide::crypto::secretbox; pub use sodiumoxide::crypto::pwhash; diff --git a/tox_encryptsave/Cargo.toml b/tox_encryptsave/Cargo.toml index f2b82bc91..c80cab99a 100644 --- a/tox_encryptsave/Cargo.toml +++ b/tox_encryptsave/Cargo.toml @@ -21,3 +21,4 @@ edition = "2018" [dependencies] tox_crypto = { version = "0.1.0", path = "../tox_crypto" } failure = "0.1" +sha2 = "0.9" diff --git a/tox_encryptsave/src/lib.rs b/tox_encryptsave/src/lib.rs index ceb7aca30..e1719d3a8 100644 --- a/tox_encryptsave/src/lib.rs +++ b/tox_encryptsave/src/lib.rs @@ -22,6 +22,7 @@ assert_eq!(plaintext, */ use failure::Fail; +use sha2::{Digest, Sha256}; use tox_crypto::pwhash::{ MEMLIMIT_INTERACTIVE, OPSLIMIT_INTERACTIVE, @@ -33,7 +34,7 @@ use tox_crypto::{ NONCEBYTES, MACBYTES, Nonce, PrecomputedKey, gen_nonce, - secretbox, sha256 + secretbox }; /// Length in bytes of the salt used to encrypt/decrypt data. @@ -117,7 +118,7 @@ impl PassKey { pub fn with_salt(passphrase: &[u8], salt: Salt) -> Result { if passphrase.is_empty() { return Err(KeyDerivationError::Null) }; - let sha256::Digest(passhash) = sha256::hash(passphrase); + let passhash = Sha256::digest(passphrase); let OpsLimit(ops) = OPSLIMIT_INTERACTIVE; let mut key = secretbox::Key([0; secretbox::KEYBYTES]); diff --git a/tox_packet/Cargo.toml b/tox_packet/Cargo.toml index bf33ad6d1..d3aa8f3f6 100644 --- a/tox_packet/Cargo.toml +++ b/tox_packet/Cargo.toml @@ -26,3 +26,4 @@ nom = "5.1" cookie-factory = "0.3" bitflags = "1.0" failure = "0.1" +sha2 = "0.9" diff --git a/tox_packet/src/dht/cookie.rs b/tox_packet/src/dht/cookie.rs index 6145cb780..cf6cfd719 100644 --- a/tox_packet/src/dht/cookie.rs +++ b/tox_packet/src/dht/cookie.rs @@ -3,8 +3,10 @@ use super::*; use nom::number::complete::be_u64; +use sha2::{Digest, Sha512}; +use sha2::digest::generic_array::typenum::marker_traits::Unsigned; -use std::time::SystemTime; +use std::{convert::TryInto, time::SystemTime}; use tox_binary_io::*; use tox_crypto::*; @@ -160,10 +162,11 @@ impl EncryptedCookie { } } /// Calculate SHA512 hash of encrypted cookie together with nonce - pub fn hash(&self) -> sha512::Digest { + pub fn hash(&self) -> [u8; ::OutputSize::USIZE] { let mut buf = [0; 112]; let (_, size) = self.to_bytes((&mut buf, 0)).unwrap(); - sha512::hash(&buf[..size]) + // TODO: use `Into` directly when GenericArray supports it + Sha512::digest(&buf[..size]).as_slice().try_into().unwrap() } } diff --git a/tox_packet/src/dht/crypto_handshake.rs b/tox_packet/src/dht/crypto_handshake.rs index 1de370547..3cddbcc2a 100644 --- a/tox_packet/src/dht/crypto_handshake.rs +++ b/tox_packet/src/dht/crypto_handshake.rs @@ -3,6 +3,10 @@ use super::*; +use std::convert::TryInto; +use nom::map_opt; +use sha2::{Digest, Sha512}; +use sha2::digest::generic_array::typenum::marker_traits::Unsigned; use tox_binary_io::*; use tox_crypto::*; use crate::dht::cookie::EncryptedCookie; @@ -126,7 +130,7 @@ pub struct CryptoHandshakePayload { /// used to make sure that possible attacker can't combine payload from old /// `CryptoHandshake` with new `Cookie` and try to do mess sending such /// packets. - pub cookie_hash: sha512::Digest, + pub cookie_hash: [u8; ::OutputSize::USIZE], /// Encrypted cookie of sender of `CryptoHandshake` packet. When node /// receives `CryptoHandshake` it can take this cookie instead of sending /// `CookieRequest` to obtain one. @@ -137,7 +141,7 @@ impl FromBytes for CryptoHandshakePayload { named!(from_bytes, do_parse!( base_nonce: call!(Nonce::from_bytes) >> session_pk: call!(PublicKey::from_bytes) >> - cookie_hash: call!(sha512::Digest::from_bytes) >> + cookie_hash: map_opt!(take!(::OutputSize::USIZE), |bytes: &[u8]| bytes.try_into().ok()) >> cookie: call!(EncryptedCookie::from_bytes) >> eof!() >> (CryptoHandshakePayload { @@ -184,7 +188,7 @@ mod tests { CryptoHandshakePayload { base_nonce: gen_nonce(), session_pk: gen_keypair().0, - cookie_hash: sha512::hash(&[1, 2, 3]), + cookie_hash: [42; 64], cookie: EncryptedCookie { nonce: secretbox::gen_nonce(), payload: vec![42; 88], @@ -205,7 +209,7 @@ mod tests { let payload = CryptoHandshakePayload { base_nonce: gen_nonce(), session_pk: gen_keypair().0, - cookie_hash: sha512::hash(&[1, 2, 3]), + cookie_hash: [42; 64], cookie: EncryptedCookie { nonce: secretbox::gen_nonce(), payload: vec![42; 88], @@ -234,7 +238,7 @@ mod tests { let payload = CryptoHandshakePayload { base_nonce: gen_nonce(), session_pk: gen_keypair().0, - cookie_hash: sha512::hash(&[1, 2, 3]), + cookie_hash: [42; 64], cookie: EncryptedCookie { nonce: secretbox::gen_nonce(), payload: vec![42; 88], diff --git a/tox_packet/src/onion/onion_announce_request.rs b/tox_packet/src/onion/onion_announce_request.rs index 23864042e..1ddf375f9 100644 --- a/tox_packet/src/onion/onion_announce_request.rs +++ b/tox_packet/src/onion/onion_announce_request.rs @@ -3,12 +3,14 @@ use super::*; +use std::convert::TryInto; use tox_binary_io::*; use tox_crypto::*; use crate::dht::*; use nom::{ flat_map, + map_opt, number::complete::le_u64, combinator::{rest, rest_len}, bytes::complete::take @@ -170,7 +172,7 @@ Length | Content #[derive(Clone, Debug, Eq, PartialEq)] pub struct OnionAnnounceRequestPayload { /// Onion ping id - pub ping_id: sha256::Digest, + pub ping_id: [u8; 32], /// `PublicKey` we are searching for pub search_pk: PublicKey, /// `PublicKey` that should be used for sending data packets @@ -181,7 +183,7 @@ pub struct OnionAnnounceRequestPayload { impl FromBytes for OnionAnnounceRequestPayload { named!(from_bytes, do_parse!( - ping_id: call!(sha256::Digest::from_bytes) >> + ping_id: map_opt!(take!(32), |bytes: &[u8]| bytes.try_into().ok()) >> search_pk: call!(PublicKey::from_bytes) >> data_pk: call!(PublicKey::from_bytes) >> sendback_data: le_u64 >> @@ -237,7 +239,7 @@ mod tests { tox_crypto::crypto_init().unwrap(), onion_announce_request_payload_encode_decode, OnionAnnounceRequestPayload { - ping_id: sha256::hash(&[1, 2, 3]), + ping_id: [42; 32], search_pk: gen_keypair().0, data_pk: gen_keypair().0, sendback_data: 12345 @@ -251,7 +253,7 @@ mod tests { let (bob_pk, _bob_sk) = gen_keypair(); let shared_secret = encrypt_precompute(&bob_pk, &alice_sk); let payload = OnionAnnounceRequestPayload { - ping_id: sha256::hash(&[1, 2, 3]), + ping_id: [42; 32], search_pk: gen_keypair().0, data_pk: gen_keypair().0, sendback_data: 12345 @@ -272,7 +274,7 @@ mod tests { let (_eve_pk, eve_sk) = gen_keypair(); let shared_secret = encrypt_precompute(&bob_pk, &alice_sk); let payload = OnionAnnounceRequestPayload { - ping_id: sha256::hash(&[1, 2, 3]), + ping_id: [42; 32], search_pk: gen_keypair().0, data_pk: gen_keypair().0, sendback_data: 12345