Skip to main content

coven_format/
sealed.rs

1//! Bounds shared by every sealed object layout.
2
3use crate::error::{bound, exact_length, require, Error, Rule};
4
5use coven_crypto::{SEALED_OBJECT_CHUNK_OVERHEAD, SIGNATURE_LEN};
6
7/// Bytes a stored sealed chunk adds to its plaintext: the 4-byte length
8/// prefix, then the nonce and tag.
9pub const STORED_CHUNK_OVERHEAD: usize = 4 + SEALED_OBJECT_CHUNK_OVERHEAD;
10
11pub(crate) fn signature(bytes: &[u8]) -> Result<coven_crypto::Signature, Error> {
12    exact_length(bytes.len(), SIGNATURE_LEN)?;
13    Ok(coven_crypto::Signature::from_bytes(bytes.try_into().expect("a signature's length")))
14}
15
16pub(crate) fn prefix(bytes: &[u8], kind: u8) -> Result<(), Error> {
17    let prefix = bytes.get(..3).ok_or(Error::Truncated)?;
18    if prefix[0] != kind {
19        return Err(Error::UnknownTag { field: "sealed object kind", tag: prefix[0] });
20    }
21    let crate::FormatVersion::V1 = crate::FormatVersion::decode(prefix)?;
22    Ok(())
23}
24
25pub(crate) fn chunk_length(prefix: &[u8], maximum: usize) -> Result<usize, Error> {
26    let bytes: [u8; 4] = prefix.get(..4).ok_or(Error::Truncated)?.try_into().expect("four bytes");
27    let length = u32::from_be_bytes(bytes) as usize;
28    bound(length, maximum, "sealed chunk")?;
29    require(length > 0, "sealed chunk", Rule::Chunk)?;
30    Ok(length + STORED_CHUNK_OVERHEAD)
31}
32
33pub(crate) fn chunk(bytes: &[u8], maximum: usize) -> Result<&[u8], Error> {
34    exact_length(bytes.len(), chunk_length(bytes, maximum)?)?;
35    Ok(&bytes[4..])
36}
37
38pub(crate) fn encode_chunk(bytes: &[u8]) -> Result<Vec<u8>, Error> {
39    let length = bytes.len().checked_sub(SEALED_OBJECT_CHUNK_OVERHEAD).ok_or(Error::Truncated)?;
40    require(length > 0, "sealed chunk", Rule::Chunk)?;
41    bound(length, crate::wire::MAX_OBJECT, "sealed chunk")?;
42    let mut result = Vec::new();
43    result.try_reserve_exact(4 + bytes.len())?;
44    result.extend_from_slice(&(length as u32).to_be_bytes());
45    result.extend_from_slice(bytes);
46    Ok(result)
47}
48
49#[cfg(test)]
50#[path = "sealed_tests.rs"]
51mod tests;