1use super::{CryptoError, CryptoProvider, CryptoResult};
2use crate::v3::{AuthProtocol, PrivProtocol};
3
4pub struct RustCryptoProvider;
9
10macro_rules! dispatch_auth {
13 ($protocol:expr, $fn:ident, $($arg:expr),*) => {
14 match $protocol {
15 AuthProtocol::Md5 => $fn::<md5::Md5>($($arg),*),
16 AuthProtocol::Sha1 => $fn::<sha1::Sha1>($($arg),*),
17 AuthProtocol::Sha224 => $fn::<sha2::Sha224>($($arg),*),
18 AuthProtocol::Sha256 => $fn::<sha2::Sha256>($($arg),*),
19 AuthProtocol::Sha384 => $fn::<sha2::Sha384>($($arg),*),
20 AuthProtocol::Sha512 => $fn::<sha2::Sha512>($($arg),*),
21 }
22 };
23}
24
25impl CryptoProvider for RustCryptoProvider {
26 fn hash(&self, protocol: AuthProtocol, data: &[u8]) -> CryptoResult<Vec<u8>> {
27 Ok(dispatch_auth!(protocol, hash_impl, data))
28 }
29
30 fn password_to_key(&self, protocol: AuthProtocol, password: &[u8]) -> CryptoResult<Vec<u8>> {
31 const EXPANSION_SIZE: usize = 1_048_576; Ok(dispatch_auth!(
33 protocol,
34 password_to_key_impl,
35 password,
36 EXPANSION_SIZE
37 ))
38 }
39
40 fn localize_key(
41 &self,
42 protocol: AuthProtocol,
43 master_key: &[u8],
44 engine_id: &[u8],
45 ) -> CryptoResult<Vec<u8>> {
46 Ok(dispatch_auth!(
47 protocol,
48 localize_key_impl,
49 master_key,
50 engine_id
51 ))
52 }
53
54 fn compute_hmac(
55 &self,
56 protocol: AuthProtocol,
57 key: &[u8],
58 slices: &[&[u8]],
59 truncate_len: usize,
60 ) -> CryptoResult<Vec<u8>> {
61 Ok(dispatch_auth!(
62 protocol,
63 compute_hmac_impl,
64 key,
65 slices,
66 truncate_len
67 ))
68 }
69
70 fn encrypt(
71 &self,
72 protocol: PrivProtocol,
73 key: &[u8],
74 iv: &[u8],
75 data: &mut [u8],
76 ) -> CryptoResult<()> {
77 match protocol {
78 PrivProtocol::Des => encrypt_des_cbc(key, iv, data),
79 PrivProtocol::Des3 => encrypt_des3_cbc(key, iv, data),
80 PrivProtocol::Aes128 | PrivProtocol::Aes192 | PrivProtocol::Aes256 => {
81 encrypt_aes_cfb(key, iv, data)
82 }
83 }
84 }
85
86 fn decrypt(
87 &self,
88 protocol: PrivProtocol,
89 key: &[u8],
90 iv: &[u8],
91 data: &mut [u8],
92 ) -> CryptoResult<()> {
93 match protocol {
94 PrivProtocol::Des => decrypt_des_cbc(key, iv, data),
95 PrivProtocol::Des3 => decrypt_des3_cbc(key, iv, data),
96 PrivProtocol::Aes128 | PrivProtocol::Aes192 | PrivProtocol::Aes256 => {
97 decrypt_aes_cfb(key, iv, data)
98 }
99 }
100 }
101}
102
103use digest::core_api::BlockSizeUser;
106use digest::{Digest, KeyInit, Mac, OutputSizeUser};
107
108fn hash_impl<D>(data: &[u8]) -> Vec<u8>
109where
110 D: Digest + Default,
111{
112 let mut hasher = D::new();
113 hasher.update(data);
114 hasher.finalize().to_vec()
115}
116
117fn password_to_key_impl<D>(password: &[u8], expansion_size: usize) -> Vec<u8>
118where
119 D: Digest + Default,
120{
121 if password.is_empty() {
122 return vec![0u8; <D as OutputSizeUser>::output_size()];
123 }
124
125 let mut hasher = D::new();
126
127 let mut buf = [0u8; 64];
128 let password_len = password.len();
129 let mut password_index = 0;
130 let mut count = 0;
131
132 while count < expansion_size {
133 for byte in &mut buf {
134 *byte = password[password_index];
135 password_index = (password_index + 1) % password_len;
136 }
137 hasher.update(buf);
138 count += 64;
139 }
140
141 hasher.finalize().to_vec()
142}
143
144fn localize_key_impl<D>(master_key: &[u8], engine_id: &[u8]) -> Vec<u8>
145where
146 D: Digest + Default,
147{
148 let mut hasher = D::new();
149 hasher.update(master_key);
150 hasher.update(engine_id);
151 hasher.update(master_key);
152 hasher.finalize().to_vec()
153}
154
155fn compute_hmac_impl<D>(key: &[u8], slices: &[&[u8]], truncate_len: usize) -> Vec<u8>
156where
157 D: Digest + BlockSizeUser + Clone,
158{
159 use hmac::SimpleHmac;
160
161 let mut mac =
162 <SimpleHmac<D> as KeyInit>::new_from_slice(key).expect("HMAC can take key of any size");
163 for slice in slices {
164 Mac::update(&mut mac, slice);
165 }
166 let result = mac.finalize().into_bytes();
167 result[..truncate_len].to_vec()
168}
169
170fn encrypt_des_cbc(key: &[u8], iv: &[u8], data: &mut [u8]) -> CryptoResult<()> {
173 use cbc::cipher::{BlockEncryptMut, KeyIvInit};
174 type DesCbc = cbc::Encryptor<des::Des>;
175
176 let cipher = DesCbc::new_from_slices(key, iv).map_err(|_| {
177 tracing::debug!(target: "async_snmp::crypto", "DES encryption failed: invalid key length");
178 CryptoError::InvalidKeyLength
179 })?;
180 let len = data.len();
181 cipher
182 .encrypt_padded_mut::<cbc::cipher::block_padding::NoPadding>(data, len)
183 .map_err(|_| {
184 tracing::debug!(target: "async_snmp::crypto", "DES encryption failed: cipher error");
185 CryptoError::CipherError
186 })?;
187 Ok(())
188}
189
190fn decrypt_des_cbc(key: &[u8], iv: &[u8], data: &mut [u8]) -> CryptoResult<()> {
191 use cbc::cipher::{BlockDecryptMut, KeyIvInit};
192 type DesCbc = cbc::Decryptor<des::Des>;
193
194 let cipher = DesCbc::new_from_slices(key, iv).map_err(|_| {
195 tracing::debug!(target: "async_snmp::crypto", "DES decryption failed: invalid key length");
196 CryptoError::InvalidKeyLength
197 })?;
198 cipher
199 .decrypt_padded_mut::<cbc::cipher::block_padding::NoPadding>(data)
200 .map_err(|_| {
201 tracing::debug!(target: "async_snmp::crypto", "DES decryption failed: cipher error");
202 CryptoError::CipherError
203 })?;
204 Ok(())
205}
206
207fn encrypt_des3_cbc(key: &[u8], iv: &[u8], data: &mut [u8]) -> CryptoResult<()> {
208 use cbc::cipher::{BlockEncryptMut, KeyIvInit};
209 type Des3Cbc = cbc::Encryptor<des::TdesEde3>;
210
211 let cipher = Des3Cbc::new_from_slices(key, iv).map_err(|_| {
212 tracing::debug!(target: "async_snmp::crypto", "3DES encryption failed: invalid key length");
213 CryptoError::InvalidKeyLength
214 })?;
215 let len = data.len();
216 cipher
217 .encrypt_padded_mut::<cbc::cipher::block_padding::NoPadding>(data, len)
218 .map_err(|_| {
219 tracing::debug!(target: "async_snmp::crypto", "3DES encryption failed: cipher error");
220 CryptoError::CipherError
221 })?;
222 Ok(())
223}
224
225fn decrypt_des3_cbc(key: &[u8], iv: &[u8], data: &mut [u8]) -> CryptoResult<()> {
226 use cbc::cipher::{BlockDecryptMut, KeyIvInit};
227 type Des3Cbc = cbc::Decryptor<des::TdesEde3>;
228
229 let cipher = Des3Cbc::new_from_slices(key, iv).map_err(|_| {
230 tracing::debug!(target: "async_snmp::crypto", "3DES decryption failed: invalid key length");
231 CryptoError::InvalidKeyLength
232 })?;
233 cipher
234 .decrypt_padded_mut::<cbc::cipher::block_padding::NoPadding>(data)
235 .map_err(|_| {
236 tracing::debug!(target: "async_snmp::crypto", "3DES decryption failed: cipher error");
237 CryptoError::CipherError
238 })?;
239 Ok(())
240}
241
242fn encrypt_aes_cfb(key: &[u8], iv: &[u8], data: &mut [u8]) -> CryptoResult<()> {
243 use aes::{Aes128, Aes192, Aes256};
244 use cfb_mode::cipher::{AsyncStreamCipher, KeyIvInit};
245
246 match key.len() {
247 16 => {
248 type Aes128Cfb = cfb_mode::Encryptor<Aes128>;
249 let cipher = Aes128Cfb::new_from_slices(key, iv).map_err(|_| {
250 tracing::debug!(target: "async_snmp::crypto", "AES-128 encryption failed: invalid key length");
251 CryptoError::InvalidKeyLength
252 })?;
253 cipher.encrypt(data);
254 }
255 24 => {
256 type Aes192Cfb = cfb_mode::Encryptor<Aes192>;
257 let cipher = Aes192Cfb::new_from_slices(key, iv).map_err(|_| {
258 tracing::debug!(target: "async_snmp::crypto", "AES-192 encryption failed: invalid key length");
259 CryptoError::InvalidKeyLength
260 })?;
261 cipher.encrypt(data);
262 }
263 32 => {
264 type Aes256Cfb = cfb_mode::Encryptor<Aes256>;
265 let cipher = Aes256Cfb::new_from_slices(key, iv).map_err(|_| {
266 tracing::debug!(target: "async_snmp::crypto", "AES-256 encryption failed: invalid key length");
267 CryptoError::InvalidKeyLength
268 })?;
269 cipher.encrypt(data);
270 }
271 key_len => {
272 tracing::debug!(target: "async_snmp::crypto", { key_len }, "AES encryption failed: unsupported key length");
273 return Err(CryptoError::InvalidKeyLength);
274 }
275 }
276 Ok(())
277}
278
279fn decrypt_aes_cfb(key: &[u8], iv: &[u8], data: &mut [u8]) -> CryptoResult<()> {
280 use aes::{Aes128, Aes192, Aes256};
281 use cfb_mode::cipher::{AsyncStreamCipher, KeyIvInit};
282
283 match key.len() {
284 16 => {
285 type Aes128Cfb = cfb_mode::Decryptor<Aes128>;
286 let cipher = Aes128Cfb::new_from_slices(key, iv).map_err(|_| {
287 tracing::debug!(target: "async_snmp::crypto", "AES-128 decryption failed: invalid key length");
288 CryptoError::InvalidKeyLength
289 })?;
290 cipher.decrypt(data);
291 }
292 24 => {
293 type Aes192Cfb = cfb_mode::Decryptor<Aes192>;
294 let cipher = Aes192Cfb::new_from_slices(key, iv).map_err(|_| {
295 tracing::debug!(target: "async_snmp::crypto", "AES-192 decryption failed: invalid key length");
296 CryptoError::InvalidKeyLength
297 })?;
298 cipher.decrypt(data);
299 }
300 32 => {
301 type Aes256Cfb = cfb_mode::Decryptor<Aes256>;
302 let cipher = Aes256Cfb::new_from_slices(key, iv).map_err(|_| {
303 tracing::debug!(target: "async_snmp::crypto", "AES-256 decryption failed: invalid key length");
304 CryptoError::InvalidKeyLength
305 })?;
306 cipher.decrypt(data);
307 }
308 key_len => {
309 tracing::debug!(target: "async_snmp::crypto", { key_len }, "AES decryption failed: unsupported key length");
310 return Err(CryptoError::InvalidKeyLength);
311 }
312 }
313 Ok(())
314}