opentdf_protocol/nanotdf/
header.rs1use crate::binary::{BinaryRead, BinaryWrite, read_u8, write_u8};
6use crate::nanotdf::{MAGIC_NUMBER_AND_VERSION, Policy, resource_locator::ResourceLocator};
7use std::io::{self, Read, Write};
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12pub struct MagicNumberAndVersion {
13 pub bytes: [u8; 3],
14}
15
16impl Default for MagicNumberAndVersion {
17 fn default() -> Self {
18 Self {
19 bytes: MAGIC_NUMBER_AND_VERSION,
20 }
21 }
22}
23
24impl MagicNumberAndVersion {
25 pub fn new() -> Self {
27 Self::default()
28 }
29
30 pub fn validate(&self) -> io::Result<()> {
32 if self.bytes != MAGIC_NUMBER_AND_VERSION {
33 return Err(io::Error::new(
34 io::ErrorKind::InvalidData,
35 format!(
36 "Invalid magic number and version: {:02X}{:02X}{:02X} (expected 4C314C)",
37 self.bytes[0], self.bytes[1], self.bytes[2]
38 ),
39 ));
40 }
41 Ok(())
42 }
43}
44
45impl BinaryRead for MagicNumberAndVersion {
46 fn read_from<R: Read>(reader: &mut R) -> io::Result<Self> {
47 let mut bytes = [0u8; 3];
48 reader.read_exact(&mut bytes)?;
49 let magic = Self { bytes };
50 magic.validate()?;
51 Ok(magic)
52 }
53}
54
55impl BinaryWrite for MagicNumberAndVersion {
56 fn write_to<W: Write>(&self, writer: &mut W) -> io::Result<()> {
57 writer.write_all(&self.bytes)
58 }
59
60 fn serialized_size(&self) -> usize {
61 3
62 }
63}
64
65#[derive(Debug, Clone, Copy, PartialEq, Eq)]
67#[repr(u8)]
68pub enum EccMode {
69 Secp256r1 = 0x00,
71 Secp384r1 = 0x01,
73 Secp521r1 = 0x02,
75 Secp256k1 = 0x03,
77}
78
79impl EccMode {
80 pub fn from_bits(bits: u8) -> io::Result<Self> {
82 match bits & 0x07 {
83 0x00 => Ok(EccMode::Secp256r1),
84 0x01 => Ok(EccMode::Secp384r1),
85 0x02 => Ok(EccMode::Secp521r1),
86 0x03 => Ok(EccMode::Secp256k1),
87 _ => Err(io::Error::new(
88 io::ErrorKind::InvalidData,
89 format!("Invalid ECC mode: {}", bits),
90 )),
91 }
92 }
93
94 pub fn to_bits(self) -> u8 {
96 self as u8
97 }
98
99 pub fn public_key_size(self) -> usize {
101 match self {
102 EccMode::Secp256r1 => 33, EccMode::Secp384r1 => 49, EccMode::Secp521r1 => 67, EccMode::Secp256k1 => 33, }
107 }
108
109 pub fn signature_size(self) -> usize {
111 match self {
112 EccMode::Secp256r1 => 64, EccMode::Secp384r1 => 96, EccMode::Secp521r1 => 132, EccMode::Secp256k1 => 64, }
117 }
118}
119
120#[derive(Debug, Clone, Copy, PartialEq, Eq)]
128pub struct EccAndBindingMode {
129 pub use_ecdsa_binding: bool,
131 pub ecc_mode: EccMode,
133}
134
135impl EccAndBindingMode {
136 pub fn new(use_ecdsa_binding: bool, ecc_mode: EccMode) -> Self {
138 Self {
139 use_ecdsa_binding,
140 ecc_mode,
141 }
142 }
143
144 pub fn from_byte(byte: u8) -> io::Result<Self> {
146 let use_ecdsa_binding = (byte & 0x80) != 0;
147 let ecc_mode = EccMode::from_bits(byte & 0x07)?;
148 Ok(Self {
149 use_ecdsa_binding,
150 ecc_mode,
151 })
152 }
153
154 pub fn to_byte(self) -> u8 {
156 let ecdsa_bit = if self.use_ecdsa_binding { 0x80 } else { 0x00 };
157 ecdsa_bit | self.ecc_mode.to_bits()
158 }
159}
160
161impl BinaryRead for EccAndBindingMode {
162 fn read_from<R: Read>(reader: &mut R) -> io::Result<Self> {
163 let byte = read_u8(reader)?;
164 Self::from_byte(byte)
165 }
166}
167
168impl BinaryWrite for EccAndBindingMode {
169 fn write_to<W: Write>(&self, writer: &mut W) -> io::Result<()> {
170 write_u8(writer, self.to_byte())
171 }
172
173 fn serialized_size(&self) -> usize {
174 1
175 }
176}
177
178#[derive(Debug, Clone, Copy, PartialEq, Eq)]
180#[repr(u8)]
181pub enum SymmetricCipher {
182 Aes256Gcm64 = 0x00,
184 Aes256Gcm96 = 0x01,
186 Aes256Gcm104 = 0x02,
188 Aes256Gcm112 = 0x03,
190 Aes256Gcm120 = 0x04,
192 Aes256Gcm128 = 0x05,
194}
195
196impl SymmetricCipher {
197 pub fn from_bits(bits: u8) -> io::Result<Self> {
199 match bits & 0x0F {
200 0x00 => Ok(SymmetricCipher::Aes256Gcm64),
201 0x01 => Ok(SymmetricCipher::Aes256Gcm96),
202 0x02 => Ok(SymmetricCipher::Aes256Gcm104),
203 0x03 => Ok(SymmetricCipher::Aes256Gcm112),
204 0x04 => Ok(SymmetricCipher::Aes256Gcm120),
205 0x05 => Ok(SymmetricCipher::Aes256Gcm128),
206 _ => Err(io::Error::new(
207 io::ErrorKind::InvalidData,
208 format!("Invalid symmetric cipher: {}", bits),
209 )),
210 }
211 }
212
213 pub fn to_bits(self) -> u8 {
215 self as u8
216 }
217
218 pub fn tag_size(self) -> usize {
220 match self {
221 SymmetricCipher::Aes256Gcm64 => 8,
222 SymmetricCipher::Aes256Gcm96 => 12,
223 SymmetricCipher::Aes256Gcm104 => 13,
224 SymmetricCipher::Aes256Gcm112 => 14,
225 SymmetricCipher::Aes256Gcm120 => 15,
226 SymmetricCipher::Aes256Gcm128 => 16,
227 }
228 }
229}
230
231#[derive(Debug, Clone, Copy, PartialEq, Eq)]
233pub struct PayloadSignatureMode {
234 pub has_signature: bool,
236 pub signature_ecc_mode: Option<EccMode>,
238}
239
240impl PayloadSignatureMode {
241 pub fn none() -> Self {
243 Self {
244 has_signature: false,
245 signature_ecc_mode: None,
246 }
247 }
248
249 pub fn with_signature(ecc_mode: EccMode) -> Self {
251 Self {
252 has_signature: true,
253 signature_ecc_mode: Some(ecc_mode),
254 }
255 }
256
257 pub fn signature_size(&self) -> usize {
259 if let Some(ecc_mode) = self.signature_ecc_mode {
260 ecc_mode.public_key_size() + ecc_mode.signature_size()
261 } else {
262 0
263 }
264 }
265}
266
267#[derive(Debug, Clone, Copy, PartialEq, Eq)]
275pub struct SymmetricAndPayloadConfig {
276 pub signature_mode: PayloadSignatureMode,
277 pub symmetric_cipher: SymmetricCipher,
278}
279
280impl SymmetricAndPayloadConfig {
281 pub fn new(signature_mode: PayloadSignatureMode, symmetric_cipher: SymmetricCipher) -> Self {
283 Self {
284 signature_mode,
285 symmetric_cipher,
286 }
287 }
288
289 pub fn from_byte(byte: u8) -> io::Result<Self> {
291 let has_signature = (byte & 0x80) != 0;
292 let signature_ecc_mode = if has_signature {
293 Some(EccMode::from_bits((byte >> 4) & 0x07)?)
294 } else {
295 None
296 };
297 let symmetric_cipher = SymmetricCipher::from_bits(byte & 0x0F)?;
298
299 Ok(Self {
300 signature_mode: PayloadSignatureMode {
301 has_signature,
302 signature_ecc_mode,
303 },
304 symmetric_cipher,
305 })
306 }
307
308 pub fn to_byte(self) -> u8 {
310 let sig_bit = if self.signature_mode.has_signature {
311 0x80
312 } else {
313 0x00
314 };
315 let sig_ecc = if let Some(ecc_mode) = self.signature_mode.signature_ecc_mode {
316 ecc_mode.to_bits() << 4
317 } else {
318 0x00
319 };
320 sig_bit | sig_ecc | self.symmetric_cipher.to_bits()
321 }
322}
323
324impl BinaryRead for SymmetricAndPayloadConfig {
325 fn read_from<R: Read>(reader: &mut R) -> io::Result<Self> {
326 let byte = read_u8(reader)?;
327 Self::from_byte(byte)
328 }
329}
330
331impl BinaryWrite for SymmetricAndPayloadConfig {
332 fn write_to<W: Write>(&self, writer: &mut W) -> io::Result<()> {
333 write_u8(writer, self.to_byte())
334 }
335
336 fn serialized_size(&self) -> usize {
337 1
338 }
339}
340
341#[derive(Debug, Clone, PartialEq, Eq)]
350pub struct Header {
351 pub magic_number_and_version: MagicNumberAndVersion,
352 pub kas: ResourceLocator,
353 pub ecc_and_binding_mode: EccAndBindingMode,
354 pub symmetric_and_payload_config: SymmetricAndPayloadConfig,
355 pub policy: Policy,
356 pub ephemeral_public_key: Vec<u8>,
357}
358
359impl Header {
360 pub fn new(
362 kas: ResourceLocator,
363 ecc_and_binding_mode: EccAndBindingMode,
364 symmetric_and_payload_config: SymmetricAndPayloadConfig,
365 policy: Policy,
366 ephemeral_public_key: Vec<u8>,
367 ) -> io::Result<Self> {
368 let expected_size = ecc_and_binding_mode.ecc_mode.public_key_size();
370 if ephemeral_public_key.len() != expected_size {
371 return Err(io::Error::new(
372 io::ErrorKind::InvalidInput,
373 format!(
374 "Invalid ephemeral public key size: {} (expected {})",
375 ephemeral_public_key.len(),
376 expected_size
377 ),
378 ));
379 }
380
381 Ok(Self {
382 magic_number_and_version: MagicNumberAndVersion::new(),
383 kas,
384 ecc_and_binding_mode,
385 symmetric_and_payload_config,
386 policy,
387 ephemeral_public_key,
388 })
389 }
390}
391
392impl BinaryRead for Header {
393 fn read_from<R: Read>(reader: &mut R) -> io::Result<Self> {
394 let magic_number_and_version = MagicNumberAndVersion::read_from(reader)?;
395 let kas = ResourceLocator::read_from(reader)?;
396 let ecc_and_binding_mode = EccAndBindingMode::read_from(reader)?;
397 let symmetric_and_payload_config = SymmetricAndPayloadConfig::read_from(reader)?;
398 let policy = Policy::read_from(reader)?;
399
400 let key_size = ecc_and_binding_mode.ecc_mode.public_key_size();
402 let mut ephemeral_public_key = vec![0u8; key_size];
403 reader.read_exact(&mut ephemeral_public_key)?;
404
405 Ok(Self {
406 magic_number_and_version,
407 kas,
408 ecc_and_binding_mode,
409 symmetric_and_payload_config,
410 policy,
411 ephemeral_public_key,
412 })
413 }
414}
415
416impl BinaryWrite for Header {
417 fn write_to<W: Write>(&self, writer: &mut W) -> io::Result<()> {
418 self.magic_number_and_version.write_to(writer)?;
419 self.kas.write_to(writer)?;
420 self.ecc_and_binding_mode.write_to(writer)?;
421 self.symmetric_and_payload_config.write_to(writer)?;
422 self.policy.write_to(writer)?;
423 writer.write_all(&self.ephemeral_public_key)?;
424 Ok(())
425 }
426
427 fn serialized_size(&self) -> usize {
428 self.magic_number_and_version.serialized_size()
429 + self.kas.serialized_size()
430 + self.ecc_and_binding_mode.serialized_size()
431 + self.symmetric_and_payload_config.serialized_size()
432 + self.policy.serialized_size()
433 + self.ephemeral_public_key.len()
434 }
435}
436
437#[cfg(test)]
438mod tests {
439 use super::*;
440
441 #[test]
442 fn test_magic_number() {
443 assert_eq!(MAGIC_NUMBER_AND_VERSION, [0x4C, 0x31, 0x4C]);
444 let magic = MagicNumberAndVersion::new();
445 assert_eq!(magic.bytes, [0x4C, 0x31, 0x4C]);
446 assert!(magic.validate().is_ok());
447 }
448
449 #[test]
450 fn test_ecc_mode_sizes() {
451 assert_eq!(EccMode::Secp256r1.public_key_size(), 33);
452 assert_eq!(EccMode::Secp384r1.public_key_size(), 49);
453 assert_eq!(EccMode::Secp521r1.public_key_size(), 67);
454 assert_eq!(EccMode::Secp256k1.public_key_size(), 33);
455
456 assert_eq!(EccMode::Secp256r1.signature_size(), 64);
457 assert_eq!(EccMode::Secp384r1.signature_size(), 96);
458 assert_eq!(EccMode::Secp521r1.signature_size(), 132);
459 }
460
461 #[test]
462 fn test_ecc_and_binding_mode() {
463 let mode = EccAndBindingMode::new(true, EccMode::Secp256r1);
464 let byte = mode.to_byte();
465 assert_eq!(byte, 0x80); let parsed = EccAndBindingMode::from_byte(byte).unwrap();
468 assert_eq!(parsed, mode);
469 }
470
471 #[test]
472 fn test_symmetric_cipher_tag_sizes() {
473 assert_eq!(SymmetricCipher::Aes256Gcm64.tag_size(), 8);
474 assert_eq!(SymmetricCipher::Aes256Gcm96.tag_size(), 12);
475 assert_eq!(SymmetricCipher::Aes256Gcm128.tag_size(), 16);
476 }
477
478 #[test]
479 fn test_symmetric_and_payload_config() {
480 let config = SymmetricAndPayloadConfig::new(
481 PayloadSignatureMode::with_signature(EccMode::Secp256r1),
482 SymmetricCipher::Aes256Gcm128,
483 );
484 let byte = config.to_byte();
485 assert_eq!(byte, 0x85);
488
489 let parsed = SymmetricAndPayloadConfig::from_byte(byte).unwrap();
490 assert_eq!(parsed.signature_mode.has_signature, true);
491 assert_eq!(
492 parsed.signature_mode.signature_ecc_mode,
493 Some(EccMode::Secp256r1)
494 );
495 assert_eq!(parsed.symmetric_cipher, SymmetricCipher::Aes256Gcm128);
496 }
497}