pub fn le64_encode(n: u64) -> [u8; 8] {
n.to_le_bytes()
}
pub fn pae_encode(pieces: &[&[u8]]) -> Vec<u8> {
let mut total_size = 8; for piece in pieces {
total_size += 8; total_size += piece.len(); }
let mut result = Vec::with_capacity(total_size);
let piece_count = pieces.len() as u64;
result.extend_from_slice(&le64_encode(piece_count));
for piece in pieces {
let piece_len = piece.len() as u64;
result.extend_from_slice(&le64_encode(piece_len));
result.extend_from_slice(piece);
}
result
}
pub fn pae_encode_public_token(
header: &[u8],
payload_bytes: &[u8],
footer_bytes: &[u8],
) -> Vec<u8> {
pae_encode(&[header, payload_bytes, footer_bytes])
}
pub fn pae_encode_local_token(header: &[u8], nonce_bytes: &[u8], footer_bytes: &[u8]) -> Vec<u8> {
pae_encode(&[header, nonce_bytes, footer_bytes])
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_le64_encode_zero() {
let result = le64_encode(0);
assert_eq!(result, [0, 0, 0, 0, 0, 0, 0, 0]);
}
#[test]
fn test_le64_encode_small_number() {
let result = le64_encode(42);
assert_eq!(result, [42, 0, 0, 0, 0, 0, 0, 0]);
}
#[test]
fn test_le64_encode_large_number() {
let result = le64_encode(0x123456789ABCDEF0);
assert_eq!(result, [0xF0, 0xDE, 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12]);
}
#[test]
fn test_le64_encode_max_value() {
let result = le64_encode(u64::MAX);
assert_eq!(result, [0xFF; 8]);
}
#[test]
fn test_pae_encode_empty() {
let result = pae_encode(&[]);
assert_eq!(result, [0, 0, 0, 0, 0, 0, 0, 0]);
}
#[test]
fn test_pae_encode_single_empty_piece() {
let result = pae_encode(&[b""]);
let expected = vec![
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, ];
assert_eq!(result, expected);
}
#[test]
fn test_pae_encode_single_piece() {
let result = pae_encode(&[b"test"]);
let expected = vec![
1, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, b't', b'e', b's', b't', ];
assert_eq!(result, expected);
}
#[test]
fn test_pae_encode_multiple_pieces() {
let result = pae_encode(&[b"hello", b"world"]);
let expected = vec![
2, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, b'h', b'e', b'l', b'l', b'o', 5, 0, 0, 0, 0, 0, 0, 0, b'w', b'o', b'r', b'l', b'd', ];
assert_eq!(result, expected);
}
#[test]
fn test_pae_encode_with_empty_middle_piece() {
let result = pae_encode(&[b"first", b"", b"third"]);
let expected = vec![
3, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, b'f', b'i', b'r', b's', b't', 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, b't', b'h', b'i', b'r', b'd', ];
assert_eq!(result, expected);
}
#[test]
fn test_pae_encode_binary_data() {
let binary_data = &[0x00, 0xFF, 0x42, 0x13];
let result = pae_encode(&[binary_data]);
let expected = vec![
1, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0x00, 0xFF, 0x42, 0x13, ];
assert_eq!(result, expected);
}
#[test]
fn test_pae_encode_large_piece() {
let large_piece = vec![b'A'; 1000];
let result = pae_encode(&[&large_piece]);
assert_eq!(result.len(), 8 + 8 + 1000); assert_eq!(&result[0..8], &[1, 0, 0, 0, 0, 0, 0, 0]); assert_eq!(&result[8..16], &le64_encode(1000)); assert!(result[16..].iter().all(|&b| b == b'A')); }
#[test]
fn test_pae_encode_rfc_vector_1() {
let result = pae_encode(&[]);
assert_eq!(result, [0, 0, 0, 0, 0, 0, 0, 0]);
}
#[test]
fn test_pae_encode_rfc_vector_2() {
let result = pae_encode(&[b""]);
let expected = vec![
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ];
assert_eq!(result, expected);
}
#[test]
fn test_pae_encode_rfc_vector_3() {
let result = pae_encode(&[b"test"]);
let expected = vec![
1, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, b't', b'e', b's', b't', ];
assert_eq!(result, expected);
}
#[test]
fn test_pae_encode_public_token() {
let header = b"paseto.pq1.public";
let payload = b"{\"sub\":\"test\"}";
let footer = b"{\"kid\":\"test-key\"}";
let result = pae_encode_public_token(header, payload, footer);
let expected = pae_encode(&[header, payload, footer]);
assert_eq!(result, expected);
}
#[test]
fn test_pae_encode_public_token_no_footer() {
let header = b"paseto.pq1.public";
let payload = b"{\"sub\":\"test\"}";
let footer = b"";
let result = pae_encode_public_token(header, payload, footer);
let expected = pae_encode(&[header, payload, footer]);
assert_eq!(result, expected);
}
#[test]
fn test_pae_encode_local_token() {
let header = b"paseto.pq1.local";
let nonce = &[
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C,
];
let footer = b"{\"version\":\"1.0\"}";
let result = pae_encode_local_token(header, nonce, footer);
let expected = pae_encode(&[header, nonce, footer]);
assert_eq!(result, expected);
}
#[test]
fn test_pae_encode_local_token_no_footer() {
let header = b"paseto.pq1.local";
let nonce = &[
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C,
];
let footer = b"";
let result = pae_encode_local_token(header, nonce, footer);
let expected = pae_encode(&[header, nonce, footer]);
assert_eq!(result, expected);
}
#[test]
fn test_pae_prevents_collision_attack() {
let result1 = pae_encode(&[b"ab", b"cd"]);
let result2 = pae_encode(&[b"a", b"bcd"]);
let result3 = pae_encode(&[b"abc", b"d"]);
assert_ne!(result1, result2);
assert_ne!(result1, result3);
assert_ne!(result2, result3);
}
#[test]
fn test_pae_is_deterministic() {
let empty: &[u8] = &[];
let input = &[b"test" as &[u8], b"data" as &[u8], empty];
let result1 = pae_encode(input);
let result2 = pae_encode(input);
assert_eq!(result1, result2);
}
#[test]
fn test_pae_handles_large_count() {
let pieces: Vec<&[u8]> = vec![b"x"; 100];
let result = pae_encode(&pieces);
assert_eq!(&result[0..8], &le64_encode(100));
assert_eq!(result.len(), 8 + 100 * 9);
}
#[test]
fn test_pae_memory_efficiency() {
let pieces = &[
b"short" as &[u8],
b"medium-length" as &[u8],
b"very-long-piece-that-takes-more-space" as &[u8],
];
let result = pae_encode(pieces);
let expected_len = 8 + (8 + 5) + (8 + 13) + (8 + 37);
assert_eq!(result.len(), expected_len);
}
}