diff --git a/Cargo.toml b/Cargo.toml
index c7ffb42..1837cee 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "snmp2"
-version = "0.4.14"
+version = "0.4.15"
edition = "2021"
description = "SNMP v1/v2/v3 sync/async client library with traps and MIB support"
authors = ["Serhij S.
"]
@@ -21,12 +21,29 @@ snmptools = { version = "^0.1.2", optional = true }
tokio = { version = "1.47", features = ["net"], optional = true }
openssl = { version = "0.10", optional = true }
+md-5 = { version = "0.10", optional = true }
+sha1 = { version = "0.10", optional = true }
+digest = { version = "0.10", optional = true }
+sha2 = { version = "0.10", optional = true }
+aes = { version = "0.8", optional = true }
+cipher = { version = "0.4", optional = true }
+des = { version = "0.8", optional = true }
+hmac = { version = "0.12", optional = true }
+cbc = { version = "0.1", optional = true }
+cfb-mode = { version = "0.8", optional = true }
+rand = { version = "0.9", optional = true }
+
[dev-dependencies]
-tokio = { version = "=1.47" }
+tokio = { version = "1" }
[features]
+default = ["tokio", "v3_rust"]
+
mibs = ["dep:snmptools"]
tokio = ["dep:tokio"]
-v3 = ["openssl"]
+v3 = []
heap_buffers = []
-full = ["mibs", "tokio", "v3"]
+full = ["mibs", "tokio", "v3_rust"]
+
+v3_openssl = ["v3", "openssl"]
+v3_rust = ["v3", "md-5", "sha1", "digest", "sha2", "aes", "cipher", "des", "hmac", "cbc", "cfb-mode", "rand"]
diff --git a/README.md b/README.md
index 75593a8..7cd060a 100644
--- a/README.md
+++ b/README.md
@@ -36,7 +36,7 @@ Supports:
- Synchronous/Asynchronous requests
- UDP transport
- MIBs (with `mibs` feature, requires `libnetsnmp`)
-- SNMP v3 (requires `v3` feature)
+- SNMP v3 (enable `v3_openssl` or `v3_rust` feature)
# Examples
@@ -139,7 +139,7 @@ let socket = UdpSocket::bind("0.0.0.0:1161").unwrap();
socket.send_to(&bytes, target_addr).unwrap();
```
-### With SNMPv3 (requires `v3` feature)
+### With SNMPv3 (enable `v3_openssl` or `v3_rust`)
When using SNMPv3, you need to provide the security context to convert the PDU to bytes:
@@ -210,9 +210,13 @@ assert_eq!(snmp_oid, snmp_oid2);
# SNMPv3
-- Requires `v3` crate feature.
+- Requires enabling one of the features: `v3_openssl` or `v3_rust`.
+ - `v3_openssl`: uses OpenSSL for hashing/HMAC and symmetric encryption.
+ - `v3_rust`: uses pure Rust crypto crates for hashing/HMAC and encryption.
-- All cryptographic algorithms are provided by [openssl](https://www.openssl.org/).
+- Cryptographic algorithms are provided by the selected backend:
+ - `v3_openssl`: [openssl](https://www.openssl.org/)
+ - `v3_rust`: pure Rust crates [Rust Crypto](https://github.com/RustCrypto): (`md-5`, `sha1`, `sha2`, `hmac`, `aes`, `des`, etc.)
- For authentication, supports: MD5 (RFC3414), SHA1 (RFC3414) and non-standard
SHA224, SHA256, SHA384, SHA512.
@@ -221,8 +225,22 @@ assert_eq!(snmp_oid, snmp_oid2);
AES192-CFB, AES256-CFB. Additional/different AES modes are not supported and
may require patching the crate.
-Note: DES legacy encryption may be disabled in openssl by default or even not
-supported at all. Refer to the library documentation how to enable it.
+Note: For `v3_openssl`, DES legacy encryption may be disabled in OpenSSL by default
+or not supported at all. Refer to the library documentation how to enable it.
+
+### Feature selection examples
+
+Pure Rust backend:
+
+```shell
+cargo add snmp2 --features v3_rust
+```
+
+OpenSSL backend (Windows-friendly vendored build):
+
+```shell
+cargo add snmp2 --features "v3_openssl,openssl/vendored"
+```
## Example
@@ -261,21 +279,22 @@ loop {
}
```
-## Building
+## Building (`v3_openssl`)
-In case of problems (e.g. with [cross-rs](https://github.com/cross-rs/cross)),
-add `openssl` with `vendored` feature:
+When using the `v3_openssl` backend, in case of problems (e.g. with
+[cross-rs](https://github.com/cross-rs/cross)), add `openssl` with `vendored` feature:
```shell
cargo add openssl --features vendored
```
-## FIPS-140 support
+## FIPS-140 support (`v3_openssl`)
-The crate uses openssl cryptography only and becomes FIPS-140 compliant as soon
+When using the `v3_openssl` backend, the crate becomes FIPS-140 compliant as soon
as FIPS mode is activated in `openssl`. Refer to the
[openssl crate](https://docs.rs/openssl) crate and
[openssl library](https://www.openssl.org/) documentation for more details.
+The `v3_rust` backend does not rely on OpenSSL and is not FIPS-certified.
## MSRV
diff --git a/build.rs b/build.rs
new file mode 100644
index 0000000..2ff266d
--- /dev/null
+++ b/build.rs
@@ -0,0 +1,15 @@
+fn main() {
+ let has_v3 = std::env::var("CARGO_FEATURE_V3").is_ok();
+ let has_v3_openssl = std::env::var("CARGO_FEATURE_V3_OPENSSL").is_ok();
+ let has_v3_rust = std::env::var("CARGO_FEATURE_V3_RUST").is_ok();
+
+ match (has_v3_openssl, has_v3_rust) {
+ (true, false) | (false, true) => {} // OK
+ (true, true) => panic!("feature_v3_openssl and feature_v3_rust are mutually exclusive!"),
+ (false, false) => {
+ if has_v3 {
+ panic!("feature_v3_openssl or feature_v3_rust is required")
+ }
+ }
+ }
+}
diff --git a/src/lib.rs b/src/lib.rs
index 50510bb..8209c4a 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -12,7 +12,7 @@ pub mod snmp;
mod syncsession;
#[cfg(feature = "v3")]
pub mod v3;
-#[cfg(feature = "v3")]
+#[cfg(feature = "v3_openssl")]
pub use openssl;
pub use syncsession::SyncSession;
#[cfg(feature = "tokio")]
@@ -141,7 +141,7 @@ impl fmt::Display for Error {
}
}
-#[cfg(feature = "v3")]
+#[cfg(feature = "v3_openssl")]
impl From
for Error {
fn from(err: openssl::error::ErrorStack) -> Error {
Error::Crypto(err.to_string())
diff --git a/src/v3.rs b/src/v3.rs
index a829771..f8313a7 100644
--- a/src/v3.rs
+++ b/src/v3.rs
@@ -1,11 +1,23 @@
use std::{fmt, time::Instant};
+#[cfg(feature = "v3_openssl")]
use openssl::{
hash::{Hasher, MessageDigest},
pkey::PKey,
sign::Signer,
};
+#[cfg(feature = "v3_rust")]
+use {
+ aes::{Aes128, Aes192, Aes256},
+ cbc::{Decryptor as CbcDecryptor, Encryptor as CbcEncryptor},
+ cfb_mode::{Decryptor as CfbDecryptor, Encryptor as CfbEncryptor},
+ cipher::{AsyncStreamCipher, BlockDecryptMut, BlockEncryptMut, KeyIvInit},
+ des::Des,
+ digest::{Digest, DynDigest},
+ hmac::{Hmac, Mac},
+};
+
use crate::{
asn1,
pdu::{self, Buf},
@@ -324,10 +336,55 @@ impl Security {
if self.engine_id().is_empty() {
return Err(Error::AuthFailure(AuthErrorKind::SecurityNotReady));
}
- let pkey = PKey::hmac(&self.authoritative_state.auth_key)?;
- let mut signer = Signer::new(self.auth_protocol.digest(), &pkey)?;
- signer.update(data)?;
- signer.sign_to_vec().map_err(Error::from)
+ #[cfg(feature = "v3_openssl")]
+ {
+ let pkey = PKey::hmac(&self.authoritative_state.auth_key)?;
+ let mut signer = Signer::new(self.auth_protocol.digest(), &pkey)?;
+ signer.update(data)?;
+ signer.sign_to_vec().map_err(Error::from)
+ }
+ #[cfg(feature = "v3_rust")]
+ {
+ let key = &self.authoritative_state.auth_key;
+ match self.auth_protocol {
+ AuthProtocol::Md5 => {
+ let mut mac = Hmac::::new_from_slice(key)
+ .map_err(|_| Error::Crypto("Invalid key length".into()))?;
+ mac.update(data);
+ Ok(mac.finalize().into_bytes().to_vec())
+ }
+ AuthProtocol::Sha1 => {
+ let mut mac = Hmac::::new_from_slice(key)
+ .map_err(|_| Error::Crypto("Invalid key length".into()))?;
+ mac.update(data);
+ Ok(mac.finalize().into_bytes().to_vec())
+ }
+ AuthProtocol::Sha224 => {
+ let mut mac = Hmac::::new_from_slice(key)
+ .map_err(|_| Error::Crypto("Invalid key length".into()))?;
+ mac.update(data);
+ Ok(mac.finalize().into_bytes().to_vec())
+ }
+ AuthProtocol::Sha256 => {
+ let mut mac = Hmac::::new_from_slice(key)
+ .map_err(|_| Error::Crypto("Invalid key length".into()))?;
+ mac.update(data);
+ Ok(mac.finalize().into_bytes().to_vec())
+ }
+ AuthProtocol::Sha384 => {
+ let mut mac = Hmac::::new_from_slice(key)
+ .map_err(|_| Error::Crypto("Invalid key length".into()))?;
+ mac.update(data);
+ Ok(mac.finalize().into_bytes().to_vec())
+ }
+ AuthProtocol::Sha512 => {
+ let mut mac = Hmac::::new_from_slice(key)
+ .map_err(|_| Error::Crypto("Invalid key length".into()))?;
+ mac.update(data);
+ Ok(mac.finalize().into_bytes().to_vec())
+ }
+ }
+ }
}
pub(crate) fn update_key(&mut self) -> Result<()> {
@@ -388,7 +445,13 @@ impl Security {
fn encrypt_des(&self, data: &[u8]) -> Result<(Vec, Vec)> {
let mut salt = [0; 8];
salt[..4].copy_from_slice(&u32::try_from(self.engine_boots())?.to_be_bytes());
+ #[cfg(feature = "v3_openssl")]
openssl::rand::rand_bytes(&mut salt[4..])?;
+ #[cfg(feature = "v3_rust")]
+ {
+ use rand::Rng;
+ rand::rng().fill(&mut salt[4..]);
+ }
if data.is_empty() {
return Ok((vec![], salt.to_vec()));
@@ -400,65 +463,124 @@ impl Security {
let des_key = &self.authoritative_state.priv_key[..8];
let pre_iv = &self.authoritative_state.priv_key[8..16];
- let cipher = openssl::symm::Cipher::des_cbc();
let mut iv = [0; 8];
for (i, (a, b)) in pre_iv.iter().zip(salt.iter()).enumerate() {
iv[i] = a ^ b;
}
- let mut encrypted = vec![0; data.len() + cipher.block_size()];
- let mut crypter =
- openssl::symm::Crypter::new(cipher, openssl::symm::Mode::Encrypt, des_key, Some(&iv))?;
- let mut count = crypter.update(data, &mut encrypted)?;
+ #[cfg(feature = "v3_openssl")]
+ {
+ let cipher = openssl::symm::Cipher::des_cbc();
+ let mut encrypted = vec![0; data.len() + cipher.block_size()];
+ let mut crypter = openssl::symm::Crypter::new(
+ cipher,
+ openssl::symm::Mode::Encrypt,
+ des_key,
+ Some(&iv),
+ )?;
+ let mut count = crypter.update(data, &mut encrypted)?;
- if count < encrypted.len() {
- count += crypter.finalize(&mut encrypted[count..])?;
+ if count < encrypted.len() {
+ count += crypter.finalize(&mut encrypted[count..])?;
+ }
+
+ encrypted.truncate(count);
+ Ok((encrypted, salt.to_vec()))
}
+ #[cfg(feature = "v3_rust")]
+ {
+ let mut encryptor = CbcEncryptor::::new_from_slices(des_key, &iv)
+ .map_err(|e| Error::Crypto(e.to_string()))?;
+
+ // PKCS#7 padding
+ let len = data.len();
+ let pad_len = 8 - (len % 8);
+ let mut padded = Vec::with_capacity(len + pad_len);
+ padded.extend_from_slice(data);
+ padded.extend(std::iter::repeat(pad_len as u8).take(pad_len));
+
+ for chunk in padded.chunks_mut(8) {
+ let block = cipher::generic_array::GenericArray::from_mut_slice(chunk);
+ encryptor.encrypt_block_mut(block);
+ }
- encrypted.truncate(count);
- Ok((encrypted, salt.to_vec()))
+ Ok((padded, salt.to_vec()))
+ }
}
- fn encrypt_aes(
- &self,
- data: &[u8],
- cipher: openssl::symm::Cipher,
- block_size: usize,
- ) -> Result<(Vec, Vec)> {
- let iv_len = cipher
- .iv_len()
- .ok_or_else(|| Error::Crypto("no IV len".to_owned()))?;
-
+ fn encrypt_aes(&self, data: &[u8], key_len: usize) -> Result<(Vec, Vec)> {
+ let iv_len = 16;
let mut iv = Vec::with_capacity(iv_len);
iv.extend_from_slice(&u32::try_from(self.engine_boots())?.to_be_bytes());
iv.extend_from_slice(&u32::try_from(self.engine_time())?.to_be_bytes());
let salt_pos = iv.len();
iv.resize(iv_len, 0);
+ #[cfg(feature = "v3_openssl")]
openssl::rand::rand_bytes(&mut iv[salt_pos..])?;
- let key_len = cipher.key_len();
+ #[cfg(feature = "v3_rust")]
+ {
+ use rand::Rng;
+ rand::rng().fill(&mut iv[salt_pos..]);
+ }
if self.authoritative_state.priv_key.len() < key_len {
return Err(Error::AuthFailure(AuthErrorKind::KeyLengthMismatch));
}
- let mut crypter = openssl::symm::Crypter::new(
- cipher,
- openssl::symm::Mode::Encrypt,
- &self.authoritative_state.priv_key[..key_len],
- Some(&iv),
- )?;
+ #[cfg(feature = "v3_openssl")]
+ {
+ let cipher = match key_len {
+ 16 => openssl::symm::Cipher::aes_128_cfb128(),
+ 24 => openssl::symm::Cipher::aes_192_cfb128(),
+ 32 => openssl::symm::Cipher::aes_256_cfb128(),
+ _ => return Err(Error::Crypto("Invalid key len".into())),
+ };
+
+ let mut crypter = openssl::symm::Crypter::new(
+ cipher,
+ openssl::symm::Mode::Encrypt,
+ &self.authoritative_state.priv_key[..key_len],
+ Some(&iv),
+ )?;
+
+ let mut encrypted = vec![0; data.len() + 16];
+ let mut count = crypter.update(data, &mut encrypted)?;
- let mut encrypted = vec![0; data.len() + block_size];
- let mut count = crypter.update(data, &mut encrypted)?;
+ if count < encrypted.len() {
+ count += crypter.finalize(&mut encrypted[count..])?;
+ }
- if count < encrypted.len() {
- count += crypter.finalize(&mut encrypted[count..])?;
+ encrypted.truncate(count);
+ Ok((encrypted, iv[salt_pos..].to_vec()))
}
+ #[cfg(feature = "v3_rust")]
+ {
+ let key = &self.authoritative_state.priv_key[..key_len];
+ let mut encrypted = data.to_vec();
+
+ match key_len {
+ 16 => {
+ let encryptor = CfbEncryptor::::new_from_slices(key, &iv)
+ .map_err(|e| Error::Crypto(e.to_string()))?;
+ encryptor.encrypt(&mut encrypted);
+ }
+ 24 => {
+ let encryptor = CfbEncryptor::::new_from_slices(key, &iv)
+ .map_err(|e| Error::Crypto(e.to_string()))?;
+ encryptor.encrypt(&mut encrypted);
+ }
+ 32 => {
+ let encryptor = CfbEncryptor::::new_from_slices(key, &iv)
+ .map_err(|e| Error::Crypto(e.to_string()))?;
+ encryptor.encrypt(&mut encrypted);
+ }
+ _ => return Err(Error::Crypto("Invalid key len".into())),
+ }
- encrypted.truncate(count);
- Ok((encrypted, iv[salt_pos..].to_vec()))
+ Ok((encrypted, iv[salt_pos..].to_vec()))
+ }
}
/// encrypts the data
@@ -477,12 +599,13 @@ impl Security {
match cipher_kind {
Cipher::Des => self.encrypt_des(data),
- Cipher::Aes128 => self.encrypt_aes(data, openssl::symm::Cipher::aes_128_cfb128(), 16),
- Cipher::Aes192 => self.encrypt_aes(data, openssl::symm::Cipher::aes_192_cfb128(), 24),
- Cipher::Aes256 => self.encrypt_aes(data, openssl::symm::Cipher::aes_256_cfb128(), 32),
+ Cipher::Aes128 => self.encrypt_aes(data, 16),
+ Cipher::Aes192 => self.encrypt_aes(data, 24),
+ Cipher::Aes256 => self.encrypt_aes(data, 32),
}
}
+ #[cfg(feature = "v3_openssl")]
fn decrypt_data_to_plain_buf(
&mut self,
mut crypter: openssl::symm::Crypter,
@@ -509,13 +632,6 @@ impl Security {
return Err(Error::AuthFailure(AuthErrorKind::KeyLengthMismatch));
}
- let cipher = openssl::symm::Cipher::des_cbc();
- let block_size = 8;
-
- if encrypted.len() % block_size > 0 {
- return Err(Error::AuthFailure(AuthErrorKind::PayloadLengthMismatch));
- }
-
let des_key = &self.authoritative_state.priv_key[..8];
let pre_iv = &self.authoritative_state.priv_key[8..16];
let mut iv = [0; 8];
@@ -524,22 +640,58 @@ impl Security {
iv[i] = a ^ b;
}
- let crypter =
- openssl::symm::Crypter::new(cipher, openssl::symm::Mode::Decrypt, des_key, Some(&iv))?;
- self.decrypt_data_to_plain_buf(crypter, block_size, encrypted)
- }
+ #[cfg(feature = "v3_openssl")]
+ {
+ let cipher = openssl::symm::Cipher::des_cbc();
+ let block_size = 8;
- fn decrypt_aes(
- &mut self,
- encrypted: &[u8],
- priv_params: &[u8],
- cipher: openssl::symm::Cipher,
- block_size: usize,
- ) -> Result<()> {
- let iv_len = cipher
- .iv_len()
- .ok_or_else(|| Error::Crypto("no IV len".to_owned()))?;
+ if encrypted.len() % block_size > 0 {
+ return Err(Error::AuthFailure(AuthErrorKind::PayloadLengthMismatch));
+ }
+
+ let crypter = openssl::symm::Crypter::new(
+ cipher,
+ openssl::symm::Mode::Decrypt,
+ des_key,
+ Some(&iv),
+ )?;
+ self.decrypt_data_to_plain_buf(crypter, block_size, encrypted)
+ }
+ #[cfg(feature = "v3_rust")]
+ {
+ let block_size = 8;
+ if encrypted.len() % block_size > 0 {
+ return Err(Error::AuthFailure(AuthErrorKind::PayloadLengthMismatch));
+ }
+
+ let mut decryptor = CbcDecryptor::::new_from_slices(des_key, &iv)
+ .map_err(|e| Error::Crypto(e.to_string()))?;
+
+ self.plain_buf.clear();
+ self.plain_buf.extend_from_slice(encrypted);
+ for chunk in self.plain_buf.chunks_mut(8) {
+ let block = cipher::generic_array::GenericArray::from_mut_slice(chunk);
+ decryptor.decrypt_block_mut(block);
+ }
+
+ if let Some(&pad_len) = self.plain_buf.last() {
+ let pad_len = pad_len as usize;
+ if pad_len > 0 && pad_len <= block_size && pad_len <= self.plain_buf.len() {
+ let new_len = self.plain_buf.len() - pad_len;
+ self.plain_buf.truncate(new_len);
+ Ok(())
+ } else {
+ Err(Error::Crypto("Invalid padding".into()))
+ }
+ } else {
+ Ok(())
+ }
+ }
+ }
+
+ fn decrypt_aes(&mut self, encrypted: &[u8], priv_params: &[u8], key_len: usize) -> Result<()> {
+ let iv_len = 16;
let mut iv = Vec::with_capacity(iv_len);
iv.extend_from_slice(&u32::try_from(self.engine_boots())?.to_be_bytes());
iv.extend_from_slice(&u32::try_from(self.engine_time())?.to_be_bytes());
@@ -549,19 +701,54 @@ impl Security {
return Err(Error::AuthFailure(AuthErrorKind::PrivLengthMismatch));
}
- let key_len = cipher.key_len();
if self.authoritative_state.priv_key.len() < key_len {
return Err(Error::AuthFailure(AuthErrorKind::KeyLengthMismatch));
}
- let crypter = openssl::symm::Crypter::new(
- cipher,
- openssl::symm::Mode::Decrypt,
- &self.authoritative_state.priv_key[..key_len],
- Some(&iv),
- )?;
+ #[cfg(feature = "v3_openssl")]
+ {
+ let cipher = match key_len {
+ 16 => openssl::symm::Cipher::aes_128_cfb128(),
+ 24 => openssl::symm::Cipher::aes_192_cfb128(),
+ 32 => openssl::symm::Cipher::aes_256_cfb128(),
+ _ => return Err(Error::Crypto("Invalid key len".into())),
+ };
+
+ let crypter = openssl::symm::Crypter::new(
+ cipher,
+ openssl::symm::Mode::Decrypt,
+ &self.authoritative_state.priv_key[..key_len],
+ Some(&iv),
+ )?;
- self.decrypt_data_to_plain_buf(crypter, block_size, encrypted)
+ self.decrypt_data_to_plain_buf(crypter, 16, encrypted)
+ }
+ #[cfg(feature = "v3_rust")]
+ {
+ let key = &self.authoritative_state.priv_key[..key_len];
+ self.plain_buf.clear();
+ self.plain_buf.extend_from_slice(encrypted);
+
+ match key_len {
+ 16 => {
+ let decryptor = CfbDecryptor::::new_from_slices(key, &iv)
+ .map_err(|e| Error::Crypto(e.to_string()))?;
+ decryptor.decrypt(&mut self.plain_buf);
+ }
+ 24 => {
+ let decryptor = CfbDecryptor::::new_from_slices(key, &iv)
+ .map_err(|e| Error::Crypto(e.to_string()))?;
+ decryptor.decrypt(&mut self.plain_buf);
+ }
+ 32 => {
+ let decryptor = CfbDecryptor::::new_from_slices(key, &iv)
+ .map_err(|e| Error::Crypto(e.to_string()))?;
+ decryptor.decrypt(&mut self.plain_buf);
+ }
+ _ => return Err(Error::Crypto("Invalid key len".into())),
+ }
+ Ok(())
+ }
}
/// decrypts the data, the result is stored in `self.plain_buf`
@@ -576,24 +763,9 @@ impl Security {
match cipher_kind {
Cipher::Des => self.decrypt_des(encrypted, priv_params),
- Cipher::Aes128 => self.decrypt_aes(
- encrypted,
- priv_params,
- openssl::symm::Cipher::aes_128_cfb128(),
- 16,
- ),
- Cipher::Aes192 => self.decrypt_aes(
- encrypted,
- priv_params,
- openssl::symm::Cipher::aes_192_cfb128(),
- 24,
- ),
- Cipher::Aes256 => self.decrypt_aes(
- encrypted,
- priv_params,
- openssl::symm::Cipher::aes_256_cfb128(),
- 32,
- ),
+ Cipher::Aes128 => self.decrypt_aes(encrypted, priv_params, 16),
+ Cipher::Aes192 => self.decrypt_aes(encrypted, priv_params, 24),
+ Cipher::Aes256 => self.decrypt_aes(encrypted, priv_params, 32),
}
}
}
@@ -610,6 +782,25 @@ pub enum Auth {
},
}
+#[cfg(feature = "v3_rust")]
+pub struct Hasher(Box);
+
+#[cfg(feature = "v3_rust")]
+impl Hasher {
+ pub fn new(d: Box) -> Result {
+ Ok(Self(d))
+ }
+
+ pub fn update(&mut self, data: &[u8]) -> Result<()> {
+ self.0.update(data);
+ Ok(())
+ }
+
+ pub fn finish(&mut self) -> Result> {
+ Ok(self.0.finalize_reset().to_vec())
+ }
+}
+
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum AuthProtocol {
Md5,
@@ -622,8 +813,24 @@ pub enum AuthProtocol {
impl AuthProtocol {
fn create_hasher(self) -> Result {
- Hasher::new(self.digest()).map_err(Into::into)
+ #[cfg(feature = "v3_openssl")]
+ {
+ Hasher::new(self.digest()).map_err(Into::into)
+ }
+ #[cfg(feature = "v3_rust")]
+ {
+ let d: Box = match self {
+ AuthProtocol::Md5 => Box::new(md5::Md5::new()),
+ AuthProtocol::Sha1 => Box::new(sha1::Sha1::new()),
+ AuthProtocol::Sha224 => Box::new(sha2::Sha224::new()),
+ AuthProtocol::Sha256 => Box::new(sha2::Sha256::new()),
+ AuthProtocol::Sha384 => Box::new(sha2::Sha384::new()),
+ AuthProtocol::Sha512 => Box::new(sha2::Sha512::new()),
+ };
+ Hasher::new(d)
+ }
}
+ #[cfg(feature = "v3_openssl")]
fn digest(self) -> MessageDigest {
match self {
AuthProtocol::Md5 => MessageDigest::md5(),