Skip to content

Commit ee785d9

Browse files
committed
Enhance README and refactor encryption handling. Update documentation to reflect automatic transport-level encryption via libp2p's Noise protocol, removing manual encryption options from the CLI. Refactor code to eliminate deprecated encryption parameters and streamline file transfer processes. Ensure all communications are securely encrypted by default.
1 parent 2212fbc commit ee785d9

File tree

10 files changed

+93
-206
lines changed

10 files changed

+93
-206
lines changed

README.md

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,26 @@
11
# CipherStream
22

3-
CipherStream is a secure P2P file transfer application built with Rust and libp2p. It allows users to send files directly to other peers on the network with optional end-to-end encryption.
3+
CipherStream is a secure P2P file transfer application built with Rust and libp2p. It allows users to send files directly to other peers on the network with **automatic transport-level encryption** via libp2p's Noise protocol.
44

55
## Features
66

77
- **Peer-to-Peer Architecture**: Direct file transfers between peers without any central server
8-
- **End-to-End Encryption**: Optional AES-256-GCM encryption for secure file transfers
8+
- **Automatic Transport Security**: Built-in encryption using libp2p's Noise protocol for all communications
99
- **Auto Discovery**: Local network peer discovery using mDNS
10-
- **Reliable Transfers**: Chunked file transfer with checksums
10+
- **Reliable Transfers**: Chunked file transfer with progress tracking
1111
- **Cross-Platform**: Works on macOS, Linux, and Windows
1212
- **Command-Line Interface**: Easy-to-use commands for sending and receiving files
1313

14+
## Security
15+
16+
CipherStream leverages **libp2p's Noise protocol** for automatic transport-level encryption. This means:
17+
18+
- All communications between peers are automatically encrypted
19+
- No need to manually enable encryption - it's always on
20+
- Uses industry-standard cryptographic protocols
21+
- Peer authentication and secure key exchange are handled automatically
22+
- Transport security is transparent to the user
23+
1424
## Installation
1525

1626
### Prerequisites
@@ -51,13 +61,14 @@ Options:
5161
To send a file to another peer:
5262

5363
```bash
54-
cipherstream send --peer <PEER_ID> --file <FILE_PATH> [--encrypt]
64+
cipherstream send --peer <PEER_ID> --file <FILE_PATH>
5565
```
5666

5767
Options:
5868
- `--peer <PEER_ID>`: The peer ID of the receiving node
5969
- `--file <FILE_PATH>`: Path to the file to send
60-
- `--encrypt`: Enable end-to-end encryption
70+
71+
**Note**: All file transfers are automatically encrypted via libp2p's transport security.
6172

6273
### Examples
6374

