1use super::wire::{self, PbValue};
5use anyhow::{bail, ensure, Context, Result};
6use ed25519_dalek::{Signer, SigningKey, Verifier, VerifyingKey};
7use hkdf::Hkdf;
8use ring::aead::{self, LessSafeKey, Nonce, UnboundKey, CHACHA20_POLY1305};
9use sha2::{Digest, Sha256};
10use std::future::Future;
11use tokio::io::{AsyncReadExt, AsyncWriteExt};
12use tokio::net::tcp::{OwnedReadHalf, OwnedWriteHalf};
13use tokio::net::TcpStream;
14use x25519_dalek::{PublicKey, StaticSecret};
15
16const PROTOCOL_NAME: &[u8; 32] = b"Noise_XX_25519_ChaChaPoly_SHA256";
17const SIG_PREFIX: &[u8] = b"noise-libp2p-static-key:";
18const TAG: usize = 16;
19pub const MAX_NOISE_MESSAGE: usize = 65535;
21pub const MAX_PLAINTEXT: usize = MAX_NOISE_MESSAGE - TAG;
23
24pub struct Identity {
26 pub key: SigningKey,
27 pub public_key_proto: Vec<u8>,
28 pub peer_id: Vec<u8>,
29}
30
31impl Identity {
32 pub fn from_seed(seed: [u8; 32]) -> Self {
33 let key = SigningKey::from_bytes(&seed);
34 let public_key_proto = wire::ed25519_public_key_proto(&key.verifying_key().to_bytes());
35 let peer_id = wire::peer_id(&public_key_proto);
36 Self {
37 key,
38 public_key_proto,
39 peer_id,
40 }
41 }
42 pub fn random() -> Self {
43 Self::from_seed(rand::random())
44 }
45 pub fn peer_id_string(&self) -> String {
46 wire::peer_id_string(&self.peer_id)
47 }
48}
49
50struct Cipher {
51 key: Option<LessSafeKey>,
52 n: u64,
53}
54
55impl Cipher {
56 fn empty() -> Self {
57 Self { key: None, n: 0 }
58 }
59 fn new(k: &[u8]) -> Self {
60 let key = UnboundKey::new(&CHACHA20_POLY1305, &k[..32]).expect("32-byte key");
61 Self {
62 key: Some(LessSafeKey::new(key)),
63 n: 0,
64 }
65 }
66 fn nonce(&mut self) -> Result<Nonce> {
67 ensure!(self.n < u64::MAX, "Noise nonce exhausted");
68 let mut n = [0u8; 12];
69 n[4..].copy_from_slice(&self.n.to_le_bytes());
70 self.n += 1;
71 Ok(Nonce::assume_unique_for_key(n))
72 }
73 fn encrypt(&mut self, ad: &[u8], plaintext: &[u8]) -> Result<Vec<u8>> {
74 if self.key.is_none() {
75 return Ok(plaintext.to_vec());
76 }
77 let nonce = self.nonce()?;
78 let mut buf = plaintext.to_vec();
79 self.key
80 .as_ref()
81 .expect("checked above")
82 .seal_in_place_append_tag(nonce, aead::Aad::from(ad), &mut buf)
83 .map_err(|_| anyhow::anyhow!("Noise encryption failed"))?;
84 Ok(buf)
85 }
86 fn decrypt(&mut self, ad: &[u8], ciphertext: &[u8]) -> Result<Vec<u8>> {
87 if self.key.is_none() {
88 return Ok(ciphertext.to_vec());
89 }
90 let nonce = self.nonce()?;
91 let mut buf = ciphertext.to_vec();
92 let n = self
93 .key
94 .as_ref()
95 .expect("checked above")
96 .open_in_place(nonce, aead::Aad::from(ad), &mut buf)
97 .map_err(|_| {
98 anyhow::anyhow!("Noise decryption failed (wrong key or tampered message)")
99 })?
100 .len();
101 buf.truncate(n);
102 Ok(buf)
103 }
104}
105
106struct Symmetric {
107 ck: [u8; 32],
108 h: [u8; 32],
109 cipher: Cipher,
110}
111
112fn hkdf2(ck: &[u8; 32], ikm: &[u8]) -> ([u8; 32], [u8; 32]) {
113 let mut okm = [0u8; 64];
114 Hkdf::<Sha256>::new(Some(ck), ikm)
115 .expand(&[], &mut okm)
116 .expect("64 bytes is a valid HKDF length");
117 let (a, b) = okm.split_at(32);
118 (a.try_into().unwrap(), b.try_into().unwrap())
119}
120
121impl Symmetric {
122 fn new() -> Self {
123 let h = *PROTOCOL_NAME;
124 let mut s = Self {
125 ck: h,
126 h,
127 cipher: Cipher::empty(),
128 };
129 s.mix_hash(&[]); s
131 }
132 fn mix_hash(&mut self, data: &[u8]) {
133 let mut d = Sha256::new();
134 d.update(self.h);
135 d.update(data);
136 self.h = d.finalize().into();
137 }
138 fn mix_key(&mut self, ikm: &[u8]) {
139 let (ck, k) = hkdf2(&self.ck, ikm);
140 self.ck = ck;
141 self.cipher = Cipher::new(&k);
142 }
143 fn encrypt_and_hash(&mut self, p: &[u8]) -> Result<Vec<u8>> {
144 let c = self.cipher.encrypt(&self.h, p)?;
145 self.mix_hash(&c);
146 Ok(c)
147 }
148 fn decrypt_and_hash(&mut self, c: &[u8]) -> Result<Vec<u8>> {
149 let p = self.cipher.decrypt(&self.h, c)?;
150 self.mix_hash(c);
151 Ok(p)
152 }
153 fn split(&self) -> (Cipher, Cipher) {
154 let (a, b) = hkdf2(&self.ck, &[]);
155 (Cipher::new(&a), Cipher::new(&b))
156 }
157}
158
159fn dh(secret: &StaticSecret, public: &[u8; 32]) -> [u8; 32] {
160 secret.diffie_hellman(&PublicKey::from(*public)).to_bytes()
161}
162
163async fn read_frame(tcp: &mut TcpStream) -> Result<Vec<u8>> {
164 let len = tcp.read_u16().await? as usize;
165 let mut b = vec![0u8; len];
166 tcp.read_exact(&mut b).await?;
167 Ok(b)
168}
169
170async fn write_frame(tcp: &mut TcpStream, b: &[u8]) -> Result<()> {
171 ensure!(b.len() <= MAX_NOISE_MESSAGE, "Noise message too long");
172 let mut out = (b.len() as u16).to_be_bytes().to_vec();
173 out.extend_from_slice(b);
174 tcp.write_all(&out).await?;
175 Ok(())
176}
177
178fn payload(id: &Identity, static_pub: &[u8; 32]) -> Vec<u8> {
179 let mut msg = SIG_PREFIX.to_vec();
180 msg.extend_from_slice(static_pub);
181 let sig = id.key.sign(&msg).to_bytes();
182 let mut out = Vec::new();
183 wire::pb_bytes(&mut out, 1, &id.public_key_proto);
184 wire::pb_bytes(&mut out, 2, &sig);
185 out
186}
187
188fn verify_payload(p: &[u8], remote_static: &[u8; 32]) -> Result<Vec<u8>> {
190 let mut key = None;
191 let mut sig = None;
192 for (f, v) in wire::pb_fields(p)? {
193 match (f, v) {
194 (1, PbValue::Bytes(b)) => key = Some(b),
195 (2, PbValue::Bytes(b)) => sig = Some(b),
196 _ => {}
197 }
198 }
199 let key_proto = key.context("handshake payload has no identity key")?;
200 let sig = sig.context("handshake payload has no signature")?;
201 let ed = wire::parse_public_key(key_proto)?;
202 let vk = VerifyingKey::from_bytes(&ed).context("invalid Ed25519 identity key")?;
203 let sig = ed25519_dalek::Signature::from_slice(sig).context("signature must be 64 bytes")?;
204 let mut msg = SIG_PREFIX.to_vec();
205 msg.extend_from_slice(remote_static);
206 vk.verify(&msg, &sig)
207 .context("the identity signature over the Noise static key does not verify")?;
208 Ok(wire::peer_id(key_proto))
209}
210
211pub struct NoiseConn {
213 pub reader: NoiseReader,
214 pub writer: NoiseWriter,
215 pub remote_peer: Vec<u8>,
216}
217
218pub async fn handshake(
220 mut tcp: TcpStream,
221 id: &Identity,
222 initiator: bool,
223 expected_peer: Option<&[u8]>,
224) -> Result<NoiseConn> {
225 let s = StaticSecret::random_from_rng(rand::rngs::OsRng);
226 let s_pub = PublicKey::from(&s).to_bytes();
227 let e = StaticSecret::random_from_rng(rand::rngs::OsRng);
228 let e_pub = PublicKey::from(&e).to_bytes();
229 let mut st = Symmetric::new();
230 let take32 = |b: &[u8], at: usize| -> Result<[u8; 32]> {
231 b.get(at..at + 32)
232 .and_then(|x| x.try_into().ok())
233 .context("Noise message too short")
234 };
235 let (remote_static, remote_payload) = if initiator {
236 st.mix_hash(&e_pub);
238 let mut m1 = e_pub.to_vec();
239 m1.extend(st.encrypt_and_hash(&[])?);
240 write_frame(&mut tcp, &m1).await?;
241 let m2 = read_frame(&mut tcp).await?;
243 let re = take32(&m2, 0)?;
244 st.mix_hash(&re);
245 st.mix_key(&dh(&e, &re));
246 ensure!(m2.len() >= 32 + 32 + TAG, "Noise message 2 too short");
247 let rs: [u8; 32] = st
248 .decrypt_and_hash(&m2[32..32 + 32 + TAG])?
249 .try_into()
250 .map_err(|_| anyhow::anyhow!("bad static key"))?;
251 st.mix_key(&dh(&e, &rs));
252 let p = st.decrypt_and_hash(&m2[32 + 32 + TAG..])?;
253 let mut m3 = st.encrypt_and_hash(&s_pub)?;
255 st.mix_key(&dh(&s, &re));
256 m3.extend(st.encrypt_and_hash(&payload(id, &s_pub))?);
257 let peer = verify_payload(&p, &rs)?;
259 if let Some(want) = expected_peer {
260 ensure!(
261 peer == want,
262 "dialled {} but the remote is {}",
263 wire::peer_id_string(want),
264 wire::peer_id_string(&peer)
265 );
266 }
267 write_frame(&mut tcp, &m3).await?;
268 (rs, peer)
269 } else {
270 let m1 = read_frame(&mut tcp).await?;
272 let re = take32(&m1, 0)?;
273 st.mix_hash(&re);
274 st.decrypt_and_hash(&m1[32..])?;
275 st.mix_hash(&e_pub);
277 let mut m2 = e_pub.to_vec();
278 st.mix_key(&dh(&e, &re));
279 m2.extend(st.encrypt_and_hash(&s_pub)?);
280 st.mix_key(&dh(&s, &re));
281 m2.extend(st.encrypt_and_hash(&payload(id, &s_pub))?);
282 write_frame(&mut tcp, &m2).await?;
283 let m3 = read_frame(&mut tcp).await?;
285 ensure!(m3.len() >= 32 + TAG, "Noise message 3 too short");
286 let rs: [u8; 32] = st
287 .decrypt_and_hash(&m3[..32 + TAG])?
288 .try_into()
289 .map_err(|_| anyhow::anyhow!("bad static key"))?;
290 st.mix_key(&dh(&e, &rs));
291 let p = st.decrypt_and_hash(&m3[32 + TAG..])?;
292 let peer = verify_payload(&p, &rs)?;
293 (rs, peer)
294 };
295 let _ = remote_static;
296 let (c1, c2) = st.split();
297 let (send, recv) = if initiator { (c1, c2) } else { (c2, c1) };
298 let (r, w) = tcp.into_split();
299 Ok(NoiseConn {
300 reader: NoiseReader {
301 tcp: r,
302 cipher: recv,
303 buf: Vec::new(),
304 pos: 0,
305 },
306 writer: NoiseWriter {
307 tcp: w,
308 cipher: send,
309 },
310 remote_peer: remote_payload,
311 })
312}
313
314pub struct NoiseReader {
315 tcp: OwnedReadHalf,
316 cipher: Cipher,
317 buf: Vec<u8>,
318 pos: usize,
319}
320
321impl NoiseReader {
322 async fn fill(&mut self) -> Result<()> {
323 let len = match self.tcp.read_u16().await {
324 Ok(l) => l as usize,
325 Err(e) if e.kind() == std::io::ErrorKind::UnexpectedEof => bail!("connection closed"),
326 Err(e) => return Err(e.into()),
327 };
328 ensure!(len >= TAG, "Noise transport message shorter than its tag");
329 let mut c = vec![0u8; len];
330 self.tcp.read_exact(&mut c).await?;
331 self.buf = self.cipher.decrypt(&[], &c)?;
332 self.pos = 0;
333 Ok(())
334 }
335 pub async fn read_exact(&mut self, out: &mut [u8]) -> Result<()> {
336 let mut done = 0;
337 while done < out.len() {
338 if self.pos == self.buf.len() {
339 self.fill().await?;
340 continue;
341 }
342 let n = (out.len() - done).min(self.buf.len() - self.pos);
343 out[done..done + n].copy_from_slice(&self.buf[self.pos..self.pos + n]);
344 self.pos += n;
345 done += n;
346 }
347 Ok(())
348 }
349}
350
351pub struct NoiseWriter {
352 tcp: OwnedWriteHalf,
353 cipher: Cipher,
354}
355
356impl NoiseWriter {
357 pub async fn write_all(&mut self, b: &[u8]) -> Result<()> {
358 let mut out = Vec::with_capacity(b.len() + (b.len() / MAX_PLAINTEXT + 1) * (TAG + 2));
359 for chunk in b.chunks(MAX_PLAINTEXT) {
360 let c = self.cipher.encrypt(&[], chunk)?;
361 out.extend_from_slice(&(c.len() as u16).to_be_bytes());
362 out.extend(c);
363 }
364 self.tcp.write_all(&out).await?;
365 Ok(())
366 }
367 pub async fn shutdown(&mut self) {
368 let _ = self.tcp.shutdown().await;
369 }
370}
371
372impl wire::Io for NoiseConn {
373 fn read_exact<'a>(
374 &'a mut self,
375 buf: &'a mut [u8],
376 ) -> impl Future<Output = Result<()>> + Send + 'a {
377 self.reader.read_exact(buf)
378 }
379 fn write_all<'a>(&'a mut self, buf: &'a [u8]) -> impl Future<Output = Result<()>> + Send + 'a {
380 self.writer.write_all(buf)
381 }
382}