Struct magic_wormhole::Key
source · pub struct Key<P: KeyPurpose>(pub Box<Key>, _);Expand description
The symmetric encryption key used to communicate with the other side.
You don’t need to do any crypto, but you might need it to derive subkeys for sub-protocols.
Tuple Fields§
§0: Box<Key>Implementations§
source§impl Key<WormholeKey>
impl Key<WormholeKey>
sourcepub fn derive_transit_key(&self, appid: &AppID) -> Key<TransitKey>
pub fn derive_transit_key(&self, appid: &AppID) -> Key<TransitKey>
Derive the sub-key used for transit
This one’s a bit special, since the Wormhole’s AppID is included in the purpose. Different kinds of applications can’t talk to each other, not even accidentally, by design.
The new key is derived with the "{appid}/transit-key" purpose.
Examples found in repository?
src/transfer.rs (line 471)
447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492
pub async fn accept<F, G, W>(
mut self,
transit_handler: G,
progress_handler: F,
content_handler: &mut W,
cancel: impl Future<Output = ()>,
) -> Result<(), TransferError>
where
F: FnMut(u64, u64) + 'static,
G: FnOnce(transit::TransitInfo, std::net::SocketAddr),
W: AsyncWrite + Unpin,
{
let run = Box::pin(async {
// send file ack.
debug!("Sending ack");
self.wormhole
.send_json(&PeerMessage::file_ack("ok"))
.await?;
let (mut transit, info, addr) = self
.connector
.follower_connect(
self.wormhole
.key()
.derive_transit_key(self.wormhole.appid()),
self.their_abilities,
self.their_hints.clone(),
)
.await?;
transit_handler(info, addr);
debug!("Beginning file transfer");
v1::tcp_file_receive(
&mut transit,
self.filesize,
progress_handler,
content_handler,
)
.await?;
Ok(())
});
futures::pin_mut!(cancel);
let result = crate::util::cancellable_2(run, cancel).await;
handle_run_result(self.wormhole, result).await
}More examples
src/transfer/v1.rs (line 81)
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340
pub async fn send_file<F, N, G, H>(
mut wormhole: Wormhole,
relay_hints: Vec<transit::RelayHint>,
file: &mut F,
file_name: N,
file_size: u64,
transit_abilities: transit::Abilities,
transit_handler: G,
progress_handler: H,
cancel: impl Future<Output = ()>,
) -> Result<(), TransferError>
where
F: AsyncRead + Unpin,
N: Into<PathBuf>,
G: FnOnce(transit::TransitInfo, std::net::SocketAddr),
H: FnMut(u64, u64) + 'static,
{
let run = Box::pin(async {
let connector = transit::init(transit_abilities, None, relay_hints).await?;
// We want to do some transit
debug!("Sending transit message '{:?}", connector.our_hints());
wormhole
.send_json(&PeerMessage::transit(
*connector.our_abilities(),
(**connector.our_hints()).clone(),
))
.await?;
// Send file offer message.
debug!("Sending file offer");
wormhole
.send_json(&PeerMessage::offer_file(file_name, file_size))
.await?;
// Wait for their transit response
let (their_abilities, their_hints): (transit::Abilities, transit::Hints) =
match wormhole.receive_json().await?? {
PeerMessage::Transit(transit) => {
debug!("Received transit message: {:?}", transit);
(transit.abilities_v1, transit.hints_v1)
},
PeerMessage::Error(err) => {
bail!(TransferError::PeerError(err));
},
other => {
bail!(TransferError::unexpected_message("transit", other))
},
};
{
// Wait for file_ack
let fileack_msg = wormhole.receive_json().await??;
debug!("Received file ack message: {:?}", fileack_msg);
match fileack_msg {
PeerMessage::Answer(Answer::FileAck(msg)) => {
ensure!(msg == "ok", TransferError::AckError);
},
PeerMessage::Error(err) => {
bail!(TransferError::PeerError(err));
},
_ => {
bail!(TransferError::unexpected_message(
"answer/file_ack",
fileack_msg
));
},
}
}
let (mut transit, info, addr) = connector
.leader_connect(
wormhole.key().derive_transit_key(wormhole.appid()),
their_abilities,
Arc::new(their_hints),
)
.await?;
transit_handler(info, addr);
debug!("Beginning file transfer");
// 11. send the file as encrypted records.
let checksum = v1::send_records(&mut transit, file, file_size, progress_handler).await?;
// 13. wait for the transit ack with sha256 sum from the peer.
debug!("sent file. Waiting for ack");
let transit_ack = transit.receive_record().await?;
let transit_ack_msg = serde_json::from_slice::<TransitAck>(&transit_ack)?;
ensure!(
transit_ack_msg.sha256 == hex::encode(checksum),
TransferError::Checksum
);
debug!("Transfer complete!");
Ok(())
});
futures::pin_mut!(cancel);
let result = crate::util::cancellable_2(run, cancel).await;
super::handle_run_result(wormhole, result).await
}
pub async fn send_folder<N, M, G, H>(
mut wormhole: Wormhole,
relay_hints: Vec<transit::RelayHint>,
folder_path: N,
folder_name: M,
transit_abilities: transit::Abilities,
transit_handler: G,
progress_handler: H,
cancel: impl Future<Output = ()>,
) -> Result<(), TransferError>
where
N: Into<PathBuf>,
M: Into<PathBuf>,
G: FnOnce(transit::TransitInfo, std::net::SocketAddr),
H: FnMut(u64, u64) + 'static,
{
let run = Box::pin(async {
let connector = transit::init(transit_abilities, None, relay_hints).await?;
let folder_path = folder_path.into();
if !folder_path.is_dir() {
panic!(
"You should only call this method with directory paths, but '{}' is not",
folder_path.display()
);
}
// We want to do some transit
debug!("Sending transit message '{:?}", connector.our_hints());
wormhole
.send_json(&PeerMessage::transit(
*connector.our_abilities(),
(**connector.our_hints()).clone(),
))
.await?;
// use sha2::{digest::FixedOutput, Digest, Sha256};
/* Helper struct stolen from https://docs.rs/count-write/0.1.0 */
struct CountWrite<W> {
inner: W,
count: u64,
}
impl<W: std::io::Write> std::io::Write for CountWrite<W> {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
let written = self.inner.write(buf)?;
self.count += written as u64;
Ok(written)
}
fn flush(&mut self) -> std::io::Result<()> {
self.inner.flush()
}
}
/* We need to know the length of what we are going to send in advance. So we build the
* tar file once, stream it into the void, and the second time we stream it over the
* wire. Also hashing for future reference.
*/
log::info!("Calculating the size of '{}'", folder_path.display());
let folder_path2 = folder_path.clone();
let (length, sha256sum_initial) = {
let mut hasher = Sha256::new();
let mut counter = CountWrite {
inner: &mut hasher,
count: 0,
};
let mut builder = async_tar::Builder::new(futures::io::AllowStdIo::new(&mut counter));
builder.mode(async_tar::HeaderMode::Deterministic);
builder.follow_symlinks(false);
/* A hasher should never fail writing */
builder.append_dir_all("", folder_path2).await.unwrap();
builder.finish().await.unwrap();
std::mem::drop(builder);
let count = counter.count;
std::mem::drop(counter);
(count, hasher.finalize_fixed())
};
// Send file offer message.
debug!("Sending file offer");
wormhole
.send_json(&PeerMessage::offer_file(folder_name, length))
.await?;
// Wait for their transit response
let (their_abilities, their_hints): (transit::Abilities, transit::Hints) =
match wormhole.receive_json().await?? {
PeerMessage::Transit(transit) => {
debug!("received transit message: {:?}", transit);
(transit.abilities_v1, transit.hints_v1)
},
PeerMessage::Error(err) => {
bail!(TransferError::PeerError(err));
},
other => {
bail!(TransferError::unexpected_message("transit", other));
},
};
// Wait for file_ack
match wormhole.receive_json().await?? {
PeerMessage::Answer(Answer::FileAck(msg)) => {
ensure!(msg == "ok", TransferError::AckError);
},
PeerMessage::Error(err) => {
bail!(TransferError::PeerError(err));
},
other => {
bail!(TransferError::unexpected_message("answer/file_ack", other));
},
}
let (mut transit, info, addr) = connector
.leader_connect(
wormhole.key().derive_transit_key(wormhole.appid()),
their_abilities,
Arc::new(their_hints),
)
.await?;
transit_handler(info, addr);
debug!("Beginning file transfer");
/* Inspired by https://github.com/RustCrypto/traits/pull/1159/files */
pub struct HashWriter<D: sha2::digest::Update, W: futures::io::AsyncWrite + Unpin> {
writer: W,
hasher: D,
}
use std::{
pin::Pin,
task::{Context, Poll},
};
impl<D: sha2::digest::Update + Unpin, W: futures::io::AsyncWrite + Unpin>
futures::io::AsyncWrite for HashWriter<D, W>
{
fn poll_write(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &[u8],
) -> Poll<std::io::Result<usize>> {
// log::debug!("Poll write, {}", buf.len());
match Pin::new(&mut self.writer).poll_write(cx, buf) {
Poll::Ready(Ok(n)) => {
self.hasher.update(&buf[..n]);
Poll::Ready(Ok(n))
},
res => res,
}
}
fn poll_flush(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<std::io::Result<()>> {
// log::debug!("Poll flush");
Pin::new(&mut self.writer).poll_flush(cx)
}
fn poll_close(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<std::io::Result<()>> {
// log::debug!("Poll close");
Pin::new(&mut self.writer).poll_close(cx)
}
}
// 11. send the file as encrypted records.
let (mut reader, writer) = futures_ringbuf::RingBuffer::new(4096).split();
let file_sender = async_std::task::spawn(async move {
let mut hash_writer = HashWriter {
writer,
hasher: Sha256::new(),
};
let mut builder = async_tar::Builder::new(&mut hash_writer);
builder.mode(async_tar::HeaderMode::Deterministic);
builder.follow_symlinks(false);
builder.append_dir_all("", folder_path).await?;
builder.finish().await?;
std::mem::drop(builder);
hash_writer.flush().await?;
hash_writer.close().await?;
let hasher = hash_writer.hasher;
std::io::Result::Ok(hasher.finalize_fixed())
});
let (checksum, sha256sum) =
match v1::send_records(&mut transit, &mut reader, length, progress_handler).await {
Ok(checksum) => (checksum, file_sender.await?),
Err(err) => {
log::debug!("Some more error {err}");
if let Some(Err(err)) = file_sender.cancel().await {
log::warn!("Error in background task: {err}");
}
return Err(err);
},
};
/* Check if the hash sum still matches what we advertized. Otherwise, tell the other side and bail out */
ensure!(
sha256sum == sha256sum_initial,
TransferError::FilesystemSkew
);
// 13. wait for the transit ack with sha256 sum from the peer.
debug!("sent file. Waiting for ack");
let transit_ack = transit.receive_record().await?;
let transit_ack_msg = serde_json::from_slice::<TransitAck>(&transit_ack)?;
ensure!(
transit_ack_msg.sha256 == hex::encode(checksum),
TransferError::Checksum
);
debug!("Transfer complete!");
Ok(())
});
futures::pin_mut!(cancel);
let result = crate::util::cancellable_2(run, cancel).await;
super::handle_run_result(wormhole, result).await
}source§impl<P: KeyPurpose> Key<P>
impl<P: KeyPurpose> Key<P>
sourcepub fn new(key: Box<Key>) -> Self
pub fn new(key: Box<Key>) -> Self
Examples found in repository?
src/core.rs (line 247)
202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252
pub async fn connect_custom(
mut server: RendezvousServer,
appid: AppID,
password: String,
app_versions: impl serde::Serialize + Send + Sync + 'static,
) -> Result<Self, WormholeError> {
/* Send PAKE */
let (pake_state, pake_msg_ser) = key::make_pake(&password, &appid);
server.send_peer_message(Phase::PAKE, pake_msg_ser).await?;
/* Receive PAKE */
let peer_pake = key::extract_pake_msg(&server.next_peer_message_some().await?.body)?;
let key = pake_state
.finish(&peer_pake)
.map_err(|_| WormholeError::PakeFailed)
.map(|key| *secretbox::Key::from_slice(&key))?;
/* Send versions message */
let mut versions = key::VersionsMessage::new();
versions.set_app_versions(serde_json::to_value(&app_versions).unwrap());
let (version_phase, version_msg) = key::build_version_msg(server.side(), &key, &versions);
server.send_peer_message(version_phase, version_msg).await?;
let peer_version = server.next_peer_message_some().await?;
/* Handle received message */
let versions: key::VersionsMessage = peer_version
.decrypt(&key)
.ok_or(WormholeError::PakeFailed)
.and_then(|plaintext| {
serde_json::from_slice(&plaintext).map_err(WormholeError::ProtocolJson)
})?;
let peer_version = versions.app_versions;
if server.needs_nameplate_release() {
server.release_nameplate().await?;
}
log::info!("Found peer on the rendezvous server.");
/* We are now fully initialized! Up and running! :tada: */
Ok(Self {
server,
appid,
phase: 0,
key: key::Key::new(key.into()),
verifier: Box::new(key::derive_verifier(&key)),
our_version: Box::new(app_versions),
peer_version,
})
}sourcepub fn to_hex(&self) -> String
pub fn to_hex(&self) -> String
Examples found in repository?
src/core/key.rs (line 57)
51 52 53 54 55 56 57 58 59 60 61 62
pub fn derive_transit_key(&self, appid: &AppID) -> Key<crate::transit::TransitKey> {
let transit_purpose = format!("{}/transit-key", &*appid);
let derived_key = self.derive_subkey_from_purpose(&transit_purpose);
trace!(
"Input key: {}, Transit key: {}, Transit purpose: '{}'",
self.to_hex(),
derived_key.to_hex(),
&transit_purpose
);
derived_key
}More examples
src/transit.rs (line 1449)
1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467
async fn handshake_exchange(
is_leader: bool,
tside: Arc<String>,
socket: TcpStream,
host_type: &TransitInfo,
cryptor: &dyn crypto::TransitCryptoInit,
key: Arc<Key<TransitKey>>,
) -> Result<HandshakeResult, crypto::TransitHandshakeError> {
/* Set proper read and write timeouts. This will temporarily set the socket into blocking mode :/ */
// https://github.com/async-rs/async-std/issues/499
let socket = std::net::TcpStream::try_from(socket)
.expect("Internal error: this should not fail because we never cloned the socket");
socket.set_write_timeout(Some(std::time::Duration::from_secs(120)))?;
socket.set_read_timeout(Some(std::time::Duration::from_secs(120)))?;
let mut socket: TcpStream = socket.into();
if host_type != &TransitInfo::Direct {
log::trace!("initiating relay handshake");
let sub_key = key.derive_subkey_from_purpose::<crate::GenericKey>("transit_relay_token");
socket
.write_all(format!("please relay {} for side {}\n", sub_key.to_hex(), tside).as_bytes())
.await?;
let mut rx = [0u8; 3];
socket.read_exact(&mut rx).await?;
let ok_msg: [u8; 3] = *b"ok\n";
ensure!(
ok_msg == rx,
crypto::TransitHandshakeError::RelayHandshakeFailed
);
}
let finalizer = if is_leader {
cryptor.handshake_leader(&mut socket).await?
} else {
cryptor.handshake_follower(&mut socket).await?
};
Ok((socket, finalizer))
}src/transit/crypto.rs (line 161)
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255
async fn handshake_leader(
&self,
socket: &mut TcpStream,
) -> Result<Box<dyn TransitCryptoInitFinalizer>, TransitHandshakeError> {
// 9. create record keys
let rkey = self
.key
.derive_subkey_from_purpose("transit_record_receiver_key");
let skey = self
.key
.derive_subkey_from_purpose("transit_record_sender_key");
// for transmit mode, send send_handshake_msg and compare.
// the received message with send_handshake_msg
socket
.write_all(
format!(
"transit sender {} ready\n\n",
self.key
.derive_subkey_from_purpose::<crate::GenericKey>("transit_sender")
.to_hex()
)
.as_bytes(),
)
.await?;
let expected_rx_handshake = format!(
"transit receiver {} ready\n\n",
self.key
.derive_subkey_from_purpose::<crate::GenericKey>("transit_receiver")
.to_hex()
);
assert_eq!(expected_rx_handshake.len(), 89);
read_expect(socket, expected_rx_handshake.as_bytes()).await?;
struct Finalizer {
skey: Key<TransitTxKey>,
rkey: Key<TransitRxKey>,
}
impl TransitCryptoInitFinalizer for Finalizer {
fn handshake_finalize(
self: Box<Self>,
socket: &mut TcpStream,
) -> BoxFuture<Result<DynTransitCrypto, TransitHandshakeError>> {
Box::pin(async move {
socket.write_all(b"go\n").await?;
Ok::<_, TransitHandshakeError>((
Box::new(SecretboxCryptoEncrypt {
skey: self.skey,
snonce: Default::default(),
}) as Box<dyn TransitCryptoEncrypt>,
Box::new(SecretboxCryptoDecrypt {
rkey: self.rkey,
rnonce: Default::default(),
}) as Box<dyn TransitCryptoDecrypt>,
))
})
}
}
Ok(Box::new(Finalizer { skey, rkey }))
}
async fn handshake_follower(
&self,
socket: &mut TcpStream,
) -> Result<Box<dyn TransitCryptoInitFinalizer>, TransitHandshakeError> {
// 9. create record keys
/* The order here is correct. The "sender" and "receiver" side are a misnomer and should be called
* "leader" and "follower" instead. As a follower, we use the leader key for receiving and our
* key for sending.
*/
let rkey = self
.key
.derive_subkey_from_purpose("transit_record_sender_key");
let skey = self
.key
.derive_subkey_from_purpose("transit_record_receiver_key");
// for receive mode, send receive_handshake_msg and compare.
// the received message with send_handshake_msg
socket
.write_all(
format!(
"transit receiver {} ready\n\n",
self.key
.derive_subkey_from_purpose::<crate::GenericKey>("transit_receiver")
.to_hex(),
)
.as_bytes(),
)
.await?;
let expected_tx_handshake = format!(
"transit sender {} ready\n\ngo\n",
self.key
.derive_subkey_from_purpose::<crate::GenericKey>("transit_sender")
.to_hex(),
);
assert_eq!(expected_tx_handshake.len(), 90);
read_expect(socket, expected_tx_handshake.as_bytes()).await?;
Ok(Box::new((
Box::new(SecretboxCryptoEncrypt {
skey,
snonce: Default::default(),
}) as Box<dyn TransitCryptoEncrypt>,
Box::new(SecretboxCryptoDecrypt {
rkey,
rnonce: Default::default(),
}) as Box<dyn TransitCryptoDecrypt>,
)) as Box<dyn TransitCryptoInitFinalizer>)
}sourcepub fn derive_subkey_from_purpose<NewP: KeyPurpose>(
&self,
purpose: &str
) -> Key<NewP>
pub fn derive_subkey_from_purpose<NewP: KeyPurpose>(
&self,
purpose: &str
) -> Key<NewP>
Derive a new sub-key from this one
Examples found in repository?
src/core/key.rs (line 54)
51 52 53 54 55 56 57 58 59 60 61 62
pub fn derive_transit_key(&self, appid: &AppID) -> Key<crate::transit::TransitKey> {
let transit_purpose = format!("{}/transit-key", &*appid);
let derived_key = self.derive_subkey_from_purpose(&transit_purpose);
trace!(
"Input key: {}, Transit key: {}, Transit purpose: '{}'",
self.to_hex(),
derived_key.to_hex(),
&transit_purpose
);
derived_key
}More examples
src/transit.rs (line 1447)
1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467
async fn handshake_exchange(
is_leader: bool,
tside: Arc<String>,
socket: TcpStream,
host_type: &TransitInfo,
cryptor: &dyn crypto::TransitCryptoInit,
key: Arc<Key<TransitKey>>,
) -> Result<HandshakeResult, crypto::TransitHandshakeError> {
/* Set proper read and write timeouts. This will temporarily set the socket into blocking mode :/ */
// https://github.com/async-rs/async-std/issues/499
let socket = std::net::TcpStream::try_from(socket)
.expect("Internal error: this should not fail because we never cloned the socket");
socket.set_write_timeout(Some(std::time::Duration::from_secs(120)))?;
socket.set_read_timeout(Some(std::time::Duration::from_secs(120)))?;
let mut socket: TcpStream = socket.into();
if host_type != &TransitInfo::Direct {
log::trace!("initiating relay handshake");
let sub_key = key.derive_subkey_from_purpose::<crate::GenericKey>("transit_relay_token");
socket
.write_all(format!("please relay {} for side {}\n", sub_key.to_hex(), tside).as_bytes())
.await?;
let mut rx = [0u8; 3];
socket.read_exact(&mut rx).await?;
let ok_msg: [u8; 3] = *b"ok\n";
ensure!(
ok_msg == rx,
crypto::TransitHandshakeError::RelayHandshakeFailed
);
}
let finalizer = if is_leader {
cryptor.handshake_leader(&mut socket).await?
} else {
cryptor.handshake_follower(&mut socket).await?
};
Ok((socket, finalizer))
}src/transit/crypto.rs (line 148)
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255
async fn handshake_leader(
&self,
socket: &mut TcpStream,
) -> Result<Box<dyn TransitCryptoInitFinalizer>, TransitHandshakeError> {
// 9. create record keys
let rkey = self
.key
.derive_subkey_from_purpose("transit_record_receiver_key");
let skey = self
.key
.derive_subkey_from_purpose("transit_record_sender_key");
// for transmit mode, send send_handshake_msg and compare.
// the received message with send_handshake_msg
socket
.write_all(
format!(
"transit sender {} ready\n\n",
self.key
.derive_subkey_from_purpose::<crate::GenericKey>("transit_sender")
.to_hex()
)
.as_bytes(),
)
.await?;
let expected_rx_handshake = format!(
"transit receiver {} ready\n\n",
self.key
.derive_subkey_from_purpose::<crate::GenericKey>("transit_receiver")
.to_hex()
);
assert_eq!(expected_rx_handshake.len(), 89);
read_expect(socket, expected_rx_handshake.as_bytes()).await?;
struct Finalizer {
skey: Key<TransitTxKey>,
rkey: Key<TransitRxKey>,
}
impl TransitCryptoInitFinalizer for Finalizer {
fn handshake_finalize(
self: Box<Self>,
socket: &mut TcpStream,
) -> BoxFuture<Result<DynTransitCrypto, TransitHandshakeError>> {
Box::pin(async move {
socket.write_all(b"go\n").await?;
Ok::<_, TransitHandshakeError>((
Box::new(SecretboxCryptoEncrypt {
skey: self.skey,
snonce: Default::default(),
}) as Box<dyn TransitCryptoEncrypt>,
Box::new(SecretboxCryptoDecrypt {
rkey: self.rkey,
rnonce: Default::default(),
}) as Box<dyn TransitCryptoDecrypt>,
))
})
}
}
Ok(Box::new(Finalizer { skey, rkey }))
}
async fn handshake_follower(
&self,
socket: &mut TcpStream,
) -> Result<Box<dyn TransitCryptoInitFinalizer>, TransitHandshakeError> {
// 9. create record keys
/* The order here is correct. The "sender" and "receiver" side are a misnomer and should be called
* "leader" and "follower" instead. As a follower, we use the leader key for receiving and our
* key for sending.
*/
let rkey = self
.key
.derive_subkey_from_purpose("transit_record_sender_key");
let skey = self
.key
.derive_subkey_from_purpose("transit_record_receiver_key");
// for receive mode, send receive_handshake_msg and compare.
// the received message with send_handshake_msg
socket
.write_all(
format!(
"transit receiver {} ready\n\n",
self.key
.derive_subkey_from_purpose::<crate::GenericKey>("transit_receiver")
.to_hex(),
)
.as_bytes(),
)
.await?;
let expected_tx_handshake = format!(
"transit sender {} ready\n\ngo\n",
self.key
.derive_subkey_from_purpose::<crate::GenericKey>("transit_sender")
.to_hex(),
);
assert_eq!(expected_tx_handshake.len(), 90);
read_expect(socket, expected_tx_handshake.as_bytes()).await?;
Ok(Box::new((
Box::new(SecretboxCryptoEncrypt {
skey,
snonce: Default::default(),
}) as Box<dyn TransitCryptoEncrypt>,
Box::new(SecretboxCryptoDecrypt {
rkey,
rnonce: Default::default(),
}) as Box<dyn TransitCryptoDecrypt>,
)) as Box<dyn TransitCryptoInitFinalizer>)
}