send poly1305 hashes as well (message integrity)
This commit is contained in:
parent
4bef2ecc9c
commit
df5be01dfe
3 changed files with 68 additions and 28 deletions
75
src/lib.rs
75
src/lib.rs
|
|
@ -1,5 +1,7 @@
|
|||
use crate::EncryptionError::IO;
|
||||
use chacha::Block;
|
||||
use diffie_hellman::{Public, Secret};
|
||||
use poly1305::oneoff_authenticate;
|
||||
use rand::{RngCore, rng};
|
||||
use std::io::{Error, Read, Write};
|
||||
use std::net::{Shutdown, TcpStream};
|
||||
|
|
@ -20,6 +22,12 @@ pub struct EncryptedStream {
|
|||
const KEY_DERIVATION_CONTEXT: &str =
|
||||
concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION"));
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum EncryptionError {
|
||||
InvalidMAC,
|
||||
IO(Error),
|
||||
}
|
||||
|
||||
impl EncryptedStream {
|
||||
/// connect and negotiate an encrypted stream as a client
|
||||
pub fn connect(address: &str) -> Result<EncryptedStream, Error> {
|
||||
|
|
@ -37,25 +45,19 @@ impl EncryptedStream {
|
|||
|
||||
let shared_secret = secret.diffie_hellman(&their_public);
|
||||
|
||||
let mut nonce_bytes = [0u8; 12];
|
||||
socket.read_exact(&mut nonce_bytes)?;
|
||||
|
||||
let key =
|
||||
shared_secret.derive_key(|bytes| blake3::derive_key(KEY_DERIVATION_CONTEXT, &bytes));
|
||||
|
||||
Ok(EncryptedStream::wrap(socket, key, nonce_bytes))
|
||||
Ok(EncryptedStream::wrap(socket, key))
|
||||
}
|
||||
|
||||
pub fn wrap(socket: TcpStream, key: [u8; 32], nonce: [u8; 12]) -> EncryptedStream {
|
||||
let mut nonce_u32s = [0u32; 3];
|
||||
u8_to_u32(&mut nonce_u32s, &nonce);
|
||||
|
||||
pub fn wrap(socket: TcpStream, key: [u8; 32]) -> EncryptedStream {
|
||||
let mut key_u32s = [0u32; 8];
|
||||
u8_to_u32(&mut key_u32s, &key);
|
||||
|
||||
EncryptedStream {
|
||||
socket,
|
||||
block: Block::new(key_u32s, 0, nonce_u32s, 20),
|
||||
block: Block::new(key_u32s, 0, [0u32; 3], 20),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -67,10 +69,12 @@ impl EncryptedStream {
|
|||
self.block.reset(next_nonce)
|
||||
}
|
||||
|
||||
pub fn read_packet(&mut self) -> Result<Vec<u8>, Error> {
|
||||
pub fn read_packet(&mut self) -> Result<Vec<u8>, EncryptionError> {
|
||||
// the first bytes should be the nonce
|
||||
let mut nonce_bytes = [0u8; 12];
|
||||
self.socket.read(&mut nonce_bytes)?;
|
||||
if let Err(err) = self.socket.read(&mut nonce_bytes) {
|
||||
return Err(IO(err));
|
||||
}
|
||||
|
||||
let mut nonce = [0u32; 3];
|
||||
u8_to_u32(&mut nonce, &nonce_bytes);
|
||||
|
|
@ -80,13 +84,53 @@ impl EncryptedStream {
|
|||
let poly_key = self.block.get_bytes();
|
||||
self.block.advance();
|
||||
|
||||
let mut mac = [0u8; 16];
|
||||
if let Err(err) = self.socket.read(&mut mac) {
|
||||
return Err(IO(err));
|
||||
}
|
||||
|
||||
let mut len_bytes = [0u8; 4];
|
||||
self.read(&mut len_bytes)?;
|
||||
if let Err(err) = self.socket.read(&mut len_bytes) {
|
||||
return Err(IO(err));
|
||||
}
|
||||
|
||||
let len = u32::from_le_bytes(len_bytes);
|
||||
|
||||
let mut buf = vec![0u8; len as usize];
|
||||
if let Err(err) = self.read(&mut buf) {
|
||||
return Err(IO(err));
|
||||
}
|
||||
|
||||
let my_mac = oneoff_authenticate(&buf, &poly_key[0..32].try_into().unwrap());
|
||||
|
||||
if mac != my_mac {
|
||||
return Err(EncryptionError::InvalidMAC);
|
||||
}
|
||||
|
||||
Ok(buf)
|
||||
}
|
||||
|
||||
pub fn write_packet(&mut self, buf: &[u8]) -> Result<(), Error> {
|
||||
let mut nonce_bytes = [0u8; 12];
|
||||
rng().fill_bytes(&mut nonce_bytes);
|
||||
|
||||
let mut nonce = [0u32; 3];
|
||||
u8_to_u32(&mut nonce, &nonce_bytes);
|
||||
|
||||
self.block.reset(nonce);
|
||||
|
||||
let poly_key: [u8; 32] = self.block.get_bytes()[0..32].try_into().unwrap();
|
||||
self.block.advance();
|
||||
|
||||
let mac = oneoff_authenticate(&buf, &poly_key);
|
||||
|
||||
self.socket.write(&nonce_bytes)?;
|
||||
self.socket.write(&mac)?;
|
||||
self.socket.write(&(buf.len() as u32).to_le_bytes())?;
|
||||
|
||||
self.write(&buf)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -107,15 +151,10 @@ impl TryFrom<TcpStream> for EncryptedStream {
|
|||
|
||||
let shared_secret = secret.diffie_hellman(&their_public);
|
||||
|
||||
let mut nonce_bytes = [0u8; 12];
|
||||
rng().fill_bytes(&mut nonce_bytes);
|
||||
|
||||
socket.write(&nonce_bytes)?;
|
||||
|
||||
let key =
|
||||
shared_secret.derive_key(|bytes| blake3::derive_key(KEY_DERIVATION_CONTEXT, &bytes));
|
||||
|
||||
Ok(EncryptedStream::wrap(socket, key, nonce_bytes))
|
||||
Ok(EncryptedStream::wrap(socket, key))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
14
src/main.rs
14
src/main.rs
|
|
@ -1,6 +1,6 @@
|
|||
use hermes::EncryptedStream;
|
||||
use std::env::args;
|
||||
use std::io::{Read, Write};
|
||||
use std::io::Write;
|
||||
use std::net::{Shutdown, TcpListener};
|
||||
use std::process::exit;
|
||||
|
||||
|
|
@ -22,7 +22,9 @@ fn main() {
|
|||
println!("successfully encrypted stream");
|
||||
|
||||
encrypted
|
||||
.write(b"the fitness gram pacer test is a multi-stage aerobic fitness test...")
|
||||
.write_packet(
|
||||
b"the fitness gram pacer test is a multi-stage aerobic fitness test...",
|
||||
)
|
||||
.unwrap();
|
||||
println!("successfully wrote data");
|
||||
|
||||
|
|
@ -32,13 +34,11 @@ fn main() {
|
|||
}
|
||||
}
|
||||
"c" => {
|
||||
let mut client = EncryptedStream::connect("127.0.0.1:2007").unwrap();
|
||||
println!("successfully connected client");
|
||||
let mut client = EncryptedStream::connect("127.0.0.1:2007").expect("Failed to connect");
|
||||
|
||||
let mut buf = Vec::new();
|
||||
client.read_to_end(&mut buf).unwrap();
|
||||
println!("successfully read data");
|
||||
let buf = client.read_packet().unwrap();
|
||||
|
||||
println!("success!");
|
||||
println!("data: {}", String::from_utf8_lossy(&buf));
|
||||
}
|
||||
_ => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue