Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 30 additions & 17 deletions src/crypt/fernet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ type HmacSha256 = Hmac<Sha256>;
const HMAC_OUT_SIZE: usize = <<HmacSha256 as OutputSizeUser>::OutputSize as Unsigned>::USIZE;
const AES_KEY_SIZE: usize = <<AesAlgo as KeySizeUser>::KeySize as Unsigned>::USIZE;
const IV_KEY_SIZE: usize = <<AesCbcEnc as IvSizeUser>::IvSize as Unsigned>::USIZE;
// Token layout: IV (IV_KEY_SIZE bytes) || ciphertext || HMAC (HMAC_OUT_SIZE bytes)
const FERNET_OVERHEAD_SIZE: usize = IV_KEY_SIZE + HMAC_OUT_SIZE;

pub struct PlainText<'a>(&'a [u8]);
Expand Down Expand Up @@ -161,28 +162,17 @@ impl<R: CryptoRngCore + Copy> Fernet<R> {
return Err(RnsError::InvalidArgument);
}

let expected_tag = &token_data[token_data.len() - HMAC_OUT_SIZE..];
let (data, expected_tag) = token_data.split_at(token_data.len() - HMAC_OUT_SIZE);

let mut hmac = <HmacSha256 as Mac>::new_from_slice(&self.sign_key)
.map_err(|_| RnsError::InvalidArgument)?;

hmac.update(&token_data[..token_data.len() - HMAC_OUT_SIZE]);
hmac.update(data);

let actual_tag = hmac.finalize().into_bytes();
hmac.verify_slice(expected_tag)
.map_err(|_| RnsError::IncorrectSignature)?;

let valid = expected_tag
.iter()
.zip(actual_tag.as_slice())
.map(|(x, y)| x.cmp(y))
.find(|&ord| ord != cmp::Ordering::Equal)
.unwrap_or(actual_tag.len().cmp(&expected_tag.len()))
== cmp::Ordering::Equal;

if valid {
Ok(VerifiedToken { 0: token_data })
} else {
Err(RnsError::IncorrectSignature)
}
Ok(VerifiedToken { 0: token_data })
}

