use crate::hashs::{Error as HashError, Hash, HashImpl}; #[cfg(feature="sm3")] use crate::hashs::SM3; #[cfg(feature="insecure_md5")] use crate::hashs::MD5; #[cfg(feature="insecure_sha1")] use crate::hashs::SHA1; #[cfg(feature="sha2")] use crate::hashs::SHA2; use crate::libs::utils::bytes_xor; /// 密钥杂凑消息鉴别码流式计算器(Keyed-Hash Message Authentication Code Stream Mode Calculator) /// /// # 示例(Examples) /// /// ```rust /// # use neuedu_cryptos::hashs::Error as HashError; /// # /// # fn main() -> Result<(), HashError> { /// use neuedu_cryptos::hashs::Hash; /// use neuedu_cryptos::macs::HMAC; /// /// let mut instance = HMAC::new(b"key", Hash::SM3); /// instance.update(b"message")?; /// let mac = instance.r#final()?; /// /// assert_eq!(mac, [ /// 0x34, 0xC9, 0x0B, 0x29, 0x1A, 0x80, 0xB7, 0xFD, /// 0x7F, 0x2B, 0xE4, 0x3D, 0x68, 0x39, 0x35, 0xBA, /// 0xB9, 0xD1, 0x49, 0x16, 0x46, 0x66, 0xC4, 0xEF, /// 0x88, 0x57, 0xC8, 0x15, 0xCF, 0x2E, 0xF8, 0x32, /// ]); /// # /// # Ok(()) /// # } /// ``` pub struct HMAC { hash: Hash, inner_hash: Option>, outer_hash: Option>, } impl HMAC { /// 创建一个密钥杂凑消息鉴别码实例。\ /// Create a Keyed-Hash Message Authentication Code Instance. pub fn new(key: &[u8], hash: Hash) -> Self { let mut instance = Self { hash, inner_hash: None, outer_hash: None, }; instance.inner_hash = Some(instance.get_hash_impl()); instance.outer_hash = Some(instance.get_hash_impl()); let block_sized_key = instance.compute_block_sized_key(key); let mut o_key_pad = vec![0x5C; block_sized_key.len()]; o_key_pad = bytes_xor(&block_sized_key, &o_key_pad).into(); let mut i_key_pad = vec![0x36; block_sized_key.len()]; i_key_pad = bytes_xor(&block_sized_key, &i_key_pad).into(); instance.inner_hash.as_mut().expect("").update(&i_key_pad).unwrap(); instance.outer_hash.as_mut().expect("").update(&o_key_pad).unwrap(); instance } /// 填入任意长度的待计算的消息。\ /// Feed a message of any length to be calculated. /// /// # 参数(Arguments) /// /// * message - 消息(Message) /// /// 任意长度的消息。\ /// Message of any length. pub fn update(&mut self, message: &[u8]) -> Result<(), HashError> { self.inner_hash.as_mut().expect("").update(message) } /// 结束填入待计算的消息。\ /// End feeding in messages to be calculated. pub fn r#final(&mut self) -> Result, HashError> { let inner_digest = self.inner_hash.as_mut().expect("").r#final().unwrap(); self.outer_hash.as_mut().expect("").update(&inner_digest).unwrap(); self.outer_hash.as_mut().expect("").r#final() } fn compute_block_sized_key(&self, key: &[u8]) -> Vec { let mut hash_impl = self.get_hash_impl(); let mut block_sized_key = Vec::::with_capacity(hash_impl.block_size()); // Keys longer than blockSize are shortened by hashing them if key.len() > hash_impl.block_size() { hash_impl.update(key).unwrap(); block_sized_key.append(&mut hash_impl.r#final().unwrap()); return block_sized_key; } // Keys shorter than blockSize are padded to blockSize by padding with zeros on the right if key.len() < hash_impl.block_size() { block_sized_key.append(&mut key.into()); // Pad key with zeros to make it blockSize bytes long block_sized_key.resize(hash_impl.block_size(), 0); return block_sized_key; } key.into() } fn get_hash_impl(&self) -> Box { match self.hash { #[cfg(feature="sm3")] Hash::SM3 => Box::::default(), #[cfg(feature="insecure_md5")] Hash::MD5 => Box::::default(), #[cfg(feature="insecure_sha1")] Hash::SHA1 => Box::::default(), #[cfg(feature="sha2")] Hash::SHA224 => Box::new(SHA2::new(Hash::SHA224)), #[cfg(feature="sha2")] Hash::SHA256 => Box::new(SHA2::new(Hash::SHA256)), #[cfg(feature="sha2")] Hash::SHA384 => Box::new(SHA2::new(Hash::SHA384)), #[cfg(feature="sha2")] Hash::SHA512 => Box::new(SHA2::new(Hash::SHA512)), #[cfg(feature="sha2")] Hash::SHA512_224 => Box::new(SHA2::new(Hash::SHA512_224)), #[cfg(feature="sha2")] Hash::SHA512_256 => Box::new(SHA2::new(Hash::SHA512_256)), } } }