#[cfg(any(feature = "reference-frame", feature = "lz4"))]
use crate::payload_types;
use crate::{Sealable, Session, WireError};
pub fn seal<T: Sealable>(
payload: &T,
session: &mut Session,
payload_type: u8,
) -> Result<Vec<u8>, WireError> {
let plaintext = payload.to_bin()?;
session.seal(&plaintext, payload_type)
}
pub fn open<T: Sealable>(bytes: &[u8], session: &mut Session) -> Result<T, WireError> {
let plaintext = session.open(bytes)?;
T::from_bin(&plaintext)
}
#[cfg(feature = "reference-frame")]
pub fn seal_frame(frame: &crate::Frame, session: &mut Session) -> Result<Vec<u8>, WireError> {
seal(frame, session, payload_types::PAYLOAD_TYPE_FRAME)
}
#[cfg(feature = "reference-frame")]
pub fn open_frame(bytes: &[u8], session: &mut Session) -> Result<crate::Frame, WireError> {
open(bytes, session)
}
#[cfg(feature = "reference-frame")]
pub fn seal_input(input: &crate::Input, session: &mut Session) -> Result<Vec<u8>, WireError> {
seal(input, session, payload_types::PAYLOAD_TYPE_INPUT)
}
#[cfg(feature = "reference-frame")]
pub fn open_input(bytes: &[u8], session: &mut Session) -> Result<crate::Input, WireError> {
open(bytes, session)
}
#[cfg(feature = "lz4")]
pub fn seal_frame_lz4(frame: &crate::Frame, session: &mut Session) -> Result<Vec<u8>, WireError> {
let plaintext = frame.to_bin()?;
let compressed = lz4_flex::block::compress_prepend_size(&plaintext);
session.seal(&compressed, payload_types::PAYLOAD_TYPE_FRAME_LZ4)
}
#[cfg(feature = "lz4")]
pub fn open_frame_lz4(bytes: &[u8], session: &mut Session) -> Result<crate::Frame, WireError> {
let compressed = session.open(bytes)?;
let plaintext = lz4_flex::block::decompress_size_prepended(&compressed)
.map_err(|_| WireError::OpenFailed)?;
<crate::Frame as Sealable>::from_bin(&plaintext)
}
#[cfg(feature = "consent")]
pub fn seal_consent_request(
request: &crate::consent::ConsentRequest,
session: &mut Session,
) -> Result<Vec<u8>, WireError> {
seal(
request,
session,
payload_types::PAYLOAD_TYPE_CONSENT_REQUEST,
)
}
#[cfg(feature = "consent")]
pub fn open_consent_request(
bytes: &[u8],
session: &mut Session,
) -> Result<crate::consent::ConsentRequest, WireError> {
open(bytes, session)
}
#[cfg(feature = "consent")]
pub fn seal_consent_response(
response: &crate::consent::ConsentResponse,
session: &mut Session,
) -> Result<Vec<u8>, WireError> {
seal(
response,
session,
payload_types::PAYLOAD_TYPE_CONSENT_RESPONSE,
)
}
#[cfg(feature = "consent")]
pub fn open_consent_response(
bytes: &[u8],
session: &mut Session,
) -> Result<crate::consent::ConsentResponse, WireError> {
open(bytes, session)
}
#[cfg(feature = "consent")]
pub fn seal_consent_revocation(
revocation: &crate::consent::ConsentRevocation,
session: &mut Session,
) -> Result<Vec<u8>, WireError> {
seal(
revocation,
session,
payload_types::PAYLOAD_TYPE_CONSENT_REVOCATION,
)
}
#[cfg(feature = "consent")]
pub fn open_consent_revocation(
bytes: &[u8],
session: &mut Session,
) -> Result<crate::consent::ConsentRevocation, WireError> {
open(bytes, session)
}
#[cfg(all(test, feature = "reference-frame"))]
mod tests {
use super::*;
use crate::Frame;
fn paired_sessions(key: [u8; 32]) -> (Session, Session) {
let mut sender = Session::with_source_id([0x11; 8], 0x42);
let mut receiver = Session::with_source_id([0x11; 8], 0x42);
sender.install_key(key);
receiver.install_key(key);
(sender, receiver)
}
fn sample_frame() -> Frame {
Frame {
frame_id: 1,
timestamp_ms: 1_700_000_000_000,
payload: (0..256u16).map(|i| (i & 0xFF) as u8).collect(),
}
}
#[test]
fn seal_open_frame_roundtrip() {
let (mut sender, mut receiver) = paired_sessions([0xAB; 32]);
let frame = sample_frame();
let sealed = seal_frame(&frame, &mut sender).unwrap();
let opened = open_frame(&sealed, &mut receiver).unwrap();
assert_eq!(opened, frame);
}
#[test]
fn seal_open_input_roundtrip() {
let (mut sender, mut receiver) = paired_sessions([0xCD; 32]);
let input = crate::Input {
sequence: 3,
timestamp_ms: 1_700_000_000_050,
payload: b"tap".to_vec(),
};
let sealed = seal_input(&input, &mut sender).unwrap();
let opened = open_input(&sealed, &mut receiver).unwrap();
assert_eq!(opened, input);
}
#[cfg(feature = "lz4")]
#[test]
fn lz4_roundtrip_and_smaller_than_raw() {
let (mut raw_sender, _) = paired_sessions([0x01; 32]);
let (mut lz4_sender, mut lz4_receiver) = paired_sessions([0x02; 32]);
let frame = Frame {
frame_id: 9,
timestamp_ms: 1_700_000_000_123,
payload: vec![0x5A; 4096],
};
let raw_sealed = seal_frame(&frame, &mut raw_sender).unwrap();
let lz4_sealed = seal_frame_lz4(&frame, &mut lz4_sender).unwrap();
let opened = open_frame_lz4(&lz4_sealed, &mut lz4_receiver).unwrap();
assert_eq!(opened, frame);
assert!(
lz4_sealed.len() < raw_sealed.len(),
"LZ4 sealed ({}) must be smaller than raw sealed ({}) for compressible payloads",
lz4_sealed.len(),
raw_sealed.len(),
);
}
#[test]
fn generic_seal_open_for_custom_payload_type() {
#[derive(serde::Serialize, serde::Deserialize, PartialEq, Eq, Debug)]
struct MyPayload {
marker: u32,
bytes: Vec<u8>,
}
impl Sealable for MyPayload {
fn to_bin(&self) -> Result<Vec<u8>, WireError> {
bincode::serialize(self).map_err(WireError::encode)
}
fn from_bin(b: &[u8]) -> Result<Self, WireError> {
bincode::deserialize(b).map_err(WireError::decode)
}
}
let (mut sender, mut receiver) = paired_sessions([0xEF; 32]);
let payload = MyPayload {
marker: 0xDEAD_BEEF,
bytes: vec![1, 2, 3, 4, 5],
};
let sealed = seal(&payload, &mut sender, 0x30).unwrap();
let opened: MyPayload = open(&sealed, &mut receiver).unwrap();
assert_eq!(opened, payload);
}
}