1use crate::{Error, KdfAlg, Result};
6use encoding::{CheckedSum, Decode, Encode, Reader, Writer};
7
8#[cfg(feature = "alloc")]
9use alloc::vec::Vec;
10
11#[cfg(feature = "encryption")]
12use {crate::Cipher, bcrypt_pbkdf::bcrypt_pbkdf, rand_core::CryptoRngCore, zeroize::Zeroizing};
13
14#[cfg(feature = "encryption")]
16const DEFAULT_BCRYPT_ROUNDS: u32 = 16;
17
18#[cfg(feature = "encryption")]
20const DEFAULT_SALT_SIZE: usize = 16;
21
22#[derive(Clone, Debug, Eq, PartialEq)]
24#[non_exhaustive]
25pub enum Kdf {
26 None,
28
29 #[cfg(feature = "alloc")]
31 Bcrypt {
32 salt: Vec<u8>,
34
35 rounds: u32,
37 },
38}
39
40impl Kdf {
41 #[cfg(feature = "encryption")]
43 pub fn new(algorithm: KdfAlg, rng: &mut impl CryptoRngCore) -> Result<Self> {
44 let mut salt = vec![0u8; DEFAULT_SALT_SIZE];
45 rng.fill_bytes(&mut salt);
46
47 match algorithm {
48 KdfAlg::None => {
49 Err(Error::AlgorithmUnknown)
51 }
52 KdfAlg::Bcrypt => Ok(Kdf::Bcrypt {
53 salt,
54 rounds: DEFAULT_BCRYPT_ROUNDS,
55 }),
56 }
57 }
58
59 pub fn algorithm(&self) -> KdfAlg {
61 match self {
62 Self::None => KdfAlg::None,
63 #[cfg(feature = "alloc")]
64 Self::Bcrypt { .. } => KdfAlg::Bcrypt,
65 }
66 }
67
68 #[cfg(feature = "encryption")]
70 pub fn derive(&self, password: impl AsRef<[u8]>, output: &mut [u8]) -> Result<()> {
71 match self {
72 Kdf::None => Err(Error::Decrypted),
73 Kdf::Bcrypt { salt, rounds } => {
74 bcrypt_pbkdf(password, salt, *rounds, output).map_err(|_| Error::Crypto)?;
75 Ok(())
76 }
77 }
78 }
79
80 #[cfg(feature = "encryption")]
84 pub fn derive_key_and_iv(
85 &self,
86 cipher: Cipher,
87 password: impl AsRef<[u8]>,
88 ) -> Result<(Zeroizing<Vec<u8>>, Vec<u8>)> {
89 let (key_size, iv_size) = cipher.key_and_iv_size().ok_or(Error::Decrypted)?;
90 let okm_size = key_size
91 .checked_add(iv_size)
92 .ok_or(encoding::Error::Length)?;
93
94 let mut okm = Zeroizing::new(vec![0u8; okm_size]);
95 self.derive(password, &mut okm)?;
96 let iv = okm.split_off(key_size);
97 Ok((okm, iv))
98 }
99
100 pub fn is_none(&self) -> bool {
102 self == &Self::None
103 }
104
105 pub fn is_some(&self) -> bool {
107 !self.is_none()
108 }
109
110 #[cfg(feature = "alloc")]
112 pub fn is_bcrypt(&self) -> bool {
113 matches!(self, Self::Bcrypt { .. })
114 }
115}
116
117impl Default for Kdf {
118 fn default() -> Self {
119 Self::None
120 }
121}
122
123impl Decode for Kdf {
124 type Error = Error;
125
126 fn decode(reader: &mut impl Reader) -> Result<Self> {
127 match KdfAlg::decode(reader)? {
128 KdfAlg::None => {
129 if usize::decode(reader)? == 0 {
130 Ok(Self::None)
131 } else {
132 Err(Error::AlgorithmUnknown)
133 }
134 }
135 KdfAlg::Bcrypt => {
136 #[cfg(not(feature = "alloc"))]
137 return Err(Error::AlgorithmUnknown);
138
139 #[cfg(feature = "alloc")]
140 reader.read_prefixed(|reader| {
141 Ok(Self::Bcrypt {
142 salt: Vec::decode(reader)?,
143 rounds: u32::decode(reader)?,
144 })
145 })
146 }
147 }
148 }
149}
150
151impl Encode for Kdf {
152 fn encoded_len(&self) -> encoding::Result<usize> {
153 let kdfopts_prefixed_len = match self {
154 Self::None => 4,
155 #[cfg(feature = "alloc")]
156 Self::Bcrypt { salt, .. } => [12, salt.len()].checked_sum()?,
157 };
158
159 [self.algorithm().encoded_len()?, kdfopts_prefixed_len].checked_sum()
160 }
161
162 fn encode(&self, writer: &mut impl Writer) -> encoding::Result<()> {
163 self.algorithm().encode(writer)?;
164
165 match self {
166 Self::None => 0usize.encode(writer)?,
167 #[cfg(feature = "alloc")]
168 Self::Bcrypt { salt, rounds } => {
169 [8, salt.len()].checked_sum()?.encode(writer)?;
170 salt.encode(writer)?;
171 rounds.encode(writer)?
172 }
173 }
174
175 Ok(())
176 }
177}