1use std::io::{Read, Write};
10use std::net::TcpStream;
11
12use crate::error::{Error, Result};
13
14const NOISE_PARAMS: &str = "Noise_XX_25519_ChaChaPoly_BLAKE2s";
15const CHUNK: usize = 60_000;
17
18pub fn generate_keypair() -> Result<(Vec<u8>, Vec<u8>)> {
20 let b = snow::Builder::new(NOISE_PARAMS.parse().map_err(noise)?);
21 let kp = b.generate_keypair().map_err(noise)?;
22 Ok((kp.private, kp.public))
23}
24
25fn noise<E: std::fmt::Display>(e: E) -> Error {
26 Error::Noise(e.to_string())
27}
28
29fn write_frame(s: &mut TcpStream, data: &[u8]) -> Result<()> {
30 let len: u16 = data
31 .len()
32 .try_into()
33 .map_err(|_| Error::Protocol("noise frame too large".into()))?;
34 s.write_all(&len.to_be_bytes())?;
35 s.write_all(data)?;
36 Ok(())
37}
38
39fn read_frame(s: &mut TcpStream) -> Result<Vec<u8>> {
40 let mut len = [0u8; 2];
41 s.read_exact(&mut len)?;
42 let mut buf = vec![0u8; u16::from_be_bytes(len) as usize];
43 s.read_exact(&mut buf)?;
44 Ok(buf)
45}
46
47pub struct Transport {
49 stream: TcpStream,
50 noise: snow::TransportState,
51 pub remote_static: Vec<u8>,
53}
54
55impl Transport {
56 pub fn initiate(stream: TcpStream, static_priv: &[u8]) -> Result<Self> {
58 Self::handshake(stream, static_priv, true)
59 }
60
61 pub fn respond(stream: TcpStream, static_priv: &[u8]) -> Result<Self> {
63 Self::handshake(stream, static_priv, false)
64 }
65
66 fn handshake(mut stream: TcpStream, static_priv: &[u8], initiator: bool) -> Result<Self> {
67 let builder =
68 snow::Builder::new(NOISE_PARAMS.parse().map_err(noise)?).local_private_key(static_priv);
69 let mut hs = if initiator {
70 builder.build_initiator().map_err(noise)?
71 } else {
72 builder.build_responder().map_err(noise)?
73 };
74
75 let mut buf = vec![0u8; 65535];
76 let mut my_turn = initiator;
77 while !hs.is_handshake_finished() {
78 if my_turn {
79 let n = hs.write_message(&[], &mut buf).map_err(noise)?;
80 write_frame(&mut stream, &buf[..n])?;
81 } else {
82 let msg = read_frame(&mut stream)?;
83 hs.read_message(&msg, &mut buf).map_err(noise)?;
84 }
85 my_turn = !my_turn;
86 }
87 let remote_static = hs
88 .get_remote_static()
89 .map(|s| s.to_vec())
90 .ok_or_else(|| Error::Protocol("peer did not present a static key".into()))?;
91 let noise = hs.into_transport_mode().map_err(noise)?;
92 Ok(Self {
93 stream,
94 noise,
95 remote_static,
96 })
97 }
98
99 pub fn send(&mut self, plaintext: &[u8]) -> Result<()> {
101 let mut out = vec![0u8; 65535];
102 for chunk in plaintext.chunks(CHUNK).chain(if plaintext.is_empty() {
103 Some([].as_slice())
105 } else {
106 None
107 }) {
108 let n = self.noise.write_message(chunk, &mut out).map_err(noise)?;
109 write_frame(&mut self.stream, &out[..n])?;
110 }
111 write_frame(&mut self.stream, &[])?;
113 Ok(())
114 }
115
116 pub fn recv(&mut self) -> Result<Vec<u8>> {
118 let mut out = vec![0u8; 65535];
119 let mut msg = Vec::new();
120 loop {
121 let frame = read_frame(&mut self.stream)?;
122 if frame.is_empty() {
123 break;
124 }
125 let n = self.noise.read_message(&frame, &mut out).map_err(noise)?;
126 msg.extend_from_slice(&out[..n]);
127 }
128 Ok(msg)
129 }
130}