DirSync::Resp work
Signed-off-by: Luca Fulchir <luca.fulchir@runesauth.com>
This commit is contained in:
parent
7a129dbe90
commit
a5f18ac533
|
@ -11,15 +11,16 @@
|
|||
use super::{Error, HandshakeData};
|
||||
use crate::{
|
||||
auth,
|
||||
connection::ID,
|
||||
connection::{ProtocolVersion, ID},
|
||||
enc::{
|
||||
asym::{ExchangePubKey, KeyExchange, KeyID},
|
||||
sym::{CipherKind, Secret},
|
||||
sym::{CipherKind, HeadLen, Secret, TagLen},
|
||||
},
|
||||
};
|
||||
|
||||
use ::arrayref::array_mut_ref;
|
||||
use ::std::{collections::VecDeque, num::NonZeroU64, vec::Vec};
|
||||
use trust_dns_client::rr::rdata::key::Protocol;
|
||||
|
||||
type Nonce = [u8; 16];
|
||||
|
||||
|
@ -42,10 +43,15 @@ impl DirSync {
|
|||
}
|
||||
/// Serialize into raw bytes
|
||||
/// NOTE: assumes that there is exactly asa much buffer as needed
|
||||
pub fn serialize(&self, out: &mut [u8]) {
|
||||
pub fn serialize(
|
||||
&self,
|
||||
head_len: HeadLen,
|
||||
tag_len: TagLen,
|
||||
out: &mut [u8],
|
||||
) {
|
||||
match self {
|
||||
DirSync::Req(req) => req.serialize(out),
|
||||
DirSync::Resp(resp) => resp.serialize(out),
|
||||
DirSync::Req(req) => req.serialize(head_len, tag_len, out),
|
||||
DirSync::Resp(resp) => resp.serialize(head_len, tag_len, out),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -67,9 +73,21 @@ pub struct Req {
|
|||
}
|
||||
|
||||
impl Req {
|
||||
/// Set the cleartext data after it was parsed
|
||||
pub fn set_data(&mut self, data: ReqData) {
|
||||
self.data = ReqInner::Data(data);
|
||||
/// return the offset of the encrypted data
|
||||
/// NOTE: starts from the beginning of the fenrir packet
|
||||
pub fn encrypted_offset(&self) -> usize {
|
||||
ProtocolVersion::len()
|
||||
+ KeyID::len()
|
||||
+ KeyExchange::len()
|
||||
+ CipherKind::len()
|
||||
+ self.exchange_key.len()
|
||||
}
|
||||
/// return the total length of the cleartext data
|
||||
pub fn encrypted_length(&self) -> usize {
|
||||
match &self.data {
|
||||
ReqInner::ClearText(data) => data.len(),
|
||||
_ => 0,
|
||||
}
|
||||
}
|
||||
/// actual length of the directory synchronized request
|
||||
pub fn len(&self) -> usize {
|
||||
|
@ -81,7 +99,12 @@ impl Req {
|
|||
}
|
||||
/// Serialize into raw bytes
|
||||
/// NOTE: assumes that there is exactly as much buffer as needed
|
||||
pub fn serialize(&self, out: &mut [u8]) {
|
||||
pub fn serialize(
|
||||
&self,
|
||||
head_len: HeadLen,
|
||||
tag_len: TagLen,
|
||||
out: &mut [u8],
|
||||
) {
|
||||
//assert!(out.len() > , ": not enough buffer to serialize");
|
||||
todo!()
|
||||
}
|
||||
|
@ -108,10 +131,7 @@ impl super::HandshakeParsing for Req {
|
|||
Ok(exchange_key) => exchange_key,
|
||||
Err(e) => return Err(e.into()),
|
||||
};
|
||||
let mut vec = VecDeque::with_capacity(raw.len() - (4 + len));
|
||||
vec.extend(raw[(4 + len)..].iter().copied());
|
||||
let _ = vec.make_contiguous();
|
||||
let data = ReqInner::CipherText(vec);
|
||||
let data = ReqInner::CipherText(raw.len() - (4 + len));
|
||||
Ok(HandshakeData::DirSync(DirSync::Req(Self {
|
||||
key_id,
|
||||
exchange,
|
||||
|
@ -125,40 +145,35 @@ impl super::HandshakeParsing for Req {
|
|||
/// Quick way to avoid mixing cipher and clear text
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum ReqInner {
|
||||
/// Client data, still in ciphertext
|
||||
CipherText(VecDeque<u8>),
|
||||
/// Client data, decrypted but unprocessed
|
||||
ClearText(VecDeque<u8>),
|
||||
/// Parsed client data
|
||||
Data(ReqData),
|
||||
/// Data is still encrytped, we only keep the length
|
||||
CipherText(usize),
|
||||
/// Client data, decrypted and parsed
|
||||
ClearText(ReqData),
|
||||
}
|
||||
impl ReqInner {
|
||||
/// The length of the data
|
||||
pub fn len(&self) -> usize {
|
||||
match self {
|
||||
ReqInner::CipherText(c) => c.len(),
|
||||
ReqInner::ClearText(c) => c.len(),
|
||||
ReqInner::Data(d) => d.len(),
|
||||
ReqInner::CipherText(len) => *len,
|
||||
ReqInner::ClearText(data) => data.len(),
|
||||
}
|
||||
}
|
||||
/// Get the ciptertext, or panic
|
||||
pub fn ciphertext<'a>(&'a mut self) -> &'a mut VecDeque<u8> {
|
||||
match self {
|
||||
ReqInner::CipherText(data) => data,
|
||||
_ => panic!(),
|
||||
/// parse the cleartext
|
||||
pub fn deserialize_as_cleartext(&mut self, raw: &[u8]) {
|
||||
let clear = match self {
|
||||
ReqInner::CipherText(len) => {
|
||||
assert!(
|
||||
*len == raw.len(),
|
||||
"DirSync::ReqInner::CipherText length mismatch"
|
||||
);
|
||||
match ReqData::deserialize(raw) {
|
||||
Ok(clear) => clear,
|
||||
Err(_) => return,
|
||||
}
|
||||
}
|
||||
/// switch from ciphertext to cleartext
|
||||
pub fn mark_as_cleartext(&mut self) {
|
||||
let mut newdata: VecDeque<u8>;
|
||||
match self {
|
||||
ReqInner::CipherText(data) => {
|
||||
newdata = VecDeque::new();
|
||||
::core::mem::swap(&mut newdata, data);
|
||||
}
|
||||
_ => return,
|
||||
}
|
||||
*self = ReqInner::ClearText(newdata);
|
||||
};
|
||||
*self = ReqInner::ClearText(clear);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -246,12 +261,7 @@ impl ReqData {
|
|||
pub const MIN_PKT_LEN: usize =
|
||||
16 + KeyID::len() + ID::len() + AuthInfo::MIN_PKT_LEN;
|
||||
/// Parse the cleartext raw data
|
||||
pub fn deserialize(raw: &ReqInner) -> Result<Self, Error> {
|
||||
let raw = match raw {
|
||||
// raw is VecDeque, assume everything is on the first slice
|
||||
ReqInner::ClearText(raw) => raw.as_slices().0,
|
||||
_ => return Err(Error::Parsing),
|
||||
};
|
||||
pub fn deserialize(raw: &[u8]) -> Result<Self, Error> {
|
||||
if raw.len() < Self::MIN_PKT_LEN {
|
||||
return Err(Error::NotEnoughData);
|
||||
}
|
||||
|
@ -285,21 +295,19 @@ impl ReqData {
|
|||
#[derive(Debug, Clone)]
|
||||
pub enum RespInner {
|
||||
/// Server data, still in ciphertext
|
||||
CipherText(VecDeque<u8>),
|
||||
/// Server data, decrypted but unprocessed
|
||||
ClearText(VecDeque<u8>),
|
||||
/// Parsed server data
|
||||
Data(RespData),
|
||||
CipherText(usize),
|
||||
/// Parsed, cleartext server data
|
||||
ClearText(RespData),
|
||||
}
|
||||
impl RespInner {
|
||||
/// The length of the data
|
||||
pub fn len(&self) -> usize {
|
||||
match self {
|
||||
RespInner::CipherText(c) => c.len(),
|
||||
RespInner::ClearText(c) => c.len(),
|
||||
RespInner::Data(d) => RespData::len(),
|
||||
RespInner::CipherText(len) => *len,
|
||||
RespInner::ClearText(d) => RespData::len(),
|
||||
}
|
||||
}
|
||||
/*
|
||||
/// Get the ciptertext, or panic
|
||||
pub fn ciphertext<'a>(&'a mut self) -> &'a mut VecDeque<u8> {
|
||||
match self {
|
||||
|
@ -307,6 +315,25 @@ impl RespInner {
|
|||
_ => panic!(),
|
||||
}
|
||||
}
|
||||
*/
|
||||
/// parse the cleartext
|
||||
pub fn deserialize_as_cleartext(&mut self, raw: &[u8]) {
|
||||
let clear = match self {
|
||||
RespInner::CipherText(len) => {
|
||||
assert!(
|
||||
*len == raw.len(),
|
||||
"DirSync::RespInner::CipherText length mismatch"
|
||||
);
|
||||
match RespData::deserialize(raw) {
|
||||
Ok(clear) => clear,
|
||||
Err(_) => return,
|
||||
}
|
||||
}
|
||||
_ => return,
|
||||
};
|
||||
*self = RespInner::ClearText(clear);
|
||||
}
|
||||
/*
|
||||
/// switch from ciphertext to cleartext
|
||||
pub fn mark_as_cleartext(&mut self) {
|
||||
let mut newdata: VecDeque<u8>;
|
||||
|
@ -319,6 +346,7 @@ impl RespInner {
|
|||
}
|
||||
*self = RespInner::ClearText(newdata);
|
||||
}
|
||||
*/
|
||||
/// serialize, but only if ciphertext
|
||||
pub fn serialize(&self, out: &mut [u8]) {
|
||||
todo!()
|
||||
|
@ -344,31 +372,48 @@ impl super::HandshakeParsing for Resp {
|
|||
KeyID(u16::from_le_bytes(raw[0..1].try_into().unwrap()));
|
||||
Ok(HandshakeData::DirSync(DirSync::Resp(Self {
|
||||
client_key_id,
|
||||
data: RespInner::CipherText(raw[KeyID::len()..].to_vec().into()),
|
||||
data: RespInner::CipherText(raw[KeyID::len()..].len()),
|
||||
})))
|
||||
}
|
||||
}
|
||||
|
||||
impl Resp {
|
||||
/// return the offset of the encrypted data
|
||||
/// NOTE: starts from the beginning of the fenrir packet
|
||||
pub fn encrypted_offset(&self) -> usize {
|
||||
ProtocolVersion::len() + KeyID::len()
|
||||
}
|
||||
/// return the total length of the cleartext data
|
||||
pub fn encrypted_length(&self) -> usize {
|
||||
match &self.data {
|
||||
RespInner::ClearText(_data) => RespData::len(),
|
||||
_ => 0,
|
||||
}
|
||||
}
|
||||
/// Total length of the response handshake
|
||||
pub fn len(&self) -> usize {
|
||||
KeyID::len() + self.data.len()
|
||||
}
|
||||
/// Serialize into raw bytes
|
||||
/// NOTE: assumes that there is exactly as much buffer as needed
|
||||
/// NOTE: assumes that the data is encrypted
|
||||
pub fn serialize(&self, out: &mut [u8]) {
|
||||
/// NOTE: assumes that the data is *ClearText*
|
||||
pub fn serialize(
|
||||
&self,
|
||||
head_len: HeadLen,
|
||||
tag_len: TagLen,
|
||||
out: &mut [u8],
|
||||
) {
|
||||
assert!(
|
||||
out.len() == KeyID::len() + self.data.len(),
|
||||
"DirSync Resp: not enough buffer to serialize"
|
||||
);
|
||||
self.client_key_id.serialize(array_mut_ref![out, 0, 2]);
|
||||
let end_data = 2 + self.data.len();
|
||||
self.data.serialize(&mut out[2..end_data]);
|
||||
let end_data = (2 + self.data.len()) - tag_len.0;
|
||||
self.data.serialize(&mut out[(2 + head_len.0)..end_data]);
|
||||
}
|
||||
/// Set the cleartext data after it was parsed
|
||||
pub fn set_data(&mut self, data: RespData) {
|
||||
self.data = RespInner::Data(data);
|
||||
self.data = RespInner::ClearText(data);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -409,7 +454,7 @@ impl RespData {
|
|||
out[start..end].copy_from_slice(self.service_key.as_ref());
|
||||
}
|
||||
/// Parse the cleartext raw data
|
||||
pub fn deserialize(raw: &RespInner) -> Result<Self, Error> {
|
||||
pub fn deserialize(raw: &[u8]) -> Result<Self, Error> {
|
||||
todo!();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,10 @@ pub mod dirsync;
|
|||
|
||||
use ::num_traits::FromPrimitive;
|
||||
|
||||
use crate::connection::{self, ProtocolVersion};
|
||||
use crate::{
|
||||
connection::{self, ProtocolVersion},
|
||||
enc::sym::{HeadLen, TagLen},
|
||||
};
|
||||
|
||||
/// Handshake errors
|
||||
#[derive(::thiserror::Error, Debug, Copy, Clone)]
|
||||
|
@ -53,9 +56,14 @@ impl HandshakeData {
|
|||
}
|
||||
/// Serialize into raw bytes
|
||||
/// NOTE: assumes that there is exactly asa much buffer as needed
|
||||
pub fn serialize(&self, out: &mut [u8]) {
|
||||
pub fn serialize(
|
||||
&self,
|
||||
head_len: HeadLen,
|
||||
tag_len: TagLen,
|
||||
out: &mut [u8],
|
||||
) {
|
||||
match self {
|
||||
HandshakeData::DirSync(d) => d.serialize(out),
|
||||
HandshakeData::DirSync(d) => d.serialize(head_len, tag_len, out),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -126,10 +134,15 @@ impl Handshake {
|
|||
}
|
||||
/// serialize the handshake into bytes
|
||||
/// NOTE: assumes that there is exactly as much buffer as needed
|
||||
pub fn serialize(&self, out: &mut [u8]) {
|
||||
pub fn serialize(
|
||||
&self,
|
||||
head_len: HeadLen,
|
||||
tag_len: TagLen,
|
||||
out: &mut [u8],
|
||||
) {
|
||||
assert!(out.len() > 1, "Handshake: not enough buffer to serialize");
|
||||
self.fenrir_version.serialize(&mut out[0]);
|
||||
self.data.serialize(&mut out[1..]);
|
||||
self.data.serialize(head_len, tag_len, &mut out[1..]);
|
||||
}
|
||||
|
||||
pub(crate) fn work(&self, keys: &[HandshakeServer]) -> Result<(), Error> {
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
//
|
||||
//! Raw packet handling, encryption, decryption, parsing
|
||||
|
||||
use crate::enc::sym::{HeadLen, TagLen};
|
||||
|
||||
/// Fenrir Connection id
|
||||
/// 0 is special as it represents the handshake
|
||||
/// Connection IDs are to be considered u64 little endian
|
||||
|
@ -100,10 +102,15 @@ impl PacketData {
|
|||
}
|
||||
/// serialize data into bytes
|
||||
/// NOTE: assumes that there is exactly asa much buffer as needed
|
||||
pub fn serialize(&self, out: &mut [u8]) {
|
||||
pub fn serialize(
|
||||
&self,
|
||||
head_len: HeadLen,
|
||||
tag_len: TagLen,
|
||||
out: &mut [u8],
|
||||
) {
|
||||
assert!(self.len() == out.len(), "PacketData: wrong buffer length");
|
||||
match self {
|
||||
PacketData::Handshake(h) => h.serialize(out),
|
||||
PacketData::Handshake(h) => h.serialize(head_len, tag_len, out),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -124,12 +131,18 @@ impl Packet {
|
|||
}
|
||||
/// serialize packet into buffer
|
||||
/// NOTE: assumes that there is exactly asa much buffer as needed
|
||||
pub fn serialize(&self, out: &mut [u8]) {
|
||||
pub fn serialize(
|
||||
&self,
|
||||
head_len: HeadLen,
|
||||
tag_len: TagLen,
|
||||
out: &mut [u8],
|
||||
) {
|
||||
assert!(
|
||||
out.len() > ConnectionID::len(),
|
||||
"Packet: not enough buffer to serialize"
|
||||
);
|
||||
self.id.serialize(&mut out[0..ConnectionID::len()]);
|
||||
self.data.serialize(&mut out[ConnectionID::len()..]);
|
||||
self.data
|
||||
.serialize(head_len, tag_len, &mut out[ConnectionID::len()..]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,9 +59,9 @@ impl CipherKind {
|
|||
1
|
||||
}
|
||||
/// required length of the nonce
|
||||
pub fn nonce_len(&self) -> usize {
|
||||
pub fn nonce_len(&self) -> HeadLen {
|
||||
// TODO: how the hell do I take this from ::chacha20poly1305?
|
||||
Nonce::len()
|
||||
HeadLen(Nonce::len())
|
||||
}
|
||||
/// required length of the key
|
||||
pub fn key_len(&self) -> usize {
|
||||
|
@ -69,9 +69,9 @@ impl CipherKind {
|
|||
XChaCha20Poly1305::key_size()
|
||||
}
|
||||
/// Length of the authentication tag
|
||||
pub fn tag_len(&self) -> usize {
|
||||
pub fn tag_len(&self) -> TagLen {
|
||||
// TODO: how the hell do I take this from ::chacha20poly1305?
|
||||
::ring::aead::CHACHA20_POLY1305.tag_len()
|
||||
TagLen(::ring::aead::CHACHA20_POLY1305.tag_len())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -90,6 +90,16 @@ pub enum CipherDirection {
|
|||
Send,
|
||||
}
|
||||
|
||||
/// strong typedef for header length
|
||||
/// aka: nonce length in the encrypted data)
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct HeadLen(pub usize);
|
||||
/// strong typedef for the Tag length
|
||||
/// aka: cryptographic authentication tag length at the end
|
||||
/// of the encrypted data
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct TagLen(pub usize);
|
||||
|
||||
/// actual ciphers
|
||||
enum Cipher {
|
||||
/// Cipher XChaha20_Poly1305
|
||||
|
@ -105,31 +115,33 @@ impl Cipher {
|
|||
}
|
||||
}
|
||||
}
|
||||
fn nonce_len(&self) -> usize {
|
||||
fn nonce_len(&self) -> HeadLen {
|
||||
match self {
|
||||
Cipher::XChaCha20Poly1305(_) => {
|
||||
// TODO: how the hell do I take this from ::chacha20poly1305?
|
||||
::ring::aead::CHACHA20_POLY1305.nonce_len()
|
||||
HeadLen(::ring::aead::CHACHA20_POLY1305.nonce_len())
|
||||
}
|
||||
}
|
||||
}
|
||||
fn tag_len(&self) -> usize {
|
||||
fn tag_len(&self) -> TagLen {
|
||||
match self {
|
||||
Cipher::XChaCha20Poly1305(_) => {
|
||||
// TODO: how the hell do I take this from ::chacha20poly1305?
|
||||
::ring::aead::CHACHA20_POLY1305.tag_len()
|
||||
TagLen(::ring::aead::CHACHA20_POLY1305.tag_len())
|
||||
}
|
||||
}
|
||||
}
|
||||
fn decrypt(&self, aad: AAD, data: &mut VecDeque<u8>) -> Result<(), Error> {
|
||||
fn decrypt<'a>(
|
||||
&self,
|
||||
aad: AAD,
|
||||
raw_data: &'a mut [u8],
|
||||
) -> Result<&'a [u8], Error> {
|
||||
match self {
|
||||
Cipher::XChaCha20Poly1305(cipher) => {
|
||||
use ::chacha20poly1305::{
|
||||
aead::generic_array::GenericArray, AeadInPlace,
|
||||
};
|
||||
let final_len: usize;
|
||||
{
|
||||
let raw_data = data.as_mut_slices().0;
|
||||
let final_len: usize = {
|
||||
// FIXME: check min data length
|
||||
let (nonce_bytes, data_and_tag) = raw_data.split_at_mut(13);
|
||||
let (data_notag, tag_bytes) = data_and_tag.split_at_mut(
|
||||
|
@ -147,11 +159,11 @@ impl Cipher {
|
|||
if maybe.is_err() {
|
||||
return Err(Error::Decrypt);
|
||||
}
|
||||
final_len = data_notag.len();
|
||||
}
|
||||
data.drain(..Nonce::len());
|
||||
data.truncate(final_len);
|
||||
Ok(())
|
||||
data_notag.len()
|
||||
};
|
||||
//data.drain(..Nonce::len());
|
||||
//data.truncate(final_len);
|
||||
Ok(&raw_data[Nonce::len()..Nonce::len() + final_len])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -159,7 +171,7 @@ impl Cipher {
|
|||
match self {
|
||||
Cipher::XChaCha20Poly1305(cipher) => {
|
||||
let cipher = CipherKind::XChaCha20Poly1305;
|
||||
cipher.nonce_len() + cipher.tag_len()
|
||||
cipher.nonce_len().0 + cipher.tag_len().0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -167,28 +179,30 @@ impl Cipher {
|
|||
&self,
|
||||
nonce: &Nonce,
|
||||
aad: AAD,
|
||||
data: &mut Data,
|
||||
data: &mut [u8],
|
||||
) -> Result<(), Error> {
|
||||
// No need to check for minimum buffer size since `Data` assures we
|
||||
// already went through that
|
||||
// FIXME: check minimum buffer size
|
||||
match self {
|
||||
Cipher::XChaCha20Poly1305(cipher) => {
|
||||
use ::chacha20poly1305::{
|
||||
aead::generic_array::GenericArray, AeadInPlace,
|
||||
};
|
||||
let tag_len: usize = ::ring::aead::CHACHA20_POLY1305.tag_len();
|
||||
let data_len_notag = data.len() - tag_len;
|
||||
// write nonce
|
||||
data.get_slice_full()[..Nonce::len()]
|
||||
.copy_from_slice(nonce.as_bytes());
|
||||
data[..Nonce::len()].copy_from_slice(nonce.as_bytes());
|
||||
|
||||
// encrypt data
|
||||
match cipher.cipher.encrypt_in_place_detached(
|
||||
nonce.as_bytes().into(),
|
||||
aad.0,
|
||||
data.get_slice(),
|
||||
&mut data[Nonce::len()..data_len_notag],
|
||||
) {
|
||||
Ok(tag) => {
|
||||
data[data_len_notag..]
|
||||
// add tag
|
||||
data.get_tag_slice().copy_from_slice(tag.as_slice());
|
||||
//data.get_tag_slice()
|
||||
.copy_from_slice(tag.as_slice());
|
||||
Ok(())
|
||||
}
|
||||
Err(_) => Err(Error::Encrypt),
|
||||
|
@ -216,7 +230,7 @@ impl CipherRecv {
|
|||
Self(Cipher::new(kind, secret))
|
||||
}
|
||||
/// Get the length of the nonce for this cipher
|
||||
pub fn nonce_len(&self) -> usize {
|
||||
pub fn nonce_len(&self) -> HeadLen {
|
||||
self.0.nonce_len()
|
||||
}
|
||||
/// Decrypt a paket. Nonce and Tag are taken from the packet,
|
||||
|
@ -224,8 +238,8 @@ impl CipherRecv {
|
|||
pub fn decrypt<'a>(
|
||||
&self,
|
||||
aad: AAD,
|
||||
data: &mut VecDeque<u8>,
|
||||
) -> Result<(), Error> {
|
||||
data: &'a mut [u8],
|
||||
) -> Result<&'a [u8], Error> {
|
||||
self.0.decrypt(aad, data)
|
||||
}
|
||||
}
|
||||
|
@ -289,12 +303,12 @@ impl CipherSend {
|
|||
pub fn make_data(&self, length: usize) -> Data {
|
||||
Data {
|
||||
data: Vec::with_capacity(length + self.cipher.overhead()),
|
||||
skip_start: self.cipher.nonce_len(),
|
||||
skip_end: self.cipher.tag_len(),
|
||||
skip_start: self.cipher.nonce_len().0,
|
||||
skip_end: self.cipher.tag_len().0,
|
||||
}
|
||||
}
|
||||
/// Encrypt the given data
|
||||
pub fn encrypt(&self, aad: AAD, data: &mut Data) -> Result<(), Error> {
|
||||
pub fn encrypt(&self, aad: AAD, data: &mut [u8]) -> Result<(), Error> {
|
||||
let old_nonce = self.nonce.advance();
|
||||
self.cipher.encrypt(&old_nonce, aad, data)?;
|
||||
Ok(())
|
||||
|
|
102
src/lib.rs
102
src/lib.rs
|
@ -28,7 +28,7 @@ use ::tokio::{
|
|||
use crate::enc::{
|
||||
asym,
|
||||
hkdf::HkdfSha3,
|
||||
sym::{CipherKind, CipherRecv, CipherSend},
|
||||
sym::{CipherKind, CipherRecv, CipherSend, HeadLen, TagLen},
|
||||
};
|
||||
pub use config::Config;
|
||||
use connection::{
|
||||
|
@ -67,13 +67,26 @@ pub struct AuthNeededInfo {
|
|||
pub cipher: CipherKind,
|
||||
}
|
||||
|
||||
/// Client information needed to fully establish the conenction
|
||||
#[derive(Debug)]
|
||||
pub struct ClientConnectInfo {
|
||||
/// Parsed handshake
|
||||
pub handshake: Handshake,
|
||||
/// hkdf generated from the handshake
|
||||
pub hkdf: HkdfSha3,
|
||||
/// cipher to be used in both directions
|
||||
pub cipher_recv: CipherRecv,
|
||||
}
|
||||
|
||||
/// Intermediate actions to be taken while parsing the handshake
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug)]
|
||||
pub enum HandshakeAction {
|
||||
/// Parsing finished, all ok, nothing to do
|
||||
None,
|
||||
/// Packet parsed, now go perform authentication
|
||||
AuthNeeded(AuthNeededInfo),
|
||||
/// the client can fully establish a connection with this info
|
||||
ClientConnect(ClientConnectInfo),
|
||||
}
|
||||
// No async here
|
||||
struct FenrirInner {
|
||||
|
@ -95,6 +108,7 @@ impl FenrirInner {
|
|||
fn recv_handshake(
|
||||
&self,
|
||||
mut handshake: Handshake,
|
||||
handshake_raw: &mut [u8],
|
||||
) -> Result<HandshakeAction, Error> {
|
||||
use connection::handshake::{
|
||||
dirsync::{self, DirSync},
|
||||
|
@ -159,13 +173,17 @@ impl FenrirInner {
|
|||
let cipher_recv = CipherRecv::new(req.cipher, secret_recv);
|
||||
use crate::enc::sym::AAD;
|
||||
let aad = AAD(&mut []); // no aad for now
|
||||
match cipher_recv.decrypt(aad, &mut req.data.ciphertext()) {
|
||||
Ok(()) => req.data.mark_as_cleartext(),
|
||||
match cipher_recv.decrypt(
|
||||
aad,
|
||||
&mut handshake_raw[req.encrypted_offset()..],
|
||||
) {
|
||||
Ok(cleartext) => {
|
||||
req.data.deserialize_as_cleartext(cleartext)
|
||||
}
|
||||
Err(e) => {
|
||||
return Err(handshake::Error::Key(e).into());
|
||||
}
|
||||
}
|
||||
req.set_data(dirsync::ReqData::deserialize(&req.data)?);
|
||||
|
||||
let cipher = req.cipher;
|
||||
|
||||
|
@ -200,17 +218,26 @@ impl FenrirInner {
|
|||
let cipher_recv =
|
||||
CipherRecv::new(hshake.cipher, secret_recv);
|
||||
use crate::enc::sym::AAD;
|
||||
let aad = AAD(&mut []); // no aad for now
|
||||
match cipher_recv.decrypt(aad, &mut resp.data.ciphertext())
|
||||
{
|
||||
Ok(()) => resp.data.mark_as_cleartext(),
|
||||
// no aad for now
|
||||
let aad = AAD(&mut []);
|
||||
let mut raw_data = &mut handshake_raw[resp
|
||||
.encrypted_offset()
|
||||
..(resp.encrypted_offset() + resp.encrypted_length())];
|
||||
match cipher_recv.decrypt(aad, &mut raw_data) {
|
||||
Ok(cleartext) => {
|
||||
resp.data.deserialize_as_cleartext(&cleartext)
|
||||
}
|
||||
Err(e) => {
|
||||
return Err(handshake::Error::Key(e).into());
|
||||
}
|
||||
}
|
||||
resp.set_data(dirsync::RespData::deserialize(&resp.data)?);
|
||||
|
||||
todo!();
|
||||
return Ok(HandshakeAction::ClientConnect(
|
||||
ClientConnectInfo {
|
||||
handshake,
|
||||
hkdf: hshake.hkdf,
|
||||
cipher_recv,
|
||||
},
|
||||
));
|
||||
}
|
||||
},
|
||||
}
|
||||
|
@ -615,7 +642,7 @@ impl Fenrir {
|
|||
|
||||
const MIN_PACKET_BYTES: usize = 8;
|
||||
/// Read and do stuff with the raw udp packet
|
||||
async fn recv(&self, udp: RawUdp) {
|
||||
async fn recv(&self, mut udp: RawUdp) {
|
||||
if udp.data.len() < Self::MIN_PACKET_BYTES {
|
||||
return;
|
||||
}
|
||||
|
@ -630,7 +657,9 @@ impl Fenrir {
|
|||
return;
|
||||
}
|
||||
};
|
||||
let action = match self._inner.recv_handshake(handshake) {
|
||||
let action =
|
||||
match self._inner.recv_handshake(handshake, &mut udp.data[8..])
|
||||
{
|
||||
Ok(action) => action,
|
||||
Err(err) => {
|
||||
::tracing::debug!("Handshake recv error {}", err);
|
||||
|
@ -657,10 +686,10 @@ impl Fenrir {
|
|||
DirSync::Req(req) => {
|
||||
use dirsync::ReqInner;
|
||||
let req_data = match req.data {
|
||||
ReqInner::Data(req_data) => req_data,
|
||||
ReqInner::ClearText(req_data) => req_data,
|
||||
_ => {
|
||||
::tracing::error!(
|
||||
"token_check: expected Data"
|
||||
"token_check: expected ClearText"
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
@ -697,6 +726,8 @@ impl Fenrir {
|
|||
connection::ID::new_rand(&self.rand);
|
||||
let srv_secret =
|
||||
enc::sym::Secret::new_rand(&self.rand);
|
||||
let head_len = req.cipher.nonce_len();
|
||||
let tag_len = req.cipher.tag_len();
|
||||
|
||||
let raw_conn = Connection::new(
|
||||
authinfo.hkdf,
|
||||
|
@ -711,9 +742,6 @@ impl Fenrir {
|
|||
lock.reserve_first(raw_conn)
|
||||
};
|
||||
|
||||
// TODO: move all the next bits into
|
||||
// dirsync::Req::respond(...)
|
||||
|
||||
let resp_data = dirsync::RespData {
|
||||
client_nonce: req_data.nonce,
|
||||
id: auth_conn.id,
|
||||
|
@ -721,25 +749,18 @@ impl Fenrir {
|
|||
service_key: srv_secret,
|
||||
};
|
||||
use crate::enc::sym::AAD;
|
||||
let aad = AAD(&mut []); // no aad for now
|
||||
let mut data = auth_conn
|
||||
.cipher_send
|
||||
.make_data(dirsync::RespData::len());
|
||||
// no aad for now
|
||||
let aad = AAD(&mut []);
|
||||
|
||||
if let Err(e) = auth_conn
|
||||
.cipher_send
|
||||
.encrypt(aad, &mut data)
|
||||
{
|
||||
::tracing::error!("can't encrypt: {:?}", e);
|
||||
return;
|
||||
}
|
||||
use dirsync::RespInner;
|
||||
let resp = dirsync::Resp {
|
||||
client_key_id: req_data.client_key_id,
|
||||
data: RespInner::CipherText(
|
||||
data.get_raw().into(),
|
||||
),
|
||||
data: RespInner::ClearText(resp_data),
|
||||
};
|
||||
let offset_to_encrypt = resp.encrypted_offset();
|
||||
let encrypt_until = offset_to_encrypt
|
||||
+ resp.encrypted_length()
|
||||
+ tag_len.0;
|
||||
let resp_handshake = Handshake::new(
|
||||
HandshakeData::DirSync(DirSync::Resp(resp)),
|
||||
);
|
||||
|
@ -750,7 +771,20 @@ impl Fenrir {
|
|||
};
|
||||
let mut raw_out =
|
||||
Vec::<u8>::with_capacity(packet.len());
|
||||
packet.serialize(&mut raw_out);
|
||||
packet.serialize(
|
||||
head_len,
|
||||
tag_len,
|
||||
&mut raw_out,
|
||||
);
|
||||
|
||||
if let Err(e) = auth_conn.cipher_send.encrypt(
|
||||
aad,
|
||||
&mut raw_out
|
||||
[offset_to_encrypt..encrypt_until],
|
||||
) {
|
||||
::tracing::error!("can't encrypt: {:?}", e);
|
||||
return;
|
||||
}
|
||||
self.send_packet(raw_out, udp.src, udp.dst)
|
||||
.await;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue