mirror of
https://gitlab.redox-os.org/CoffeeCode/redox-ssh.git
synced 2025-12-29 00:22:19 +01:00
Implement hmac-sha2-256
This commit is contained in:
parent
64e44de13a
commit
fe447bf443
11 changed files with 253 additions and 83 deletions
12
README.md
12
README.md
|
|
@ -6,17 +6,19 @@ A ssh client and server written entirely on rust, primarily targeted at [Redox O
|
||||||
|
|
||||||
Currently implemented features, ordered by priority:
|
Currently implemented features, ordered by priority:
|
||||||
|
|
||||||
- [ ] SSH Server
|
- [x] SSH Server
|
||||||
- [ ] SSH Client
|
- [ ] SSH Client
|
||||||
- [ ] Key Exchange algorithms
|
- Key Exchange algorithms
|
||||||
- [ ] `diffie-hellman-group-exchange-sha1`
|
- [ ] `diffie-hellman-group-exchange-sha1`
|
||||||
- [x] `curve25519-sha256`
|
- [x] `curve25519-sha256`
|
||||||
- [ ] Public Key algorithms
|
- Public Key algorithms
|
||||||
- [ ] `ssh-rsa`
|
- [ ] `ssh-rsa`
|
||||||
- [x] `ssh-ed25519`
|
- [x] `ssh-ed25519`
|
||||||
- [ ] Encryption algorithms
|
- Encryption algorithms
|
||||||
- [ ] `aes256-ctr`
|
- [x] `aes256-ctr`
|
||||||
- [ ] `aes256-gcm`
|
- [ ] `aes256-gcm`
|
||||||
|
- MAC algorithms
|
||||||
|
- [x] `hmac-sha2-256`
|
||||||
- [ ] Port forwarding
|
- [ ] Port forwarding
|
||||||
- [ ] SCP File Transfers
|
- [ ] SCP File Transfers
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ pub static ENCRYPTION: &[EncryptionAlgorithm] =
|
||||||
&[EncryptionAlgorithm::AES256_CTR];
|
&[EncryptionAlgorithm::AES256_CTR];
|
||||||
|
|
||||||
/// Slice of implemented MAC algorithms, ordered by preference
|
/// Slice of implemented MAC algorithms, ordered by preference
|
||||||
pub static MAC: &[MacAlgorithm] = &[MacAlgorithm::HMAC_SHA2_512];
|
pub static MAC: &[MacAlgorithm] = &[MacAlgorithm::HMAC_SHA2_256];
|
||||||
|
|
||||||
/// Slice of implemented compression algorithms, ordered by preference
|
/// Slice of implemented compression algorithms, ordered by preference
|
||||||
pub static COMPRESSION: &[CompressionAlgorithm] =
|
pub static COMPRESSION: &[CompressionAlgorithm] =
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ use std::sync::Arc;
|
||||||
use encryption::{AesCtr, Decryptor, Encryption};
|
use encryption::{AesCtr, Decryptor, Encryption};
|
||||||
use error::{ConnectionError, ConnectionResult};
|
use error::{ConnectionError, ConnectionResult};
|
||||||
use key_exchange::{self, KexResult, KeyExchange};
|
use key_exchange::{self, KexResult, KeyExchange};
|
||||||
|
use mac::{Hmac, MacAlgorithm};
|
||||||
use message::MessageType;
|
use message::MessageType;
|
||||||
use packet::{Packet, ReadPacketExt, WritePacketExt};
|
use packet::{Packet, ReadPacketExt, WritePacketExt};
|
||||||
use server::ServerConfig;
|
use server::ServerConfig;
|
||||||
|
|
@ -38,6 +39,8 @@ pub struct Connection {
|
||||||
stream: Box<Write>,
|
stream: Box<Write>,
|
||||||
session_id: Option<Vec<u8>>,
|
session_id: Option<Vec<u8>>,
|
||||||
encryption: Option<(Box<Encryption>, Box<Encryption>)>,
|
encryption: Option<(Box<Encryption>, Box<Encryption>)>,
|
||||||
|
mac: Option<(Box<MacAlgorithm>, Box<MacAlgorithm>)>,
|
||||||
|
seq: (u32, u32),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Connection {
|
impl<'a> Connection {
|
||||||
|
|
@ -50,6 +53,8 @@ impl<'a> Connection {
|
||||||
stream: Box::new(stream),
|
stream: Box::new(stream),
|
||||||
session_id: None,
|
session_id: None,
|
||||||
encryption: None,
|
encryption: None,
|
||||||
|
mac: None,
|
||||||
|
seq: (0, 0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -61,20 +66,58 @@ impl<'a> Connection {
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let packet = if let Some((ref mut c2s, _)) = self.encryption {
|
let packet = if let Some((ref mut c2s, _)) = self.encryption {
|
||||||
println!("decrypting!!!");
|
|
||||||
let mut decryptor = Decryptor::new(&mut **c2s, &mut reader);
|
let mut decryptor = Decryptor::new(&mut **c2s, &mut reader);
|
||||||
Packet::read_from(&mut decryptor)?
|
Packet::read_from(&mut decryptor)?
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Packet::read_from(&mut reader)?
|
Packet::read_from(&mut reader)?
|
||||||
};
|
};
|
||||||
trace!("Packet received: {:?}", packet);
|
|
||||||
|
if let Some((ref mut mac, _)) = self.mac {
|
||||||
|
let mut sig = vec![0; mac.size()];
|
||||||
|
reader.read_exact(&mut sig)?;
|
||||||
|
|
||||||
|
let mut sig_cmp = vec![0; mac.size()];
|
||||||
|
mac.sign(packet.data(), self.seq.0, sig_cmp.as_mut_slice());
|
||||||
|
|
||||||
|
if sig != sig_cmp {
|
||||||
|
return Err(ConnectionError::IntegrityError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
trace!("Packet {} received: {:?}", self.seq.0, packet);
|
||||||
self.process(packet)?;
|
self.process(packet)?;
|
||||||
|
|
||||||
|
self.seq.0 += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send(&mut self, packet: &Packet) -> io::Result<()> {
|
pub fn send(&mut self, packet: Packet) -> io::Result<()> {
|
||||||
packet.write_to(&mut self.stream)
|
trace!("Sending packet {}: {:?}", self.seq.1, packet);
|
||||||
|
|
||||||
|
let packet = packet.to_raw()?;
|
||||||
|
|
||||||
|
if let Some((_, ref mut s2c)) = self.encryption {
|
||||||
|
|
||||||
|
let mut encrypted = vec![0; packet.data().len()];
|
||||||
|
s2c.encrypt(packet.data(), encrypted.as_mut_slice());
|
||||||
|
|
||||||
|
// Sending encrypted packet
|
||||||
|
self.stream.write_all(encrypted.as_slice())?;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
packet.write_to(&mut self.stream)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.seq.1 += 1;
|
||||||
|
|
||||||
|
if let Some((_, ref mut mac)) = self.mac {
|
||||||
|
let mut sig = vec![0; mac.size()];
|
||||||
|
mac.sign(packet.data(), self.seq.1, sig.as_mut_slice());
|
||||||
|
self.stream.write_all(sig.as_slice())?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_id(&mut self) -> io::Result<()> {
|
fn send_id(&mut self) -> io::Result<()> {
|
||||||
|
|
@ -134,18 +177,18 @@ impl<'a> Connection {
|
||||||
match packet.msg_type()
|
match packet.msg_type()
|
||||||
{
|
{
|
||||||
MessageType::KexInit => {
|
MessageType::KexInit => {
|
||||||
println!("Starting Key Exchange!");
|
debug!("Starting key exchange");
|
||||||
self.kex_init(packet)
|
self.kex_init(packet)
|
||||||
}
|
}
|
||||||
MessageType::NewKeys => {
|
MessageType::NewKeys => {
|
||||||
println!("Switching to new Keys");
|
debug!("Switching to new keys");
|
||||||
|
|
||||||
let iv_c2s = self.generate_key(b"A", 256)?;
|
let iv_c2s = self.generate_key(b"A", 256)?;
|
||||||
let iv_s2c = self.generate_key(b"B", 256)?;
|
let iv_s2c = self.generate_key(b"B", 256)?;
|
||||||
let enc_c2s = self.generate_key(b"C", 256)?;
|
let enc_c2s = self.generate_key(b"C", 256)?;
|
||||||
let enc_s2c = self.generate_key(b"D", 256)?;
|
let enc_s2c = self.generate_key(b"D", 256)?;
|
||||||
let int_c2s = self.generate_key(b"E", 256)?;
|
let mac_c2s = self.generate_key(b"E", 256)?;
|
||||||
let int_s2c = self.generate_key(b"F", 256)?;
|
let mac_s2c = self.generate_key(b"F", 256)?;
|
||||||
|
|
||||||
self.encryption =
|
self.encryption =
|
||||||
Some((
|
Some((
|
||||||
|
|
@ -157,6 +200,29 @@ impl<'a> Connection {
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
|
|
||||||
|
self.mac = Some((
|
||||||
|
Box::new(Hmac::new(mac_c2s.as_slice())),
|
||||||
|
Box::new(Hmac::new(mac_s2c.as_slice())),
|
||||||
|
));
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
MessageType::ServiceRequest => {
|
||||||
|
let mut reader = packet.reader();
|
||||||
|
let name = reader.read_string()?;
|
||||||
|
|
||||||
|
trace!(
|
||||||
|
"{:?}",
|
||||||
|
::std::str::from_utf8(&name.as_slice()).unwrap()
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut res = Packet::new(MessageType::ServiceAccept);
|
||||||
|
res.with_writer(&|w| {
|
||||||
|
w.write_bytes(name.as_slice())?;
|
||||||
|
Ok(())
|
||||||
|
})?;
|
||||||
|
|
||||||
|
self.send(res)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
MessageType::KeyExchange(_) => {
|
MessageType::KeyExchange(_) => {
|
||||||
|
|
@ -168,7 +234,7 @@ impl<'a> Connection {
|
||||||
{
|
{
|
||||||
KexResult::Done(packet) => {
|
KexResult::Done(packet) => {
|
||||||
self.state = ConnectionState::Established;
|
self.state = ConnectionState::Established;
|
||||||
self.send(&packet)?;
|
self.send(packet)?;
|
||||||
|
|
||||||
if self.session_id.is_none() {
|
if self.session_id.is_none() {
|
||||||
self.session_id =
|
self.session_id =
|
||||||
|
|
@ -176,11 +242,11 @@ impl<'a> Connection {
|
||||||
}
|
}
|
||||||
|
|
||||||
let packet = Packet::new(MessageType::NewKeys);
|
let packet = Packet::new(MessageType::NewKeys);
|
||||||
self.send(&packet)?;
|
self.send(packet)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
KexResult::Ok(packet) => {
|
KexResult::Ok(packet) => {
|
||||||
self.send(&packet)?;
|
self.send(packet)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
KexResult::Error => Err(ConnectionError::KeyExchangeError),
|
KexResult::Error => Err(ConnectionError::KeyExchangeError),
|
||||||
|
|
@ -190,8 +256,8 @@ impl<'a> Connection {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
println!("Unhandled packet: {:?}", packet);
|
error!("Unhandled packet: {:?}", packet);
|
||||||
Err(ConnectionError::KeyExchangeError)
|
Err(ConnectionError::ProtocolError)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -220,11 +286,11 @@ impl<'a> Connection {
|
||||||
let mac_algo = negotiate(MAC, mac_algos_s2c.as_slice())?;
|
let mac_algo = negotiate(MAC, mac_algos_s2c.as_slice())?;
|
||||||
let comp_algo = negotiate(COMPRESSION, comp_algos_s2c.as_slice())?;
|
let comp_algo = negotiate(COMPRESSION, comp_algos_s2c.as_slice())?;
|
||||||
|
|
||||||
println!("Negotiated Kex Algorithm: {:?}", kex_algo);
|
debug!("Negotiated Kex Algorithm: {:?}", kex_algo);
|
||||||
println!("Negotiated Host Key Algorithm: {:?}", srv_host_key_algo);
|
debug!("Negotiated Host Key Algorithm: {:?}", srv_host_key_algo);
|
||||||
println!("Negotiated Encryption Algorithm: {:?}", enc_algo);
|
debug!("Negotiated Encryption Algorithm: {:?}", enc_algo);
|
||||||
println!("Negotiated Mac Algorithm: {:?}", mac_algo);
|
debug!("Negotiated Mac Algorithm: {:?}", mac_algo);
|
||||||
println!("Negotiated Comp Algorithm: {:?}", comp_algo);
|
debug!("Negotiated Comp Algorithm: {:?}", comp_algo);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save payload for hash generation
|
// Save payload for hash generation
|
||||||
|
|
|
||||||
|
|
@ -9,16 +9,18 @@ pub struct AesCtr {
|
||||||
|
|
||||||
impl AesCtr {
|
impl AesCtr {
|
||||||
pub fn new(key: &[u8], iv: &[u8]) -> AesCtr {
|
pub fn new(key: &[u8], iv: &[u8]) -> AesCtr {
|
||||||
AesCtr { cipher: ctr(KeySize::KeySize256, key, iv) }
|
AesCtr { cipher: ctr(KeySize::KeySize256, key, &iv[0..16]) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Encryption for AesCtr {
|
impl Encryption for AesCtr {
|
||||||
fn encrypt(&mut self, data: &[u8], buf: &mut [u8]) {
|
fn encrypt(&mut self, data: &[u8], buf: &mut [u8]) {
|
||||||
|
trace!("Encrypting {} -> {}", data.len(), buf.len());
|
||||||
self.cipher.process(data, buf);
|
self.cipher.process(data, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decrypt(&mut self, data: &[u8], buf: &mut [u8]) {
|
fn decrypt(&mut self, data: &[u8], buf: &mut [u8]) {
|
||||||
self.encrypt(data, buf);
|
trace!("Decrypting {} -> {}", data.len(), buf.len());
|
||||||
|
self.cipher.process(data, buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,8 +27,11 @@ impl<'a> Decryptor<'a> {
|
||||||
impl<'a> Read for Decryptor<'a> {
|
impl<'a> Read for Decryptor<'a> {
|
||||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||||
let mut tmp = vec![0; buf.len()];
|
let mut tmp = vec![0; buf.len()];
|
||||||
self.stream.read(tmp.as_mut_slice())?;
|
let count = self.stream.read(tmp.as_mut_slice())?;
|
||||||
self.encryption.decrypt(tmp.as_slice(), buf);
|
self.encryption.decrypt(
|
||||||
Ok(buf.len())
|
&tmp.as_slice()[0..count],
|
||||||
|
&mut buf[0..count],
|
||||||
|
);
|
||||||
|
Ok(count)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ pub enum ConnectionError {
|
||||||
NegotiationError,
|
NegotiationError,
|
||||||
KeyExchangeError,
|
KeyExchangeError,
|
||||||
KeyGenerationError,
|
KeyGenerationError,
|
||||||
|
IntegrityError,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for ConnectionError {
|
impl fmt::Display for ConnectionError {
|
||||||
|
|
@ -30,6 +31,7 @@ impl Error for ConnectionError {
|
||||||
&NegotiationError => "negotiation error",
|
&NegotiationError => "negotiation error",
|
||||||
&KeyExchangeError => "key exchange error",
|
&KeyExchangeError => "key exchange error",
|
||||||
&KeyGenerationError => "key generation error",
|
&KeyGenerationError => "key generation error",
|
||||||
|
&IntegrityError => "integrity error",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ const ECDH_KEX_INIT: u8 = 30;
|
||||||
const ECDH_KEX_REPLY: u8 = 31;
|
const ECDH_KEX_REPLY: u8 = 31;
|
||||||
|
|
||||||
pub struct Curve25519 {
|
pub struct Curve25519 {
|
||||||
shared_secret: Option<[u8; 32]>,
|
shared_secret: Option<Vec<u8>>,
|
||||||
exchange_hash: Option<Vec<u8>>,
|
exchange_hash: Option<Vec<u8>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -65,7 +65,6 @@ impl KeyExchange for Curve25519 {
|
||||||
key
|
key
|
||||||
};
|
};
|
||||||
|
|
||||||
println!("Received qc: {:?}", client_public);
|
|
||||||
let mut packet =
|
let mut packet =
|
||||||
Packet::new(MessageType::KeyExchange(ECDH_KEX_REPLY));
|
Packet::new(MessageType::KeyExchange(ECDH_KEX_REPLY));
|
||||||
|
|
||||||
|
|
@ -82,8 +81,14 @@ impl KeyExchange for Curve25519 {
|
||||||
};
|
};
|
||||||
|
|
||||||
let server_public = curve25519::curve25519_base(&server_secret);
|
let server_public = curve25519::curve25519_base(&server_secret);
|
||||||
let shared_secret =
|
let shared_secret = {
|
||||||
curve25519::curve25519(&server_secret, &client_public);
|
let mut buf = Vec::new();
|
||||||
|
buf.write_mpint(BigInt::from_bytes_be(
|
||||||
|
Sign::Plus,
|
||||||
|
&curve25519::curve25519(&server_secret, &client_public),
|
||||||
|
));
|
||||||
|
buf
|
||||||
|
};
|
||||||
|
|
||||||
let hash_data = {
|
let hash_data = {
|
||||||
let mut buf = Vec::new();
|
let mut buf = Vec::new();
|
||||||
|
|
@ -104,9 +109,7 @@ impl KeyExchange for Curve25519 {
|
||||||
buf.write_bytes(item);
|
buf.write_bytes(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
buf.write_mpint(
|
buf.write_raw_bytes(&shared_secret);
|
||||||
BigInt::from_bytes_be(Sign::Plus, &shared_secret),
|
|
||||||
);
|
|
||||||
|
|
||||||
buf
|
buf
|
||||||
};
|
};
|
||||||
|
|
@ -115,10 +118,6 @@ impl KeyExchange for Curve25519 {
|
||||||
let hash = self.hash(&[hash_data.as_slice()]);
|
let hash = self.hash(&[hash_data.as_slice()]);
|
||||||
let signature = config.as_ref().key.sign(&hash).unwrap();
|
let signature = config.as_ref().key.sign(&hash).unwrap();
|
||||||
|
|
||||||
println!("Hash: {:?}", hash);
|
|
||||||
println!("Public Key: {:?}", public_key);
|
|
||||||
println!("Signature: {:?}", signature);
|
|
||||||
|
|
||||||
packet
|
packet
|
||||||
.with_writer(&|w| {
|
.with_writer(&|w| {
|
||||||
w.write_bytes(public_key.as_slice())?;
|
w.write_bytes(public_key.as_slice())?;
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ mod message;
|
||||||
mod connection;
|
mod connection;
|
||||||
mod key_exchange;
|
mod key_exchange;
|
||||||
mod encryption;
|
mod encryption;
|
||||||
|
mod mac;
|
||||||
|
|
||||||
pub mod public_key;
|
pub mod public_key;
|
||||||
pub mod server;
|
pub mod server;
|
||||||
|
|
|
||||||
35
src/mac/hmac.rs
Normal file
35
src/mac/hmac.rs
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
use crypto::hmac::Hmac as rcHmac;
|
||||||
|
use crypto::mac::Mac;
|
||||||
|
use crypto::sha2::Sha256;
|
||||||
|
use mac::MacAlgorithm;
|
||||||
|
|
||||||
|
pub struct Hmac {
|
||||||
|
hmac: Box<rcHmac<Sha256>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Hmac {
|
||||||
|
pub fn new(key: &[u8]) -> Hmac {
|
||||||
|
let digest = Sha256::new();
|
||||||
|
Hmac { hmac: Box::new(rcHmac::new(digest, key)) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MacAlgorithm for Hmac {
|
||||||
|
fn size(&self) -> usize {
|
||||||
|
32
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sign(&mut self, data: &[u8], seq: u32, buf: &mut [u8]) {
|
||||||
|
let sequence = &[
|
||||||
|
((seq & 0xff000000) >> 24) as u8,
|
||||||
|
((seq & 0x00ff0000) >> 16) as u8,
|
||||||
|
((seq & 0x0000ff00) >> 8) as u8,
|
||||||
|
((seq & 0x000000ff)) as u8,
|
||||||
|
];
|
||||||
|
|
||||||
|
self.hmac.input(sequence);
|
||||||
|
self.hmac.input(data);
|
||||||
|
self.hmac.raw_result(buf);
|
||||||
|
self.hmac.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
8
src/mac/mod.rs
Normal file
8
src/mac/mod.rs
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
mod hmac;
|
||||||
|
|
||||||
|
pub use self::hmac::Hmac;
|
||||||
|
|
||||||
|
pub trait MacAlgorithm {
|
||||||
|
fn size(&self) -> usize;
|
||||||
|
fn sign(&mut self, data: &[u8], seq: u32, buf: &mut [u8]);
|
||||||
|
}
|
||||||
138
src/packet.rs
138
src/packet.rs
|
|
@ -8,85 +8,137 @@ use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
|
||||||
use message::MessageType;
|
use message::MessageType;
|
||||||
use num_bigint::BigInt;
|
use num_bigint::BigInt;
|
||||||
|
|
||||||
pub struct Packet {
|
pub enum Packet {
|
||||||
payload: Vec<u8>,
|
Raw(Vec<u8>, usize),
|
||||||
|
Payload(Vec<u8>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Packet {
|
impl Packet {
|
||||||
pub fn new(msg_type: MessageType) -> Packet {
|
pub fn new(msg_type: MessageType) -> Packet {
|
||||||
Packet { payload: (&[msg_type.into()]).to_vec() }
|
Packet::Payload([msg_type.into()].to_vec())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn msg_type(&self) -> MessageType {
|
pub fn msg_type(&self) -> MessageType {
|
||||||
self.payload[0].into()
|
match self
|
||||||
}
|
{
|
||||||
|
&Packet::Raw(ref data, _) => data[5],
|
||||||
pub fn payload(self) -> Vec<u8> {
|
&Packet::Payload(ref data) => data[0],
|
||||||
self.payload
|
}.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_from<R: io::Read>(stream: &mut R) -> Result<Packet> {
|
pub fn read_from<R: io::Read>(stream: &mut R) -> Result<Packet> {
|
||||||
let mac_len = 0;
|
let packet_len = stream.read_uint32()? as usize;
|
||||||
|
trace!("Reading incoming packet ({} bytes)", packet_len);
|
||||||
trace!("Waiting for incoming packet...");
|
|
||||||
let packet_len = stream.read_u32::<BigEndian>()? as usize;
|
|
||||||
trace!("Read incoming packet ({} bytes)", packet_len);
|
|
||||||
|
|
||||||
let padding_len = stream.read_u8()? as usize;
|
|
||||||
let payload_len = packet_len - padding_len - 1;
|
|
||||||
trace!("Padding: {} bytes", padding_len);
|
|
||||||
|
|
||||||
// TODO: Prevent packets that are too large
|
// TODO: Prevent packets that are too large
|
||||||
|
|
||||||
let mut payload = Vec::with_capacity(payload_len);
|
let mut raw = Vec::with_capacity(packet_len + 4);
|
||||||
let mut padding = Vec::with_capacity(padding_len);
|
raw.write_uint32(packet_len as u32)?;
|
||||||
// let mut mac = Vec::with_capacity(mac_len);
|
|
||||||
|
|
||||||
trace!("Reading packet...");
|
let count = stream.take(packet_len as u64).read_to_end(&mut raw)?;
|
||||||
stream.take(payload_len as u64).read_to_end(&mut payload)?;
|
|
||||||
trace!("Reading payload...");
|
|
||||||
stream.take(padding_len as u64).read_to_end(&mut padding)?;
|
|
||||||
|
|
||||||
// if mac_len > 0 {
|
if count == packet_len {
|
||||||
// stream.take(mac_len as u64).read_to_end(&mut mac);
|
let padding_len = raw[4] as usize;
|
||||||
// }
|
let payload_len = packet_len - padding_len - 1;
|
||||||
|
// TODO: Verify packet size (mod 8)
|
||||||
Ok(Packet { payload: payload })
|
Ok(Packet::Raw(raw, payload_len))
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Err(io::Error::new(io::ErrorKind::BrokenPipe, "broken stream"))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write_to<W: io::Write>(&self, stream: &mut W) -> Result<()> {
|
pub fn write_to<W: io::Write>(&self, stream: &mut W) -> Result<()> {
|
||||||
let padding_len = self.padding_len();
|
match self
|
||||||
let packet_len = self.payload.len() + padding_len + 1;
|
{
|
||||||
|
&Packet::Raw(ref data, _) => {
|
||||||
|
stream.write_all(data)?;
|
||||||
|
stream.flush()
|
||||||
|
}
|
||||||
|
&Packet::Payload(ref payload) => {
|
||||||
|
let padding_len = self.padding_len();
|
||||||
|
let packet_len = payload.len() + padding_len + 1;
|
||||||
|
|
||||||
stream.write_u32::<BigEndian>(packet_len as u32)?;
|
stream.write_u32::<BigEndian>(packet_len as u32)?;
|
||||||
stream.write_u8(padding_len as u8)?;
|
stream.write_u8(padding_len as u8)?;
|
||||||
stream.write(&self.payload)?;
|
stream.write_all(&payload)?;
|
||||||
stream.write(&[0u8; 255][..padding_len])?;
|
stream.write_all(&[0u8; 255][..padding_len])?;
|
||||||
stream.flush()?;
|
|
||||||
|
|
||||||
Ok(())
|
stream.flush()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn payload(self) -> Vec<u8> {
|
||||||
|
match self
|
||||||
|
{
|
||||||
|
Packet::Raw(data, payload_len) => data[5..payload_len + 5].to_vec(),
|
||||||
|
Packet::Payload(payload) => payload,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn data<'a>(&'a self) -> &'a [u8] {
|
||||||
|
match self
|
||||||
|
{
|
||||||
|
&Packet::Raw(ref data, _) => &data,
|
||||||
|
&Packet::Payload(ref payload) => &payload,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_raw(self) -> Result<Packet> {
|
||||||
|
match self
|
||||||
|
{
|
||||||
|
Packet::Raw(_, _) => Ok(self),
|
||||||
|
Packet::Payload(ref payload) => {
|
||||||
|
let mut buf = Vec::with_capacity(payload.len());
|
||||||
|
self.write_to(&mut buf)?;
|
||||||
|
Ok(Packet::Raw(buf, payload.len()))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn writer<'a>(&'a mut self) -> &'a mut Write {
|
pub fn writer<'a>(&'a mut self) -> &'a mut Write {
|
||||||
&mut self.payload
|
match self
|
||||||
|
{
|
||||||
|
&mut Packet::Raw(ref mut data, _) => data,
|
||||||
|
&mut Packet::Payload(ref mut payload) => payload,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_writer(&mut self, f: &Fn(&mut Write) -> Result<()>)
|
pub fn with_writer(&mut self, f: &Fn(&mut Write) -> Result<()>)
|
||||||
-> Result<()> {
|
-> Result<()> {
|
||||||
f(&mut self.payload)
|
f(self.writer())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reader<'a>(&'a self) -> BufReader<&'a [u8]> {
|
pub fn reader<'a>(&'a self) -> BufReader<&'a [u8]> {
|
||||||
BufReader::new(&self.payload.as_slice()[1..])
|
match self
|
||||||
|
{
|
||||||
|
&Packet::Raw(ref data, payload_len) => {
|
||||||
|
BufReader::new(&data.as_slice()[6..payload_len + 5])
|
||||||
|
}
|
||||||
|
&Packet::Payload(ref payload) => {
|
||||||
|
BufReader::new(&payload.as_slice()[1..])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn payload_len(&self) -> usize {
|
||||||
|
match self
|
||||||
|
{
|
||||||
|
&Packet::Raw(_, payload_len) => payload_len,
|
||||||
|
&Packet::Payload(ref payload) => payload.len(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn padding_len(&self) -> usize {
|
pub fn padding_len(&self) -> usize {
|
||||||
|
let align = 32;
|
||||||
|
|
||||||
// Calculate the padding to reach a multiple of 8 bytes
|
// Calculate the padding to reach a multiple of 8 bytes
|
||||||
let padding_len = 8 - ((self.payload.len() + 5) % 8);
|
let padding_len = align - ((self.payload_len() + 5) % align);
|
||||||
|
|
||||||
// The padding has to be at least 4 bytes long
|
// The padding has to be at least 4 bytes long
|
||||||
if padding_len < 4 {
|
if padding_len < 4 {
|
||||||
padding_len + 8
|
padding_len + align
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
padding_len
|
padding_len
|
||||||
|
|
@ -200,7 +252,7 @@ impl fmt::Debug for Packet {
|
||||||
f,
|
f,
|
||||||
"Packet({:?}, {} bytes)",
|
"Packet({:?}, {} bytes)",
|
||||||
self.msg_type(),
|
self.msg_type(),
|
||||||
self.payload.len()
|
self.payload_len()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue