/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(), ¶ms.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(), ¶ms.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 | ¶ms.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 | | } |