Coverage Report

Created: 2026-06-14 06:21

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/pkcs5-0.7.1/src/pbes2/encryption.rs
Line
Count
Source
1
//! PBES2 encryption.
2
3
use super::{EncryptionScheme, Kdf, Parameters, Pbkdf2Params, Pbkdf2Prf, ScryptParams};
4
use crate::{Error, Result};
5
use cbc::cipher::{
6
    block_padding::Pkcs7, BlockCipher, BlockDecryptMut, BlockEncryptMut, KeyInit, KeyIvInit,
7
};
8
use 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
};
17
use scrypt::scrypt;
18
19
/// Maximum size of a derived encryption key
20
const MAX_KEY_LEN: usize = 32;
21
22
0
fn cbc_encrypt<'a, C: BlockEncryptMut + BlockCipher + KeyInit>(
23
0
    es: EncryptionScheme<'_>,
24
0
    key: EncryptionKey,
25
0
    iv: &[u8],
26
0
    buffer: &'a mut [u8],
27
0
    pos: usize,
28
0
) -> Result<&'a [u8]> {
29
0
    cbc::Encryptor::<C>::new_from_slices(key.as_slice(), iv)
30
0
        .map_err(|_| es.to_alg_params_invalid())?
31
0
        .encrypt_padded_mut::<Pkcs7>(buffer, pos)
32
0
        .map_err(|_| Error::EncryptFailed)
33
0
}
34
35
0
fn cbc_decrypt<'a, C: BlockDecryptMut + BlockCipher + KeyInit>(
36
0
    es: EncryptionScheme<'_>,
37
0
    key: EncryptionKey,
38
0
    iv: &[u8],
39
0
    buffer: &'a mut [u8],
40
0
) -> Result<&'a [u8]> {
41
0
    cbc::Decryptor::<C>::new_from_slices(key.as_slice(), iv)
42
0
        .map_err(|_| es.to_alg_params_invalid())?
43
0
        .decrypt_padded_mut::<Pkcs7>(buffer)
44
0
        .map_err(|_| Error::EncryptFailed)
45
0
}
46
47
0
pub fn encrypt_in_place<'b>(
48
0
    params: &Parameters<'_>,
49
0
    password: impl AsRef<[u8]>,
50
0
    buf: &'b mut [u8],
51
0
    pos: usize,
52
0
) -> Result<&'b [u8]> {
53
0
    let es = params.encryption;
54
0
    let key_size = es.key_size();
55
0
    if key_size > MAX_KEY_LEN {
56
0
        return Err(es.to_alg_params_invalid());
57
0
    }
58
0
    let key = EncryptionKey::derive_from_password(password.as_ref(), &params.kdf, key_size)?;
59
60
0
    match es {
61
0
        EncryptionScheme::Aes128Cbc { iv } => cbc_encrypt::<aes::Aes128Enc>(es, key, iv, buf, pos),
62
0
        EncryptionScheme::Aes192Cbc { iv } => cbc_encrypt::<aes::Aes192Enc>(es, key, iv, buf, pos),
63
0
        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
0
}
72
73
/// Decrypt a message encrypted with PBES2-based key derivation
74
0
pub fn decrypt_in_place<'a>(
75
0
    params: &Parameters<'_>,
76
0
    password: impl AsRef<[u8]>,
77
0
    buf: &'a mut [u8],
78
0
) -> Result<&'a [u8]> {
79
0
    let es = params.encryption;
80
0
    let key = EncryptionKey::derive_from_password(password.as_ref(), &params.kdf, es.key_size())?;
81
82
0
    match es {
83
0
        EncryptionScheme::Aes128Cbc { iv } => cbc_decrypt::<aes::Aes128Dec>(es, key, iv, buf),
84
0
        EncryptionScheme::Aes192Cbc { iv } => cbc_decrypt::<aes::Aes192Dec>(es, key, iv, buf),
85
0
        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
0
}
92
93
/// Encryption key as derived by PBKDF2
94
// TODO(tarcieri): zeroize?
95
struct EncryptionKey {
96
    buffer: [u8; MAX_KEY_LEN],
97
    length: usize,
98
}
99
100
impl EncryptionKey {
101
    /// Derive an encryption key using the supplied PBKDF parameters.
102
0
    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
0
        if let Some(len) = kdf.key_length() {
105
0
            if key_size != len.into() {
106
0
                return Err(kdf.to_alg_params_invalid());
107
0
            }
108
0
        }
109
110
0
        match kdf {
111
0
            Kdf::Pbkdf2(pbkdf2_params) => {
112
0
                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
0
                        return Err(Error::UnsupportedAlgorithm {
122
0
                            oid: super::HMAC_WITH_SHA1_OID,
123
0
                        })
124
                    }
125
0
                    Pbkdf2Prf::HmacWithSha224 => EncryptionKey::derive_with_pbkdf2::<sha2::Sha224>(
126
0
                        password,
127
0
                        pbkdf2_params,
128
0
                        key_size,
129
                    ),
130
0
                    Pbkdf2Prf::HmacWithSha256 => EncryptionKey::derive_with_pbkdf2::<sha2::Sha256>(
131
0
                        password,
132
0
                        pbkdf2_params,
133
0
                        key_size,
134
                    ),
135
0
                    Pbkdf2Prf::HmacWithSha384 => EncryptionKey::derive_with_pbkdf2::<sha2::Sha384>(
136
0
                        password,
137
0
                        pbkdf2_params,
138
0
                        key_size,
139
                    ),
140
0
                    Pbkdf2Prf::HmacWithSha512 => EncryptionKey::derive_with_pbkdf2::<sha2::Sha512>(
141
0
                        password,
142
0
                        pbkdf2_params,
143
0
                        key_size,
144
                    ),
145
                };
146
147
0
                Ok(key)
148
            }
