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