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