mirror of
https://github.com/jmcorgan/fips.git
synced 2026-08-11 09:07:44 +00:00
Add explicit counter to DataPacket for out-of-order decryption
Session-layer encryption used an implicit nonce counter with no counter on the wire, requiring packets to arrive in exact order. Under bulk transfer load (e.g., SCP), UDP packet loss or reordering permanently desynchronized sender/receiver counters, causing all subsequent decryption to fail with no recovery. Add an 8-byte counter field to the DataPacket wire format and switch from implicit-counter decrypt() to decrypt_with_replay_check() which uses the explicit wire counter plus a 2048-packet sliding replay window — the same pattern already used at the link layer. Wire format: msg_type(1) + flags(1) + counter(8) + payload_len(2) = 12 bytes (was 4). FIPS_OVERHEAD updated 127 → 135 bytes accordingly.
This commit is contained in:
committed by
Johnathan Corgan
parent
3ca2f9500a
commit
d3477a7c0f
@@ -293,10 +293,10 @@ impl Node {
|
||||
}
|
||||
};
|
||||
|
||||
let plaintext = match session.decrypt(&packet.payload) {
|
||||
let plaintext = match session.decrypt_with_replay_check(&packet.payload, packet.counter) {
|
||||
Ok(pt) => pt,
|
||||
Err(e) => {
|
||||
debug!(error = %e, src = %src_addr, "Session decryption failed");
|
||||
debug!(error = %e, src = %src_addr, counter = packet.counter, "Session decryption failed");
|
||||
self.sessions.insert(*src_addr, entry);
|
||||
return;
|
||||
}
|
||||
@@ -473,6 +473,9 @@ impl Node {
|
||||
}
|
||||
};
|
||||
|
||||
// Get counter before encrypting (encrypt will increment it)
|
||||
let counter = session.current_send_counter();
|
||||
|
||||
// Encrypt with session key
|
||||
let ciphertext = session.encrypt(plaintext).map_err(|e| NodeError::SendFailed {
|
||||
node_addr: *dest_addr,
|
||||
@@ -485,8 +488,8 @@ impl Node {
|
||||
entry.set_coords_warmup_remaining(entry.coords_warmup_remaining() - 1);
|
||||
}
|
||||
|
||||
// Build DataPacket, conditionally with coordinates
|
||||
let mut data_packet = DataPacket::new(ciphertext);
|
||||
// Build DataPacket with explicit counter for replay protection
|
||||
let mut data_packet = DataPacket::new(counter, ciphertext);
|
||||
if include_coords {
|
||||
let my_coords = self.tree_state.my_coords().clone();
|
||||
let dest_coords = self.get_dest_coords(dest_addr);
|
||||
|
||||
@@ -194,7 +194,7 @@ async fn test_coord_cache_warming_data_packet_with_coords() {
|
||||
let src_coords = TreeCoordinate::from_addrs(vec![src_addr, root_addr]).unwrap();
|
||||
let dest_coords = TreeCoordinate::from_addrs(vec![dest_addr, root_addr]).unwrap();
|
||||
|
||||
let data = DataPacket::new(vec![1, 2, 3, 4])
|
||||
let data = DataPacket::new(0, vec![1, 2, 3, 4])
|
||||
.with_coords(src_coords.clone(), dest_coords.clone());
|
||||
let data_payload = data.encode();
|
||||
|
||||
@@ -229,7 +229,7 @@ async fn test_coord_cache_warming_opaque_data_packet() {
|
||||
let dest_addr = make_node_addr(0x02);
|
||||
|
||||
// DataPacket without COORDS_PRESENT — no coords to cache
|
||||
let data = DataPacket::new(vec![1, 2, 3, 4]);
|
||||
let data = DataPacket::new(0, vec![1, 2, 3, 4]);
|
||||
let data_payload = data.encode();
|
||||
|
||||
let dg = SessionDatagram::new(src_addr, dest_addr, data_payload);
|
||||
|
||||
Reference in New Issue
Block a user