Skip to main content

bitwarden_crypto/store/
cipher_suite.rs

1use crate::Kdf;
2
3/// The set of cryptographic algorithms a [`super::KeyStore`] is allowed to use, determined by the
4/// environment it operates in.
5///
6/// It is set once when the store is constructed (see [`super::KeyStore::set_cipher_suite`]) and
7/// read through [`super::KeyStoreContext`] by operations that must pick a compliant algorithm, such
8/// as the KDF for a new account.
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
10pub enum CipherSuite {
11    /// The default suite, using the modern recommended algorithms (e.g. Argon2id).
12    #[default]
13    Standard,
14    /// The FIPS-compliant suite required in government (FedRAMP) environments, restricted to
15    /// FIPS-approved algorithms (e.g. PBKDF2).
16    Fips,
17}
18
19impl CipherSuite {
20    /// Returns the [`CipherSuite`] for the current environment, given whether the client is in
21    /// Gov Mode (FedRAMP).
22    pub fn from_gov_mode(gov_mode: bool) -> Self {
23        if gov_mode {
24            CipherSuite::Fips
25        } else {
26            CipherSuite::Standard
27        }
28    }
29
30    /// Returns the KDF a new account should use under this suite.
31    ///
32    /// [`CipherSuite::Fips`] uses the FIPS-approved PBKDF2; [`CipherSuite::Standard`] uses the
33    /// modern Argon2id default.
34    pub fn default_kdf_for_new_account(self) -> Kdf {
35        match self {
36            CipherSuite::Standard => Kdf::default_argon2(),
37            CipherSuite::Fips => Kdf::default_pbkdf2(),
38        }
39    }
40
41    /// Returns whether the given KDF is allowed under this suite.
42    ///
43    /// Under [`CipherSuite::Fips`] only PBKDF2 is FIPS-approved; under [`CipherSuite::Standard`]
44    /// every supported KDF is allowed.
45    pub fn is_kdf_compliant(self, kdf: &Kdf) -> bool {
46        match self {
47            CipherSuite::Standard => true,
48            CipherSuite::Fips => matches!(kdf, Kdf::PBKDF2 { .. }),
49        }
50    }
51}
52
53#[cfg(test)]
54mod tests {
55    use super::*;
56
57    #[test]
58    fn default_is_standard() {
59        assert_eq!(CipherSuite::default(), CipherSuite::Standard);
60    }
61
62    #[test]
63    fn from_gov_mode_maps_to_suite() {
64        assert_eq!(CipherSuite::from_gov_mode(false), CipherSuite::Standard);
65        assert_eq!(CipherSuite::from_gov_mode(true), CipherSuite::Fips);
66    }
67
68    #[test]
69    fn standard_uses_argon2_for_new_account() {
70        assert!(matches!(
71            CipherSuite::Standard.default_kdf_for_new_account(),
72            Kdf::Argon2id { .. }
73        ));
74    }
75
76    #[test]
77    fn fips_uses_pbkdf2_for_new_account() {
78        assert!(matches!(
79            CipherSuite::Fips.default_kdf_for_new_account(),
80            Kdf::PBKDF2 { .. }
81        ));
82    }
83
84    #[test]
85    fn standard_allows_any_kdf() {
86        assert!(CipherSuite::Standard.is_kdf_compliant(&Kdf::default_argon2()));
87        assert!(CipherSuite::Standard.is_kdf_compliant(&Kdf::default_pbkdf2()));
88    }
89
90    #[test]
91    fn fips_allows_only_pbkdf2() {
92        assert!(CipherSuite::Fips.is_kdf_compliant(&Kdf::default_pbkdf2()));
93        assert!(!CipherSuite::Fips.is_kdf_compliant(&Kdf::default_argon2()));
94    }
95}