pkcs5/pbes2/
encryption.rs

1//! PBES2 encryption.
2
3use super::{EncryptionScheme, Kdf, Parameters, Pbkdf2Params, Pbkdf2Prf, ScryptParams};
4use crate::{Error, Result};
5use cbc::cipher::{
6    block_padding::Pkcs7, BlockCipher, BlockDecryptMut, BlockEncryptMut, KeyInit, KeyIvInit,
7};
8use pbkdf2::{
9    hmac::digest::{
10        block_buffer::Eager,
11        core_api::{BlockSizeUser, BufferKindUser, CoreProxy, FixedOutputCore, UpdateCore},
12        generic_array::typenum::{IsLess, Le, NonZero, U256},
13        HashMarker,
14    },
15    pbkdf2_hmac,
16};
17use scrypt::scrypt;
18
19/// Maximum size of a derived encryption key
20const MAX_KEY_LEN: usize = 32;
21
22fn cbc_encrypt<'a, C: BlockEncryptMut + BlockCipher + KeyInit>(
23    es: EncryptionScheme<'_>,
24    key: EncryptionKey,
25    iv: &[u8],
26    buffer: &'a mut [u8],
27    pos: usize,
28) -> Result<&'a [u8]> {
29    cbc::Encryptor::<C>::new_from_slices(key.as_slice(), iv)
30        .map_err(|_| es.to_alg_params_invalid())?
31        .encrypt_padded_mut::<Pkcs7>(buffer, pos)
32        .map_err(|_| Error::EncryptFailed)
33}
34
35fn cbc_decrypt<'a, C: BlockDecryptMut + BlockCipher + KeyInit>(
36    es: EncryptionScheme<'_>,
37    key: EncryptionKey,
38    iv: &[u8],
39    buffer: &'a mut [u8],
40) -> Result<&'a [u8]> {
41    cbc::Decryptor::<C>::new_from_slices(key.as_slice(), iv)
42        .map_err(|_| es.to_alg_params_invalid())?
43        .decrypt_padded_mut::<Pkcs7>(buffer)
44        .map_err(|_| Error::EncryptFailed)
45}
46
47pub fn encrypt_in_place<'b>(
48    params: &Parameters<'_>,
49    password: impl AsRef<[u8]>,
50    buf: &'b mut [u8],
51    pos: usize,
52) -> Result<&'b [u8]> {
53    let es = params.encryption;
54    let key_size = es.key_size();
55    if key_size > MAX_KEY_LEN {
56        return Err(es.to_alg_params_invalid());
57    }
58    let key = EncryptionKey::derive_from_password(password.as_ref(), &params.kdf, key_size)?;
59
60    match es {
61        EncryptionScheme::Aes128Cbc { iv } => cbc_encrypt::<aes::Aes128Enc>(es, key, iv, buf, pos),
62        EncryptionScheme::Aes192Cbc { iv } => cbc_encrypt::<aes::Aes192Enc>(es, key, iv, buf, pos),
63        EncryptionScheme::Aes256Cbc { iv } => cbc_encrypt::<aes::Aes256Enc>(es, key, iv, buf, pos),
64        #[cfg(feature = "3des")]
65        EncryptionScheme::DesEde3Cbc { iv } => cbc_encrypt::<des::TdesEde3>(es, key, iv, buf, pos),
66        #[cfg(feature = "des-insecure")]
67        EncryptionScheme::DesCbc { .. } => Err(Error::UnsupportedAlgorithm {
68            oid: super::DES_CBC_OID,
69        }),
70    }
71}
72
73/// Decrypt a message encrypted with PBES2-based key derivation
74pub fn decrypt_in_place<'a>(
75    params: &Parameters<'_>,
76    password: impl AsRef<[u8]>,
77    buf: &'a mut [u8],
78) -> Result<&'a [u8]> {
79    let es = params.encryption;
80    let key = EncryptionKey::derive_from_password(password.as_ref(), &params.kdf, es.key_size())?;
81
82    match es {
83        EncryptionScheme::Aes128Cbc { iv } => cbc_decrypt::<aes::Aes128Dec>(es, key, iv, buf),
84        EncryptionScheme::Aes192Cbc { iv } => cbc_decrypt::<aes::Aes192Dec>(es, key, iv, buf),
85        EncryptionScheme::Aes256Cbc { iv } => cbc_decrypt::<aes::Aes256Dec>(es, key, iv, buf),
86        #[cfg(feature = "3des")]
87        EncryptionScheme::DesEde3Cbc { iv } => cbc_decrypt::<des::TdesEde3>(es, key, iv, buf),
88        #[cfg(feature = "des-insecure")]
89        EncryptionScheme::DesCbc { iv } => cbc_decrypt::<des::Des>(es, key, iv, buf),
90    }
91}
92
93/// Encryption key as derived by PBKDF2
94// TODO(tarcieri): zeroize?
95struct EncryptionKey {
96    buffer: [u8; MAX_KEY_LEN],
97    length: usize,
98}
99
100impl EncryptionKey {
101    /// Derive an encryption key using the supplied PBKDF parameters.
102    pub fn derive_from_password(password: &[u8], kdf: &Kdf<'_>, key_size: usize) -> Result<Self> {
103        // if the kdf params defined a key length, ensure it matches the required key size
104        if let Some(len) = kdf.key_length() {
105            if key_size != len.into() {
106                return Err(kdf.to_alg_params_invalid());
107            }
108        }
109
110        match kdf {
111            Kdf::Pbkdf2(pbkdf2_params) => {
112                let key = match pbkdf2_params.prf {
113                    #[cfg(feature = "sha1-insecure")]
114                    Pbkdf2Prf::HmacWithSha1 => EncryptionKey::derive_with_pbkdf2::<sha1::Sha1>(
115                        password,
116                        pbkdf2_params,
117                        key_size,
118                    ),
119                    #[cfg(not(feature = "sha1-insecure"))]
120                    Pbkdf2Prf::HmacWithSha1 => {
121                        return Err(Error::UnsupportedAlgorithm {
122                            oid: super::HMAC_WITH_SHA1_OID,
123                        })
124                    }
125                    Pbkdf2Prf::HmacWithSha224 => EncryptionKey::derive_with_pbkdf2::<sha2::Sha224>(
126                        password,
127                        pbkdf2_params,
128                        key_size,
129                    ),
130                    Pbkdf2Prf::HmacWithSha256 => EncryptionKey::derive_with_pbkdf2::<sha2::Sha256>(
131                        password,
132                        pbkdf2_params,
133                        key_size,
134                    ),
135                    Pbkdf2Prf::HmacWithSha384 => EncryptionKey::derive_with_pbkdf2::<sha2::Sha384>(
136                        password,
137                        pbkdf2_params,
138                        key_size,
139                    ),
140                    Pbkdf2Prf::HmacWithSha512 => EncryptionKey::derive_with_pbkdf2::<sha2::Sha512>(
141                        password,
142                        pbkdf2_params,
143                        key_size,
144                    ),
145                };
146
147                Ok(key)
148            }
149            Kdf::Scrypt(scrypt_params) => {
150                EncryptionKey::derive_with_scrypt(password, scrypt_params, key_size)
151            }
152        }
153    }
154
155    /// Derive key using PBKDF2.
156    fn derive_with_pbkdf2<D>(password: &[u8], params: &Pbkdf2Params<'_>, length: usize) -> Self
157    where
158        D: CoreProxy,
159        D::Core: Sync
160            + HashMarker
161            + UpdateCore
162            + FixedOutputCore
163            + BufferKindUser<BufferKind = Eager>
164            + Default
165            + Clone,
166        <D::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
167        Le<<D::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
168    {
169        let mut buffer = [0u8; MAX_KEY_LEN];
170
171        pbkdf2_hmac::<D>(
172            password,
173            params.salt,
174            params.iteration_count,
175            &mut buffer[..length],
176        );
177
178        Self { buffer, length }
179    }
180
181    /// Derive key using scrypt.
182    fn derive_with_scrypt(
183        password: &[u8],
184        params: &ScryptParams<'_>,
185        length: usize,
186    ) -> Result<Self> {
187        let mut buffer = [0u8; MAX_KEY_LEN];
188        scrypt(
189            password,
190            params.salt,
191            &params.try_into()?,
192            &mut buffer[..length],
193        )
194        .map_err(|_| Error::AlgorithmParametersInvalid {
195            oid: super::SCRYPT_OID,
196        })?;
197
198        Ok(Self { buffer, length })
199    }
200
201    /// Get the key material as a slice
202    fn as_slice(&self) -> &[u8] {
203        &self.buffer[..self.length]
204    }
205}