Skip to main content

zip/format/
aes.rs

1//! AES related specifications
2
3use core::fmt::Display;
4
5/// The encryption specification used to encrypt a file with AES.
6///
7/// According to the [specification](https://www.winzip.com/win/en/aes_info.html#winzip11) AE-2
8/// does not make use of the CRC check.
9#[derive(Copy, Clone, Debug, Eq, PartialEq)]
10#[repr(u16)]
11pub enum AesVendorVersion {
12    /// Ae1 version
13    Ae1 = 0x0001,
14    /// Ae2 version
15    Ae2 = 0x0002,
16}
17
18impl AesVendorVersion {
19    /// As u16
20    #[must_use]
21    pub const fn as_u16(self) -> u16 {
22        self as u16
23    }
24
25    /// Returns `true` if the data is encrypted using AE2.
26    #[must_use]
27    pub const fn is_ae2_encrypted(&self) -> bool {
28        matches!(self, AesVendorVersion::Ae2)
29    }
30}
31
32impl TryFrom<u16> for AesVendorVersion {
33    type Error = &'static str;
34
35    fn try_from(value: u16) -> Result<Self, Self::Error> {
36        let aes_vendor_version = match value {
37            0x0001 => AesVendorVersion::Ae1,
38            0x0002 => AesVendorVersion::Ae2,
39            _ => return Err("Invalid AES vendor version"),
40        };
41        Ok(aes_vendor_version)
42    }
43}
44
45impl From<AesVendorVersion> for u16 {
46    fn from(value: AesVendorVersion) -> Self {
47        value.as_u16()
48    }
49}
50
51/// AES variant used.
52#[derive(Copy, Clone, Debug, Eq, PartialEq)]
53#[cfg_attr(feature = "_arbitrary", derive(arbitrary::Arbitrary))]
54#[repr(u8)]
55pub enum AesMode {
56    /// 128-bit AES encryption.
57    Aes128 = 0x01,
58    /// 192-bit AES encryption.
59    Aes192 = 0x02,
60    /// 256-bit AES encryption.
61    Aes256 = 0x03,
62}
63
64impl AesMode {
65    /// As u8
66    #[must_use]
67    pub const fn as_u8(self) -> u8 {
68        self as u8
69    }
70}
71
72impl Display for AesMode {
73    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
74        match self {
75            Self::Aes128 => write!(f, "AES-128"),
76            Self::Aes192 => write!(f, "AES-192"),
77            Self::Aes256 => write!(f, "AES-256"),
78        }
79    }
80}
81
82impl TryFrom<u8> for AesMode {
83    type Error = &'static str;
84
85    fn try_from(value: u8) -> Result<Self, Self::Error> {
86        let mode = match value {
87            0x01 => AesMode::Aes128,
88            0x02 => AesMode::Aes192,
89            0x03 => AesMode::Aes256,
90            _ => return Err("Invalid AES encryption strength"),
91        };
92        Ok(mode)
93    }
94}
95
96impl AesMode {
97    /// Length of the salt for the given AES mode.
98    #[must_use]
99    pub const fn salt_length(&self) -> usize {
100        self.key_length() / 2
101    }
102
103    /// Length of the key for the given AES mode.
104    #[must_use]
105    pub const fn key_length(&self) -> usize {
106        match self {
107            Self::Aes128 => 16,
108            Self::Aes192 => 24,
109            Self::Aes256 => 32,
110        }
111    }
112}