1use nym_noise_keys::NoiseVersion;
5use snow::error::Prerequisite;
6use snow::Error;
7use tokio::net::TcpStream;
8use tracing::{error, warn};
9
10pub mod config;
11pub mod connection;
12pub mod error;
13pub mod stream;
14
15use crate::config::NoiseConfig;
16use crate::connection::Connection;
17use crate::error::NoiseError;
18use crate::stream::NoiseStreamBuilder;
19
20const NOISE_PSK_PREFIX: &[u8] = b"NYMTECH_NOISE_dQw4w9WgXcQ";
21
22pub const LATEST_NOISE_VERSION: NoiseVersion = NoiseVersion::V1;
23
24mod psk_gen {
27 use crate::error::NoiseError;
28 use crate::stream::Psk;
29 use crate::NOISE_PSK_PREFIX;
30 use nym_crypto::asymmetric::x25519;
31 use nym_noise_keys::NoiseVersion;
32 use sha2::{Digest, Sha256};
33
34 pub(crate) fn generate_psk(
35 responder_pub_key: x25519::PublicKey,
36 version: NoiseVersion,
37 ) -> Result<Psk, NoiseError> {
38 match version {
39 NoiseVersion::V1 => Ok(generate_psk_v1(responder_pub_key)),
40 NoiseVersion::Unknown(noise_version) => {
41 Err(NoiseError::PskGenerationFailure { noise_version })
42 }
43 }
44 }
45
46 fn generate_psk_v1(responder_pub_key: x25519::PublicKey) -> [u8; 32] {
47 let mut hasher = Sha256::new();
48 hasher.update(NOISE_PSK_PREFIX);
49 hasher.update(responder_pub_key.to_bytes());
50 hasher.finalize().into()
51 }
52}
53
54pub async fn upgrade_noise_initiator(
55 conn: TcpStream,
56 config: &NoiseConfig,
57) -> Result<Connection<TcpStream>, NoiseError> {
58 if config.unsafe_disabled {
59 warn!("Noise is disabled in the config. Not attempting any handshake");
60 return Ok(Connection::Raw(conn));
61 }
62
63 let responder_addr = conn.peer_addr().map_err(|err| {
65 error!("Unable to extract peer address from connection - {err}");
66 Error::Prereq(Prerequisite::RemotePublicKey)
67 })?;
68
69 let Some(key) = config.get_noise_key(&responder_addr) else {
70 warn!("{responder_addr} can't speak Noise yet, falling back to TCP");
71 return Ok(Connection::Raw(conn));
72 };
73
74 let handshake_version = match key.supported_version {
75 NoiseVersion::V1 => NoiseVersion::V1,
76
77 NoiseVersion::Unknown(version) => {
80 warn!("{responder_addr} is announcing an v{version} version of Noise that we don't know how to parse, we will attempt to downgrade to our current highest supported version");
81 LATEST_NOISE_VERSION
82 }
83 };
84
85 NoiseStreamBuilder::new(conn)
86 .perform_initiator_handshake(config, handshake_version, key.x25519_pubkey)
87 .await
88 .map(|stream| Connection::Noise(Box::new(stream)))
89}
90pub async fn upgrade_noise_responder(
91 conn: TcpStream,
92 config: &NoiseConfig,
93) -> Result<Connection<TcpStream>, NoiseError> {
94 if config.unsafe_disabled {
95 warn!("Noise is disabled in the config. Not attempting any handshake");
96 return Ok(Connection::Raw(conn));
97 }
98
99 let initiator_addr = match conn.peer_addr() {
101 Ok(addr) => addr,
102 Err(err) => {
103 error!("Unable to extract peer address from connection - {err}");
104 return Err(Error::Prereq(Prerequisite::RemotePublicKey).into());
105 }
106 };
107
108 if config.get_noise_support(initiator_addr.ip()).is_none() {
110 warn!("{initiator_addr} can't speak Noise yet, falling back to TCP",);
111 return Ok(Connection::Raw(conn));
112 };
113
114 NoiseStreamBuilder::new(conn)
115 .perform_responder_handshake(config)
116 .await
117 .map(|stream| Connection::Noise(Box::new(stream)))
118}