1use crate::{
36 key::{argon2id_hash, balloon_hash},
37 protected::Protected,
38};
39
40use super::primitives::{get_nonce_len, Algorithm, Mode, ENCRYPTED_MASTER_KEY_LEN, SALT_LEN};
41use anyhow::{Context, Result};
42use std::io::{Cursor, Read, Seek, Write};
43
44pub const HEADER_VERSION: HeaderVersion = HeaderVersion::V5;
48
49#[allow(clippy::module_name_repetitions)]
51#[derive(PartialEq, Eq, Clone, Copy, PartialOrd)]
52pub enum HeaderVersion {
53 V1,
54 V2,
55 V3,
56 V4,
57 V5,
58}
59
60impl std::fmt::Display for HeaderVersion {
61 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
62 match self {
63 HeaderVersion::V1 => write!(f, "V1"),
64 HeaderVersion::V2 => write!(f, "V2"),
65 HeaderVersion::V3 => write!(f, "V3"),
66 HeaderVersion::V4 => write!(f, "V4"),
67 HeaderVersion::V5 => write!(f, "V5"),
68 }
69 }
70}
71
72#[allow(clippy::module_name_repetitions)]
78pub struct HeaderType {
79 pub version: HeaderVersion,
80 pub algorithm: Algorithm,
81 pub mode: Mode,
82}
83
84struct HeaderTag {
88 pub version: [u8; 2],
89 pub algorithm: [u8; 2],
90 pub mode: [u8; 2],
91}
92
93pub struct Header {
99 pub header_type: HeaderType,
100 pub nonce: Vec<u8>,
101 pub salt: Option<[u8; SALT_LEN]>, pub keyslots: Option<Vec<Keyslot>>,
103}
104
105pub const ARGON2ID_LATEST: i32 = 3;
106pub const BLAKE3BALLOON_LATEST: i32 = 5;
107
108
109#[derive(Clone, Copy, PartialEq, Eq)]
112pub enum HashingAlgorithm {
113 Argon2id(i32),
114 Blake3Balloon(i32),
115}
116
117impl std::fmt::Display for HashingAlgorithm {
118 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
119 match self {
120 HashingAlgorithm::Argon2id(i) => write!(f, "Argon2id (param v{})", i),
121 HashingAlgorithm::Blake3Balloon(i) => write!(f, "BLAKE3-Balloon (param v{})", i),
122 }
123 }
124}
125
126impl HashingAlgorithm {
127 pub fn hash(
129 &self,
130 raw_key: Protected<Vec<u8>>,
131 salt: &[u8; SALT_LEN],
132 ) -> Result<Protected<[u8; 32]>, anyhow::Error> {
133 match self {
134 HashingAlgorithm::Argon2id(i) => match i {
135 1 => argon2id_hash(raw_key, salt, &HeaderVersion::V1),
136 2 => argon2id_hash(raw_key, salt, &HeaderVersion::V2),
137 3 => argon2id_hash(raw_key, salt, &HeaderVersion::V3),
138 _ => Err(anyhow::anyhow!(
139 "argon2id is not supported with the parameters provided."
140 )),
141 },
142 HashingAlgorithm::Blake3Balloon(i) => match i {
143 4 => balloon_hash(raw_key, salt, &HeaderVersion::V4),
144 5 => balloon_hash(raw_key, salt, &HeaderVersion::V5),
145 _ => Err(anyhow::anyhow!(
146 "Balloon hashing is not supported with the parameters provided."
147 )),
148 },
149 }
150 }
151}
152
153#[derive(Clone)]
156pub struct Keyslot {
157 pub hash_algorithm: HashingAlgorithm,
158 pub encrypted_key: [u8; ENCRYPTED_MASTER_KEY_LEN],
159 pub nonce: Vec<u8>,
160 pub salt: [u8; SALT_LEN],
161}
162
163impl Keyslot {
164 #[must_use]
166 pub fn serialize(&self) -> [u8; 2] {
167 match self.hash_algorithm {
168 HashingAlgorithm::Argon2id(i) => match i {
169 1 => [0xDF, 0xA1],
170 2 => [0xDF, 0xA2],
171 3 => [0xDF, 0xA3],
172 _ => [0x00, 0x00],
173 },
174 HashingAlgorithm::Blake3Balloon(i) => match i {
175 4 => [0xDF, 0xB4],
176 5 => [0xDF, 0xB5],
177 _ => [0x00, 0x00],
178 },
179 }
180 }
181}
182
183impl Header {
184 fn get_tag(&self) -> HeaderTag {
188 let version = self.serialize_version();
189 let algorithm = self.serialize_algorithm();
190 let mode = self.serialize_mode();
191 HeaderTag {
192 version,
193 algorithm,
194 mode,
195 }
196 }
197
198 fn serialize_version(&self) -> [u8; 2] {
202 match self.header_type.version {
203 HeaderVersion::V1 => {
204 let info: [u8; 2] = [0xDE, 0x01];
205 info
206 }
207 HeaderVersion::V2 => {
208 let info: [u8; 2] = [0xDE, 0x02];
209 info
210 }
211 HeaderVersion::V3 => {
212 let info: [u8; 2] = [0xDE, 0x03];
213 info
214 }
215 HeaderVersion::V4 => {
216 let info: [u8; 2] = [0xDE, 0x04];
217 info
218 }
219 HeaderVersion::V5 => {
220 let info: [u8; 2] = [0xDE, 0x05];
221 info
222 }
223 }
224 }
225
226 #[allow(clippy::too_many_lines)]
253 pub fn deserialize(reader: &mut (impl Read + Seek)) -> Result<(Self, Vec<u8>)> {
254 let mut version_bytes = [0u8; 2];
255 reader
256 .read_exact(&mut version_bytes)
257 .context("Unable to read version from the header")?;
258 reader
259 .seek(std::io::SeekFrom::Current(-2))
260 .context("Unable to seek back to start of header")?;
261
262 let version = match version_bytes {
263 [0xDE, 0x01] => HeaderVersion::V1,
264 [0xDE, 0x02] => HeaderVersion::V2,
265 [0xDE, 0x03] => HeaderVersion::V3,
266 [0xDE, 0x04] => HeaderVersion::V4,
267 [0xDE, 0x05] => HeaderVersion::V5,
268 _ => return Err(anyhow::anyhow!("Error getting version from header")),
269 };
270
271 let header_length: usize = match version {
272 HeaderVersion::V1 | HeaderVersion::V2 | HeaderVersion::V3 => 64,
273 HeaderVersion::V4 => 128,
274 HeaderVersion::V5 => 416,
275 };
276
277 let mut full_header_bytes = vec![0u8; header_length];
278 reader
279 .read_exact(&mut full_header_bytes)
280 .context("Unable to read full bytes of the header")?;
281
282 let mut cursor = Cursor::new(full_header_bytes.clone());
283 cursor
284 .seek(std::io::SeekFrom::Start(2))
285 .context("Unable to seek past version bytes")?; let mut algorithm_bytes = [0u8; 2];
288 cursor
289 .read_exact(&mut algorithm_bytes)
290 .context("Unable to read algorithm's bytes from header")?;
291
292 let algorithm = match algorithm_bytes {
293 [0x0E, 0x01] => Algorithm::XChaCha20Poly1305,
294 [0x0E, 0x02] => Algorithm::Aes256Gcm,
295 [0x0E, 0x03] => Algorithm::DeoxysII256,
296 _ => return Err(anyhow::anyhow!("Error getting encryption mode from header")),
297 };
298
299 let mut mode_bytes = [0u8; 2];
300 cursor
301 .read_exact(&mut mode_bytes)
302 .context("Unable to read encryption mode's bytes from header")?;
303
304 let mode = match mode_bytes {
305 [0x0C, 0x01] => Mode::StreamMode,
306 [0x0C, 0x02] => Mode::MemoryMode,
307 _ => return Err(anyhow::anyhow!("Error getting cipher mode from header")),
308 };
309
310 let header_type = HeaderType {
311 version,
312 algorithm,
313 mode,
314 };
315
316 let nonce_len = get_nonce_len(&header_type.algorithm, &header_type.mode);
317 let mut salt = [0u8; 16];
318 let mut nonce = vec![0u8; nonce_len];
319
320 let keyslots: Option<Vec<Keyslot>> = match header_type.version {
321 HeaderVersion::V1 | HeaderVersion::V3 => {
322 cursor
323 .read_exact(&mut salt)
324 .context("Unable to read salt from header")?;
325 cursor
326 .read_exact(&mut [0; 16])
327 .context("Unable to read empty bytes from header")?;
328 cursor
329 .read_exact(&mut nonce)
330 .context("Unable to read nonce from header")?;
331 cursor
332 .read_exact(&mut vec![0u8; 26 - nonce_len])
333 .context("Unable to read final padding from header")?;
334
335 None
336 }
337 HeaderVersion::V2 => {
338 cursor
339 .read_exact(&mut salt)
340 .context("Unable to read salt from header")?;
341 cursor
342 .read_exact(&mut nonce)
343 .context("Unable to read nonce from header")?;
344 cursor
345 .read_exact(&mut vec![0u8; 26 - nonce_len])
346 .context("Unable to read empty bytes from header")?;
347 cursor
348 .read_exact(&mut [0u8; 16])
349 .context("Unable to read final padding from header")?;
350
351 None
352 }
353 HeaderVersion::V4 => {
354 let mut master_key_encrypted = [0u8; 48];
355 let master_key_nonce_len = get_nonce_len(&algorithm, &Mode::MemoryMode);
356 let mut master_key_nonce = vec![0u8; master_key_nonce_len];
357 cursor
358 .read_exact(&mut salt)
359 .context("Unable to read salt from header")?;
360 cursor
361 .read_exact(&mut nonce)
362 .context("Unable to read nonce from header")?;
363 cursor
364 .read_exact(&mut vec![0u8; 26 - nonce_len])
365 .context("Unable to read padding from header")?;
366 cursor
367 .read_exact(&mut master_key_encrypted)
368 .context("Unable to read encrypted master key from header")?;
369 cursor
370 .read_exact(&mut master_key_nonce)
371 .context("Unable to read master key nonce from header")?;
372 cursor
373 .read_exact(&mut vec![0u8; 32 - master_key_nonce_len])
374 .context("Unable to read padding from header")?;
375
376 let keyslot = Keyslot {
377 encrypted_key: master_key_encrypted,
378 hash_algorithm: HashingAlgorithm::Blake3Balloon(4),
379 nonce: master_key_nonce.clone(),
380 salt,
381 };
382 let keyslots = vec![keyslot];
383 Some(keyslots)
384 }
385 HeaderVersion::V5 => {
386 cursor
387 .read_exact(&mut nonce)
388 .context("Unable to read nonce from header")?;
389 cursor
390 .read_exact(&mut vec![0u8; 26 - nonce_len])
391 .context("Unable to read padding from header")?; let keyslot_nonce_len = get_nonce_len(&algorithm, &Mode::MemoryMode);
394
395 let mut keyslots: Vec<Keyslot> = Vec::new();
396 for _ in 0..4 {
397 let mut identifier = [0u8; 2];
398 cursor
399 .read_exact(&mut identifier)
400 .context("Unable to read keyslot identifier from header")?;
401
402 if identifier[..1] != [0xDF] {
403 continue;
404 }
405
406 let mut encrypted_key = [0u8; 48];
407 let mut nonce = vec![0u8; keyslot_nonce_len];
408 let mut padding = vec![0u8; 24 - keyslot_nonce_len];
409 let mut salt = [0u8; SALT_LEN];
410
411 cursor
412 .read_exact(&mut encrypted_key)
413 .context("Unable to read keyslot encrypted bytes from header")?;
414
415 cursor
416 .read_exact(&mut nonce)
417 .context("Unable to read keyslot nonce from header")?;
418
419 cursor
420 .read_exact(&mut padding)
421 .context("Unable to read keyslot padding from header")?;
422
423 cursor
424 .read_exact(&mut salt)
425 .context("Unable to read keyslot salt from header")?;
426
427 cursor
428 .read_exact(&mut [0u8; 6])
429 .context("Unable to read keyslot padding from header")?;
430
431 let hash_algorithm = match identifier {
432 [0xDF, 0xA1] => HashingAlgorithm::Argon2id(1),
433 [0xDF, 0xA2] => HashingAlgorithm::Argon2id(2),
434 [0xDF, 0xA3] => HashingAlgorithm::Argon2id(3),
435 [0xDF, 0xB4] => HashingAlgorithm::Blake3Balloon(4),
436 [0xDF, 0xB5] => HashingAlgorithm::Blake3Balloon(5),
437 _ => return Err(anyhow::anyhow!("Key hashing algorithm not identified")),
438 };
439
440 let keyslot = Keyslot {
441 hash_algorithm,
442 encrypted_key,
443 nonce,
444 salt,
445 };
446
447 keyslots.push(keyslot);
448 }
449
450 Some(keyslots)
451 }
452 };
453
454 let aad = match header_type.version {
455 HeaderVersion::V1 | HeaderVersion::V2 => Vec::<u8>::new(),
456 HeaderVersion::V3 => full_header_bytes.clone(),
457 HeaderVersion::V4 => {
458 let master_key_nonce_len = get_nonce_len(&algorithm, &Mode::MemoryMode);
459 let mut aad = Vec::new();
460
461 aad.extend_from_slice(&full_header_bytes[..48]);
463
464 aad.extend_from_slice(&full_header_bytes[(96 + master_key_nonce_len)..]);
469 aad
470 }
471 HeaderVersion::V5 => {
472 let mut aad = Vec::new();
473 aad.extend_from_slice(&full_header_bytes[..32]);
474 aad
475 }
476 };
477
478 Ok((
479 Header {
480 header_type,
481 nonce,
482 salt: Some(salt),
483 keyslots,
484 },
485 aad,
486 ))
487 }
488
489 fn serialize_algorithm(&self) -> [u8; 2] {
493 match self.header_type.algorithm {
494 Algorithm::XChaCha20Poly1305 => {
495 let info: [u8; 2] = [0x0E, 0x01];
496 info
497 }
498 Algorithm::Aes256Gcm => {
499 let info: [u8; 2] = [0x0E, 0x02];
500 info
501 }
502 Algorithm::DeoxysII256 => {
503 let info: [u8; 2] = [0x0E, 0x03];
504 info
505 }
506 }
507 }
508
509 fn serialize_mode(&self) -> [u8; 2] {
513 match self.header_type.mode {
514 Mode::StreamMode => {
515 let info: [u8; 2] = [0x0C, 0x01];
516 info
517 }
518 Mode::MemoryMode => {
519 let info: [u8; 2] = [0x0C, 0x02];
520 info
521 }
522 }
523 }
524
525 fn serialize_v3(&self, tag: &HeaderTag) -> Vec<u8> {
529 let padding =
530 vec![0u8; 26 - get_nonce_len(&self.header_type.algorithm, &self.header_type.mode)];
531 let mut header_bytes = Vec::<u8>::new();
532 header_bytes.extend_from_slice(&tag.version);
533 header_bytes.extend_from_slice(&tag.algorithm);
534 header_bytes.extend_from_slice(&tag.mode);
535 header_bytes.extend_from_slice(&self.salt.unwrap());
536 header_bytes.extend_from_slice(&[0; 16]);
537 header_bytes.extend_from_slice(&self.nonce);
538 header_bytes.extend_from_slice(&padding);
539 header_bytes
540 }
541
542 fn serialize_v4(&self, tag: &HeaderTag) -> Vec<u8> {
546 let padding =
547 vec![0u8; 26 - get_nonce_len(&self.header_type.algorithm, &self.header_type.mode)];
548 let padding2 =
549 vec![0u8; 32 - get_nonce_len(&self.header_type.algorithm, &Mode::MemoryMode)];
550
551 let keyslot = self.keyslots.clone().unwrap();
552
553 let mut header_bytes = Vec::<u8>::new();
554 header_bytes.extend_from_slice(&tag.version);
555 header_bytes.extend_from_slice(&tag.algorithm);
556 header_bytes.extend_from_slice(&tag.mode);
557 header_bytes.extend_from_slice(&self.salt.unwrap_or(keyslot[0].salt));
558 header_bytes.extend_from_slice(&self.nonce);
559 header_bytes.extend_from_slice(&padding);
560 header_bytes.extend_from_slice(&keyslot[0].encrypted_key);
561 header_bytes.extend_from_slice(&keyslot[0].nonce);
562 header_bytes.extend_from_slice(&padding2);
563 header_bytes
564 }
565
566 fn serialize_v5(&self, tag: &HeaderTag) -> Vec<u8> {
570 let padding =
571 vec![0u8; 26 - get_nonce_len(&self.header_type.algorithm, &self.header_type.mode)];
572
573 let keyslots = self.keyslots.clone().unwrap();
574
575 let mut header_bytes = Vec::<u8>::new();
576
577 header_bytes.extend_from_slice(&tag.version);
579 header_bytes.extend_from_slice(&tag.algorithm);
580 header_bytes.extend_from_slice(&tag.mode);
581 header_bytes.extend_from_slice(&self.nonce);
582 header_bytes.extend_from_slice(&padding);
583 for keyslot in &keyslots {
586 let keyslot_nonce_len = get_nonce_len(&self.header_type.algorithm, &Mode::MemoryMode);
587
588 header_bytes.extend_from_slice(&keyslot.serialize());
589 header_bytes.extend_from_slice(&keyslot.encrypted_key);
590 header_bytes.extend_from_slice(&keyslot.nonce);
591 header_bytes.extend_from_slice(&vec![0u8; 24 - keyslot_nonce_len]);
592 header_bytes.extend_from_slice(&keyslot.salt);
593 header_bytes.extend_from_slice(&[0u8; 6]);
594 }
595
596 for _ in 0..(4 - keyslots.len()) {
597 header_bytes.extend_from_slice(&[0u8; 96]);
598 }
599
600 header_bytes
601 }
602
603 pub fn serialize(&self) -> Result<Vec<u8>> {
622 let tag = self.get_tag();
623 match self.header_type.version {
624 HeaderVersion::V1 => Err(anyhow::anyhow!(
625 "Serializing V1 headers has been deprecated"
626 )),
627 HeaderVersion::V2 => Err(anyhow::anyhow!(
628 "Serializing V2 headers has been deprecated"
629 )),
630 HeaderVersion::V3 => Ok(self.serialize_v3(&tag)),
631 HeaderVersion::V4 => Ok(self.serialize_v4(&tag)),
632 HeaderVersion::V5 => Ok(self.serialize_v5(&tag)),
633 }
634 }
635
636 #[must_use]
637 pub fn get_size(&self) -> u64 {
638 match self.header_type.version {
639 HeaderVersion::V1 | HeaderVersion::V2 | HeaderVersion::V3 => 64,
640 HeaderVersion::V4 => 128,
641 HeaderVersion::V5 => 416,
642 }
643 }
644
645 pub fn create_aad(&self) -> Result<Vec<u8>> {
653 let tag = self.get_tag();
654 match self.header_type.version {
655 HeaderVersion::V1 => Err(anyhow::anyhow!(
656 "Serializing V1 headers has been deprecated"
657 )),
658 HeaderVersion::V2 => Err(anyhow::anyhow!(
659 "Serializing V2 headers has been deprecated"
660 )),
661 HeaderVersion::V3 => Ok(self.serialize_v3(&tag)),
662 HeaderVersion::V4 => {
663 let padding =
664 vec![
665 0u8;
666 26 - get_nonce_len(&self.header_type.algorithm, &self.header_type.mode)
667 ];
668 let master_key_nonce_len =
669 get_nonce_len(&self.header_type.algorithm, &Mode::MemoryMode);
670 let padding2 = vec![0u8; 32 - master_key_nonce_len];
671 let mut header_bytes = Vec::<u8>::new();
672 header_bytes.extend_from_slice(&tag.version);
673 header_bytes.extend_from_slice(&tag.algorithm);
674 header_bytes.extend_from_slice(&tag.mode);
675 header_bytes.extend_from_slice(
676 &self.salt.unwrap_or(
677 self.keyslots.as_ref().ok_or_else(|| {
678 anyhow::anyhow!("Cannot find a salt within the keyslot/header.")
679 })?[0]
680 .salt,
681 ),
682 );
683 header_bytes.extend_from_slice(&self.nonce);
684 header_bytes.extend_from_slice(&padding);
685 header_bytes.extend_from_slice(&padding2);
686 Ok(header_bytes)
687 }
688 HeaderVersion::V5 => {
689 let mut header_bytes = Vec::<u8>::new();
690 header_bytes.extend_from_slice(&tag.version);
691 header_bytes.extend_from_slice(&tag.algorithm);
692 header_bytes.extend_from_slice(&tag.mode);
693 header_bytes.extend_from_slice(&self.nonce);
694 header_bytes.extend_from_slice(&vec![
695 0u8;
696 26 - get_nonce_len(
697 &self.header_type.algorithm,
698 &self.header_type.mode
699 )
700 ]);
701 Ok(header_bytes)
702 }
703 }
704 }
705
706 pub fn write(&self, writer: &mut impl Write) -> Result<()> {
717 let header_bytes = self.serialize()?;
718 writer
719 .write(&header_bytes)
720 .context("Unable to write header")?;
721
722 Ok(())
723 }
724}