@@ -71,19 +82,14 @@ Options:
7182
cipherstream send --peer 12D3KooWB8rRTvkEnEpSvfGYEUkgpNtnEfwYzpnqCMgTRo7LghDz --file ~/Documents/report.pdf
7283
```
7384

74-
3. Send an encrypted file:
75-
```bash
76-
cipherstream send --peer 12D3KooWB8rRTvkEnEpSvfGYEUkgpNtnEfwYzpnqCMgTRo7LghDz --file ~/Documents/confidential.pdf --encrypt
77-
```
78-
7985
## Architecture
8086

8187
CipherStream is built on top of the libp2p networking stack and uses several components:
8288

83-
- **Network**: Handles connections, peer discovery and communication using libp2p
84-
- **Crypto**: Provides encryption, decryption, and file hashing functionality
89+
- **Network**: Handles connections, peer discovery and communication using libp2p with Noise protocol for security
8590
- **Protocol**: Defines the messages exchanged during file transfers
86-
- **File Transfer**: Manages the actual file transfer operations
91+
- **File Transfer**: Manages the actual file transfer operations with chunking and progress tracking
92+
- **Discovery**: Uses mDNS for local peer discovery and Kademlia DHT for broader network discovery
8793

8894
The application uses asynchronous Rust with Tokio runtime for handling concurrent operations.
8995

logs/cipherstream_node.2025-05-22

Whitespace-only changes.

src/crypto/mod.rs

Lines changed: 10 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use ring::{
2-
aead::{self, Aad, BoundKey, Nonce, NonceSequence, SealingKey, UnboundKey, AES_256_GCM},
2+
aead::{self, UnboundKey, AES_256_GCM},
33
rand::{SecureRandom, SystemRandom},
44
signature::{self, Ed25519KeyPair, KeyPair},
55
digest,
@@ -69,22 +69,20 @@ pub fn generate_key() -> Result<Vec<u8>, CryptoError> {
6969

7070
/// Encrypt data with AES-256-GCM
7171
pub fn encrypt(data: &[u8], key: &[u8]) -> Result<Vec<u8>, CryptoError> {
72-
// Create nonce and prepend it to the output
72+
// Generate a random nonce
7373
let mut nonce_bytes = [0u8; 12];
7474
let rng = SystemRandom::new();
7575
rng.fill(&mut nonce_bytes).map_err(|_| CryptoError::Encryption)?;
76-
77-
// Setup the encryption
76+
7877
let unbound_key = UnboundKey::new(&AES_256_GCM, key).map_err(|_| CryptoError::InvalidKey)?;
79-
let nonce_sequence = FixedNonce::new(nonce_bytes);
80-
let mut sealing_key = SealingKey::new(unbound_key, nonce_sequence);
81-
82-
// Encrypt the data
83-
let aad = Aad::empty();
78+
let aead_key = aead::LessSafeKey::new(unbound_key);
79+
let nonce = aead::Nonce::assume_unique_for_key(nonce_bytes);
80+
8481
let mut in_out = data.to_vec();
85-
sealing_key.seal_in_place_append_tag(aad, &mut in_out).map_err(|_| CryptoError::Encryption)?;
86-
87-
// Prepend the nonce
82+
aead_key.seal_in_place_append_tag(nonce, aead::Aad::empty(), &mut in_out)
83+
.map_err(|_| CryptoError::Encryption)?;
84+
85+
// Prepend nonce to encrypted data
8886
let mut result = nonce_bytes.to_vec();
8987
result.extend_from_slice(&in_out);
9088

@@ -149,23 +147,6 @@ pub fn verify_signature(message: &[u8], signature: &[u8], public_key: &[u8]) ->
149147
}
150148
}
151149

152-
// A fixed nonce for AES-GCM
153-
struct FixedNonce {
154-
nonce_bytes: [u8; 12],
155-
}
156-
157-
impl FixedNonce {
158-
fn new(nonce_bytes: [u8; 12]) -> Self {
159-
Self { nonce_bytes }
160-
}
161-
}
162-
163-
impl NonceSequence for FixedNonce {
164-
fn advance(&mut self) -> Result<Nonce, ring::error::Unspecified> {
165-
Ok(Nonce::assume_unique_for_key(self.nonce_bytes))
166-
}
167-
}
168-
169150
#[cfg(test)]
170151
mod tests {
171152
use super::*;

src/discovery/mod.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ pub enum SwarmCommand {
3232
SendFile {
3333
peer_id: PeerId,
3434
file_path: String,
35-
encrypt: bool,
3635
},
3736
}
3837

@@ -162,12 +161,11 @@ pub fn dial_peer(peer_id: PeerId) -> Result<(), Box<dyn std::error::Error>> {
162161
}
163162

164163
/// Send a file to a peer
165-
pub fn send_file(peer_id: PeerId, file_path: String, encrypt: bool) -> Result<(), Box<dyn std::error::Error>> {
164+
pub fn send_file(peer_id: PeerId, file_path: String) -> Result<(), Box<dyn std::error::Error>> {
166165
if let Some(tx) = get_swarm_channel() {
167166
let _ = tx.try_send(SwarmCommand::SendFile {
168167
peer_id,
169168
file_path,
170-
encrypt,
171169
});
172170
Ok(())
173171
} else {

src/file_transfer/types.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ pub enum ProtocolRequest {
3939
HandshakeRequest {
4040
filename: String,
4141
filesize: u64,
42-
encrypted: bool,
4342
transfer_id: String,
4443
},
4544
/// File data chunk request

src/main.rs

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,6 @@ enum Commands {
4444
/// Peer ID to send to
4545
#[arg(short, long)]
4646
peer: String,
47-
48-
/// Encrypt the file before sending
49-
#[arg(short, long)]
50-
encrypt: bool,
5147
},
5248
/// Connect to a specific peer
5349
Connect {
@@ -103,9 +99,9 @@ async fn main() -> Result<(), Box<dyn Error>> {
10399
info!("Starting node on port {}...", port);
104100
if let Err(e) = network::start_node(port, Some(data_dir)).await {
105101
error!("Node failed to start: {}", e);
106-
}
107102
}
108-
Commands::Send { file, peer, encrypt } => {
103+
}
104+
Commands::Send { file, peer } => {
109105
if !file.exists() {
110106
error!("File does not exist: {:?}", file);
111107
return Err("File not found".into());
@@ -119,24 +115,23 @@ async fn main() -> Result<(), Box<dyn Error>> {
119115
return Err("Invalid peer ID format".into());
120116
}
121117
};
122-
118+
123119
// We need to start a temporary node to send the file
124120
println!("Starting temporary node to send file...");
125121

126122
// First generate a peer ID for our temporary node
127123
let (local_peer_id, _local_key) = network::generate_peer_id();
128124
println!("Temporary node ID: {}", local_peer_id);
129-
125+
130126
// Start a swarm with a single purpose - to send this file
131127
let file_path = file.to_string_lossy().to_string();
132128

133129
println!("Initiating file transfer for {} to {}", file_path, peer_id);
134-
println!("Encryption: {}", if encrypt { "enabled" } else { "disabled" });
135130

136131
// Create a temp node and send the file
137132
// Use a temporary data directory for the sending node
138133
let temp_data_dir = format!(".cipherstream_temp_{}", std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_secs());
139-
network::start_temp_node_and_send_file(peer_id, file_path, encrypt, Some(temp_data_dir)).await?;
134+
network::start_temp_node_and_send_file(peer_id, file_path, false, Some(temp_data_dir)).await?;
140135

141136
println!("File transfer command completed. Check logs for status.");
142137
}
@@ -160,7 +155,7 @@ async fn main() -> Result<(), Box<dyn Error>> {
160155

161156
if peers.is_empty() {
162157
println!("No peers discovered yet. Start by running the Start command.");
163-
} else {
158+
} else {
164159
println!("Discovered peers:");
165160
for (peer_id, addrs) in peers {
166161
println!("Peer: {} at:", peer_id);

src/network/mod.rs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -317,9 +317,9 @@ async fn handle_req_resp_event(
317317
match message {
318318
request_handler::Message::Request { request, channel, .. } => {
319319
match request {
320-
ProtocolRequest::HandshakeRequest { filename, filesize, encrypted, transfer_id } => {
321-
info!("🤝 Received HandshakeRequest for '{}' ({} bytes, encrypted: {}, id: {})",
322-
filename, filesize, encrypted, transfer_id);
320+
ProtocolRequest::HandshakeRequest { filename, filesize, transfer_id } => {
321+
info!("🤝 Received HandshakeRequest for '{}' ({} bytes, id: {})",
322+
filename, filesize, transfer_id);
323323

324324
// Create download directory if it doesn't exist
325325
std::fs::create_dir_all(&download_dir)?;
@@ -398,7 +398,6 @@ async fn send_handshake_request(
398398
peer_id: &PeerId,
399399
filename: &str,
400400
file_path: &str,
401-
encrypt: bool,
402401
) -> Result<OutboundRequestId, AnyhowError> {
403402
info!("🤝 Initiating handshake for '{}' with {}", filename, peer_id);
404403

@@ -413,7 +412,6 @@ async fn send_handshake_request(
413412
let request = ProtocolRequest::HandshakeRequest {
414413
filename: filename.to_string(),
415414
filesize,
416-
encrypted: encrypt,
417415
transfer_id,
418416
};
419417

@@ -502,10 +500,11 @@ async fn cancel_transfer(
502500
}
503501

504502
// Update the start_temp_node_and_send_file function to use these new functions
503+
// Note: libp2p Noise protocol provides transport-level encryption automatically
505504
pub async fn start_temp_node_and_send_file(
506505
target_peer_id: PeerId,
507506
file_path_str: String,
508-
encrypt: bool,
507+
_encrypt: bool, // Deprecated: libp2p Noise provides encryption
509508
data_dir: Option<String>,
510509
) -> Result<(), AnyhowError> {
511510
let _start_time = Instant::now();
@@ -584,7 +583,7 @@ pub async fn start_temp_node_and_send_file(
584583

585584
if !handshake_sent {
586585
info!("🤝 Sending handshake request for file: {}", filename);
587-
match send_handshake_request(&mut swarm, &target_peer_id, &filename, &file_path_str, encrypt).await {
586+
match send_handshake_request(&mut swarm, &target_peer_id, &filename, &file_path_str).await {
588587
Ok(request_id) => {
589588
handshake_sent = true;
590589
handshake_request_id = Some(request_id);

0 commit comments

Comments
 (0)