use std::collections::HashMap;
use zeroize::{Zeroize, ZeroizeOnDrop};
use crate::error::{Result, SecurityError};
use crate::protocol::address::{GroupAddress, IndividualAddress};
#[derive(Clone, Zeroize, ZeroizeOnDrop)]
pub struct SecurityKey {
key: Vec<u8>,
}
impl SecurityKey {
#[must_use]
pub fn new(key: Vec<u8>) -> Self {
Self { key }
}
pub fn from_hex(hex: &str) -> Result<Self> {
let key = hex::decode(hex.replace([' ', ':'], "")).map_err(|e| {
SecurityError::InvalidCredentials {
details: format!("Invalid hex key: {e}"),
}
})?;
Ok(Self::new(key))
}
#[must_use]
pub fn as_bytes(&self) -> &[u8] {
&self.key
}
#[must_use]
pub fn len(&self) -> usize {
self.key.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.key.is_empty()
}
}
impl std::fmt::Debug for SecurityKey {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "SecurityKey([{} bytes])", self.key.len())
}
}
#[derive(Debug, Clone)]
pub struct SecurityCredentials {
pub user_id: u8,
pub user_password: SecurityKey,
pub device_auth: Option<SecurityKey>,
pub backbone_key: Option<SecurityKey>,
}
impl SecurityCredentials {
#[must_use]
pub fn new(user_id: u8, user_password: SecurityKey) -> Self {
Self {
user_id,
user_password,
device_auth: None,
backbone_key: None,
}
}
#[must_use]
pub fn with_device_auth(mut self, device_auth: SecurityKey) -> Self {
self.device_auth = Some(device_auth);
self
}
#[must_use]
pub fn with_backbone_key(mut self, backbone_key: SecurityKey) -> Self {
self.backbone_key = Some(backbone_key);
self
}
}
#[derive(Debug, Default)]
pub struct KeyRing {
group_keys: HashMap<GroupAddress, SecurityKey>,
sequence_numbers: HashMap<IndividualAddress, u64>,
tunnel_credentials: HashMap<String, SecurityCredentials>,
}
impl KeyRing {
#[must_use]
pub fn new() -> Self {
Self::default()
}
pub fn add_group_key(&mut self, address: GroupAddress, key: SecurityKey) {
self.group_keys.insert(address, key);
}
#[must_use]
pub fn get_group_key(&self, address: &GroupAddress) -> Option<&SecurityKey> {
self.group_keys.get(address)
}
#[must_use]
pub fn is_group_secured(&self, address: &GroupAddress) -> bool {
self.group_keys.contains_key(address)
}
pub fn secured_groups(&self) -> impl Iterator<Item = &GroupAddress> {
self.group_keys.keys()
}
pub fn set_sequence_number(&mut self, address: IndividualAddress, seq: u64) {
self.sequence_numbers.insert(address, seq);
}
#[must_use]
pub fn get_sequence_number(&self, address: &IndividualAddress) -> Option<u64> {
self.sequence_numbers.get(address).copied()
}
pub fn validate_sequence(&mut self, address: IndividualAddress, seq: u64) -> Result<()> {
if let Some(&last_seq) = self.sequence_numbers.get(&address)
&& seq <= last_seq
{
return Err(SecurityError::CryptographicError {
operation: "sequence validation".to_string(),
reason: format!("Sequence number {seq} not greater than last valid {last_seq}"),
}
.into());
}
self.sequence_numbers.insert(address, seq);
Ok(())
}
pub fn add_tunnel_credentials(&mut self, host: String, credentials: SecurityCredentials) {
self.tunnel_credentials.insert(host, credentials);
}
#[must_use]
pub fn get_tunnel_credentials(&self, host: &str) -> Option<&SecurityCredentials> {
self.tunnel_credentials.get(host)
}
#[must_use]
pub fn group_key_count(&self) -> usize {
self.group_keys.len()
}
#[must_use]
pub fn sender_count(&self) -> usize {
self.sequence_numbers.len()
}
}