149
0
            Kdf::Scrypt(scrypt_params) => {
150
0
                EncryptionKey::derive_with_scrypt(password, scrypt_params, key_size)
151
            }
152
        }
153
0
    }
154
155
    /// Derive key using PBKDF2.
156
0
    fn derive_with_pbkdf2<D>(password: &[u8], params: &Pbkdf2Params<'_>, length: usize) -> Self
157
0
    where
158
0
        D: CoreProxy,
159
0
        D::Core: Sync
160
0
            + HashMarker
161
0
            + UpdateCore
162
0
            + FixedOutputCore
163
0
            + BufferKindUser<BufferKind = Eager>
164
0
            + Default
165
0
            + Clone,
166
0
        <D::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
167
0
        Le<<D::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
168
    {
169
0
        let mut buffer = [0u8; MAX_KEY_LEN];
170
171
0
        pbkdf2_hmac::<D>(
172
0
            password,
173
0
            params.salt,
174
0
            params.iteration_count,
175
0
            &mut buffer[..length],
176
        );
177
178
0
        Self { buffer, length }
179
0
    }
Unexecuted instantiation: <pkcs5::pbes2::encryption::EncryptionKey>::derive_with_pbkdf2::<digest::core_api::wrapper::CoreWrapper<digest::core_api::ct_variable::CtVariableCoreWrapper<sha2::core_api::Sha256VarCore, typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UTerm, typenum::bit::B1>, typenum::bit::B0>, typenum::bit::B0>, typenum::bit::B0>, typenum::bit::B0>, typenum::bit::B0>, sha2::OidSha256>>>
Unexecuted instantiation: <pkcs5::pbes2::encryption::EncryptionKey>::derive_with_pbkdf2::<digest::core_api::wrapper::CoreWrapper<digest::core_api::ct_variable::CtVariableCoreWrapper<sha2::core_api::Sha256VarCore, typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UTerm, typenum::bit::B1>, typenum::bit::B1>, typenum::bit::B1>, typenum::bit::B0>, typenum::bit::B0>, sha2::OidSha224>>>
Unexecuted instantiation: <pkcs5::pbes2::encryption::EncryptionKey>::derive_with_pbkdf2::<digest::core_api::wrapper::CoreWrapper<digest::core_api::ct_variable::CtVariableCoreWrapper<sha2::core_api::Sha512VarCore, typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UTerm, typenum::bit::B1>, typenum::bit::B0>, typenum::bit::B0>, typenum::bit::B0>, typenum::bit::B0>, typenum::bit::B0>, typenum::bit::B0>, sha2::OidSha512>>>
Unexecuted instantiation: <pkcs5::pbes2::encryption::EncryptionKey>::derive_with_pbkdf2::<digest::core_api::wrapper::CoreWrapper<digest::core_api::ct_variable::CtVariableCoreWrapper<sha2::core_api::Sha512VarCore, typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UTerm, typenum::bit::B1>, typenum::bit::B1>, typenum::bit::B0>, typenum::bit::B0>, typenum::bit::B0>, typenum::bit::B0>, sha2::OidSha384>>>
180
181
    /// Derive key using scrypt.
182
0
    fn derive_with_scrypt(
183
0
        password: &[u8],
184
0
        params: &ScryptParams<'_>,
185
0
        length: usize,
186
0
    ) -> Result<Self> {
187
0
        let mut buffer = [0u8; MAX_KEY_LEN];
188
0
        scrypt(
189
0
            password,
190
0
            params.salt,
191
0
            &params.try_into()?,
192
0
            &mut buffer[..length],
193
        )
194
0
        .map_err(|_| Error::AlgorithmParametersInvalid {
195
            oid: super::SCRYPT_OID,
196
0
        })?;
197
198
0
        Ok(Self { buffer, length })
199
0
    }
200
201
    /// Get the key material as a slice
202
0
    fn as_slice(&self) -> &[u8] {
203
0
        &self.buffer[..self.length]
204
0
    }
205
}