use alloc::vec::Vec;
use rvf_types::{ErrorCode, RvfError, SignatureFooter};
const FOOTER_MIN_SIZE: usize = 8;
pub fn encode_signature_footer(footer: &SignatureFooter) -> Vec<u8> {
let sig_len = footer.sig_length as usize;
let total = 2 + 2 + sig_len + 4;
let mut buf = Vec::with_capacity(total);
buf.extend_from_slice(&footer.sig_algo.to_le_bytes());
buf.extend_from_slice(&footer.sig_length.to_le_bytes());
buf.extend_from_slice(&footer.signature[..sig_len]);
buf.extend_from_slice(&footer.footer_length.to_le_bytes());
buf
}
pub fn decode_signature_footer(data: &[u8]) -> Result<SignatureFooter, RvfError> {
if data.len() < FOOTER_MIN_SIZE {
return Err(RvfError::Code(ErrorCode::TruncatedSegment));
}
let sig_algo = u16::from_le_bytes([data[0], data[1]]);
let sig_length = u16::from_le_bytes([data[2], data[3]]);
let sig_len = sig_length as usize;
if sig_len > SignatureFooter::MAX_SIG_LEN {
return Err(RvfError::Code(ErrorCode::InvalidSignature));
}
if data.len() < 4 + sig_len + 4 {
return Err(RvfError::Code(ErrorCode::TruncatedSegment));
}
let mut signature = [0u8; SignatureFooter::MAX_SIG_LEN];
signature[..sig_len].copy_from_slice(&data[4..4 + sig_len]);
let fl_offset = 4 + sig_len;
let footer_length = u32::from_le_bytes([
data[fl_offset],
data[fl_offset + 1],
data[fl_offset + 2],
data[fl_offset + 3],
]);
Ok(SignatureFooter {
sig_algo,
sig_length,
signature,
footer_length,
})
}
#[cfg(test)]
mod tests {
use super::*;
fn make_footer(algo: u16, sig_len: u16, fill: u8) -> SignatureFooter {
let mut signature = [0u8; SignatureFooter::MAX_SIG_LEN];
signature[..sig_len as usize].fill(fill);
SignatureFooter {
sig_algo: algo,
sig_length: sig_len,
signature,
footer_length: SignatureFooter::compute_footer_length(sig_len),
}
}
#[test]
fn round_trip_ed25519() {
let footer = make_footer(0, 64, 0xAB);
let encoded = encode_signature_footer(&footer);
assert_eq!(encoded.len(), 2 + 2 + 64 + 4);
let decoded = decode_signature_footer(&encoded).unwrap();
assert_eq!(decoded.sig_algo, footer.sig_algo);
assert_eq!(decoded.sig_length, footer.sig_length);
assert_eq!(&decoded.signature[..64], &footer.signature[..64]);
assert_eq!(decoded.footer_length, footer.footer_length);
}
#[test]
fn decode_truncated_header() {
let result = decode_signature_footer(&[0u8; 5]);
assert!(result.is_err());
}
#[test]
fn decode_truncated_signature() {
let footer = make_footer(0, 64, 0xCC);
let encoded = encode_signature_footer(&footer);
let result = decode_signature_footer(&encoded[..10]);
assert!(result.is_err());
}
#[test]
fn empty_signature() {
let footer = make_footer(1, 0, 0);
let encoded = encode_signature_footer(&footer);
assert_eq!(encoded.len(), FOOTER_MIN_SIZE);
let decoded = decode_signature_footer(&encoded).unwrap();
assert_eq!(decoded.sig_algo, 1);
assert_eq!(decoded.sig_length, 0);
}
}