use params::HandshakePattern;
use error::{SnowError, StateProblem};
use cipherstate::StatelessCipherStates;
use constants::{MAXDHLEN, MAXMSGLEN, TAGLEN};
use handshakestate::HandshakeState;
use utils::Toggle;
use std::fmt;
pub struct StatelessTransportState {
pub cipherstates: StatelessCipherStates,
pattern: HandshakePattern,
dh_len: usize,
rs: Toggle<[u8; MAXDHLEN]>,
initiator: bool,
}
impl StatelessTransportState {
pub fn new(handshake: HandshakeState) -> Result<Self, SnowError> {
if !handshake.is_finished() {
bail!(StateProblem::HandshakeNotFinished);
}
let dh_len = handshake.dh_len();
let HandshakeState {cipherstates, params, rs, initiator, ..} = handshake;
let pattern = params.handshake.pattern;
Ok(Self {
cipherstates: cipherstates.into(),
pattern,
dh_len,
rs,
initiator,
})
}
pub fn get_remote_static(&self) -> Option<&[u8]> {
self.rs.as_option_ref().map(|rs| &rs[..self.dh_len])
}
pub fn write_transport_message(&self,
nonce: u64,
payload: &[u8],
message: &mut [u8]) -> Result<usize, SnowError> {
if !self.initiator && self.pattern.is_oneway() {
bail!(StateProblem::OneWay);
} else if payload.len() + TAGLEN > MAXMSGLEN || payload.len() + TAGLEN > message.len() {
bail!(SnowError::Input);
}
let cipher = if self.initiator { &self.cipherstates.0 } else { &self.cipherstates.1 };
Ok(cipher.encrypt(nonce, payload, message))
}
pub fn read_transport_message(&self,
nonce: u64,
payload: &[u8],
message: &mut [u8]) -> Result<usize, SnowError> {
if self.initiator && self.pattern.is_oneway() {
bail!(SnowError::State { reason: StateProblem::OneWay });
}
let cipher = if self.initiator { &self.cipherstates.1 } else { &self.cipherstates.0 };
cipher.decrypt(nonce, payload, message).map_err(|_| SnowError::Decrypt)
}
pub fn rekey_outgoing(&mut self) {
if self.initiator {
self.cipherstates.rekey_initiator()
} else {
self.cipherstates.rekey_responder()
}
}
pub fn rekey_incoming(&mut self) {
if self.initiator {
self.cipherstates.rekey_responder()
} else {
self.cipherstates.rekey_initiator()
}
}
pub fn rekey_initiator_manually(&mut self, key: &[u8]) {
self.cipherstates.rekey_initiator_manually(key)
}
pub fn rekey_responder_manually(&mut self, key: &[u8]) {
self.cipherstates.rekey_responder_manually(key)
}
pub fn is_initiator(&self) -> bool {
self.initiator
}
}
impl fmt::Debug for StatelessTransportState {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("StatelessTransportState").finish()
}
}