pub fn decrypt<'a, 'b>(
Expand Down Expand Up @@ -212,7 +202,8 @@ impl<R: CryptoRngCore + Copy> Fernet<R> {

#[cfg(test)]
mod tests {
use crate::crypt::fernet::Fernet;
use super::{Fernet, Token, IV_KEY_SIZE};
use crate::error::RnsError;
use core::str;
use rand_core::OsRng;

Expand Down Expand Up @@ -248,4 +239,26 @@ mod tests {
let mut out_buf = [0u8; 12];
assert!(fernet.encrypt(test_msg.into(), &mut out_buf[..]).is_err());
}

#[test]
fn tamper_detection_fails_verification() {
const BUF_SIZE: usize = 4096;
let fernet = Fernet::new_rand(OsRng);
let out_msg: &str = "#FERNET_TEST_MESSAGE#";

let mut out_buf = [0u8; BUF_SIZE];
let token = fernet
.encrypt(out_msg.into(), &mut out_buf[..])
.expect("cipher token");

let tamper_indices = [0usize, IV_KEY_SIZE, token.len() - 1];

for idx in tamper_indices {
let mut tampered = token.as_bytes().to_vec();
tampered[idx] ^= 0xFF;

let verification = fernet.verify(Token::from(tampered.as_slice()));
assert!(matches!(verification, Err(RnsError::IncorrectSignature)));
}
}
}
37 changes: 30 additions & 7 deletions src/destination.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use crate::{
hash::{AddressHash, Hash},
identity::{EmptyIdentity, HashIdentity, Identity, PrivateIdentity, PUBLIC_KEY_LENGTH},
packet::{
self, DestinationType, Header, HeaderType, IfacFlag, Packet, PacketContext,
self, ContextFlag, DestinationType, Header, HeaderType, IfacFlag, Packet, PacketContext,
PacketDataBuffer, PacketType, PropagationType,
},
};
Expand Down Expand Up @@ -60,6 +60,7 @@ pub const NAME_HASH_LENGTH: usize = 10;
pub const RAND_HASH_LENGTH: usize = 10;
pub const MIN_ANNOUNCE_DATA_LENGTH: usize =
PUBLIC_KEY_LENGTH * 2 + NAME_HASH_LENGTH + RAND_HASH_LENGTH + SIGNATURE_LENGTH;
pub const RATCHET_PUBLIC_KEY_LENGTH: usize = 32;

#[derive(Copy, Clone)]
pub struct DestinationName {
Expand Down Expand Up @@ -118,8 +119,15 @@ impl DestinationAnnounce {
}

let announce_data = packet.data.as_slice();

if announce_data.len() < MIN_ANNOUNCE_DATA_LENGTH {
let has_ratchet = packet.header.context_flag.is_set();
let min_length = MIN_ANNOUNCE_DATA_LENGTH
+ if has_ratchet {
RATCHET_PUBLIC_KEY_LENGTH
} else {
0
};

if announce_data.len() < min_length {
return Err(RnsError::OutOfMemory);
}

Expand All @@ -146,6 +154,13 @@ impl DestinationAnnounce {
offset += NAME_HASH_LENGTH;
let rand_hash = &announce_data[offset..(offset + RAND_HASH_LENGTH)];
offset += RAND_HASH_LENGTH;
let ratchet = if has_ratchet {
let slice = &announce_data[offset..(offset + RATCHET_PUBLIC_KEY_LENGTH)];
offset += RATCHET_PUBLIC_KEY_LENGTH;
Some(slice)
} else {
None
};
let signature = &announce_data[offset..(offset + SIGNATURE_LENGTH)];
offset += SIGNATURE_LENGTH;
let app_data = &announce_data[offset..];
Expand All @@ -154,14 +169,21 @@ impl DestinationAnnounce {

// Keeping signed data on stack is only option for now.
// Verification function doesn't support prehashed message.
let signed_data = PacketDataBuffer::new()
let mut signed_data = PacketDataBuffer::new();
signed_data
.chain_write(destination.as_slice())?
.chain_write(public_key.as_bytes())?
.chain_write(verifying_key.as_bytes())?
.chain_write(name_hash)?
.chain_write(rand_hash)?
.chain_write(app_data)?
.finalize();
.chain_write(rand_hash)?;

if let Some(ratchet) = ratchet {
signed_data.chain_write(ratchet)?;
}

signed_data.chain_write(app_data)?;

let signed_data = signed_data.finalize();

let signature = Signature::from_slice(signature).map_err(|_| RnsError::CryptoError)?;

Expand Down Expand Up @@ -279,6 +301,7 @@ impl Destination<PrivateIdentity, Input, Single> {
header: Header {
ifac_flag: IfacFlag::Open,
header_type: HeaderType::Type1,
context_flag: ContextFlag::Unset,
propagation_type: PropagationType::Broadcast,
destination_type: DestinationType::Single,
packet_type: PacketType::Announce,
Expand Down
43 changes: 33 additions & 10 deletions src/packet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,21 +41,39 @@ impl From<u8> for HeaderType {
}
}

#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum ContextFlag {
Unset = 0b0,
Set = 0b1,
}

impl ContextFlag {
pub fn is_set(&self) -> bool {
matches!(self, ContextFlag::Set)
}
}

impl From<u8> for ContextFlag {
fn from(value: u8) -> Self {
match value & 0b1 {
0 => ContextFlag::Unset,
1 => ContextFlag::Set,
_ => ContextFlag::Unset,
}
}
}

#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum PropagationType {
Broadcast = 0b00,
Transport = 0b01,
Reserved1 = 0b10,
Reserved2 = 0b11,
Broadcast = 0b0,
Transport = 0b1,
}

impl From<u8> for PropagationType {
fn from(value: u8) -> Self {
match value & 0b11 {
0b00 => PropagationType::Broadcast,
0b01 => PropagationType::Transport,
0b10 => PropagationType::Reserved1,
0b11 => PropagationType::Reserved2,
match value & 0b1 {
0b0 => PropagationType::Broadcast,
0b1 => PropagationType::Transport,
_ => PropagationType::Broadcast,
}
}
Expand Down Expand Up @@ -158,6 +176,7 @@ impl From<u8> for PacketContext {
pub struct Header {
pub ifac_flag: IfacFlag,
pub header_type: HeaderType,
pub context_flag: ContextFlag,
pub propagation_type: PropagationType,
pub destination_type: DestinationType,
pub packet_type: PacketType,
Expand All @@ -169,6 +188,7 @@ impl Default for Header {
Self {
ifac_flag: IfacFlag::Open,
header_type: HeaderType::Type1,
context_flag: ContextFlag::Unset,
propagation_type: PropagationType::Broadcast,
destination_type: DestinationType::Single,
packet_type: PacketType::Data,
Expand All @@ -181,6 +201,7 @@ impl Header {
pub fn to_meta(&self) -> u8 {
let meta = (self.ifac_flag as u8) << 7
| (self.header_type as u8) << 6
| (self.context_flag as u8) << 5
| (self.propagation_type as u8) << 4
| (self.destination_type as u8) << 2
| (self.packet_type as u8) << 0;
Expand All @@ -191,6 +212,7 @@ impl Header {
Self {
ifac_flag: IfacFlag::from(meta >> 7),
header_type: HeaderType::from(meta >> 6),
context_flag: ContextFlag::from(meta >> 5),
propagation_type: PropagationType::from(meta >> 4),
destination_type: DestinationType::from(meta >> 2),
packet_type: PacketType::from(meta >> 0),
Expand All @@ -203,9 +225,10 @@ impl fmt::Display for Header {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{:b}{:b}{:0>2b}{:0>2b}{:0>2b}.{}",
"{:b}{:b}{:b}{:b}{:0>2b}{:0>2b}.{}",
self.ifac_flag as u8,
self.header_type as u8,
self.context_flag as u8,
self.propagation_type as u8,
self.destination_type as u8,
self.packet_type as u8,
Expand Down
6 changes: 4 additions & 2 deletions src/serde.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,8 @@ mod tests {
buffer::{InputBuffer, OutputBuffer, StaticBuffer},
hash::AddressHash,
packet::{
DestinationType, Header, HeaderType, IfacFlag, Packet, PacketContext, PacketType,
PropagationType,
ContextFlag, DestinationType, Header, HeaderType, IfacFlag, Packet, PacketContext,
PacketType, PropagationType,
},
};

Expand All @@ -122,6 +122,7 @@ mod tests {
header: Header {
ifac_flag: IfacFlag::Open,
header_type: HeaderType::Type1,
context_flag: ContextFlag::Unset,
propagation_type: PropagationType::Broadcast,
destination_type: DestinationType::Single,
packet_type: PacketType::Announce,
Expand Down Expand Up @@ -149,6 +150,7 @@ mod tests {
header: Header {
ifac_flag: IfacFlag::Open,
header_type: HeaderType::Type1,
context_flag: ContextFlag::Unset,
propagation_type: PropagationType::Broadcast,
destination_type: DestinationType::Single,
packet_type: PacketType::Announce,
Expand Down
1 change: 1 addition & 0 deletions src/transport.rs
Original file line number Diff line number Diff line change
Expand Up @@ -884,6 +884,7 @@ fn create_retransmit_packet(packet: &Packet) -> Packet {
header: Header {
ifac_flag: packet.header.ifac_flag,
header_type: packet.header.header_type,
context_flag: packet.header.context_flag,
propagation_type: packet.header.propagation_type,
destination_type: packet.header.destination_type,
packet_type: packet.header.packet_type,
Expand Down
1 change: 1 addition & 0 deletions src/transport/announce_table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ impl AnnounceEntry {
header: Header {
ifac_flag: IfacFlag::Open,
header_type: HeaderType::Type2,
context_flag: self.packet.header.context_flag,
propagation_type: PropagationType::Broadcast,
destination_type: DestinationType::Single,
packet_type: PacketType::Announce,
Expand Down
1 change: 1 addition & 0 deletions src/transport/link_table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ fn send_backwards(packet: &Packet, entry: &LinkEntry) -> (Packet, AddressHash) {
header: Header {
ifac_flag: IfacFlag::Authenticated,
header_type: HeaderType::Type2,
context_flag: packet.header.context_flag,
propagation_type: packet.header.propagation_type,
destination_type: packet.header.destination_type,
packet_type: packet.header.packet_type,
Expand Down
2 changes: 2 additions & 0 deletions src/transport/path_table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ impl PathTable {
header: Header {
ifac_flag: IfacFlag::Authenticated,
header_type: HeaderType::Type2,
context_flag: original_packet.header.context_flag,
propagation_type: original_packet.header.propagation_type,
destination_type: original_packet.header.destination_type,
packet_type: original_packet.header.packet_type,
Expand Down Expand Up @@ -132,6 +133,7 @@ impl PathTable {
header: Header {
ifac_flag: IfacFlag::Authenticated,
header_type: HeaderType::Type2,
context_flag: original_packet.header.context_flag,
propagation_type: original_packet.header.propagation_type,
destination_type: original_packet.header.destination_type,
packet_type: original_packet.header.packet_type,
Expand Down