diff --git a/Cargo.toml b/Cargo.toml index 59dc1d6..5b14e99 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,9 +12,11 @@ crate-type = ["dylib", "rlib"] aes = "0.8.3" base64 = "0.21.2" blockhash = "0.5.0" -cbc = "0.1.2" +cbc = { version = "0.1.2", features = ["std"] } +cipher = "0.4.4" des = "0.8.1" hex = "0.4.3" +hmac-sha256 = "1.1.7" hmac-sha512 = "1.1.5" image = "0.24.6" md-5 = "0.10.5" diff --git a/README.md b/README.md index a44a486..9ba6bd3 100644 --- a/README.md +++ b/README.md @@ -4,10 +4,10 @@ Rust 中可以使用的常用辅助功能工具箱。主要配备以下功能: - 加解密算法 - [ ] 随机密钥自解密算法 - - [ ] AES-CBC 便捷加解密算法 - - [ ] No Padding - - [ ] ZerosPadding - - [ ] Pkcs7Padding + - [x] AES-CBC 便捷加解密算法 + - [x] No Padding + - [x] ZerosPadding + - [x] Pkcs7Padding - [ ] DES-CBC 便捷加解密算法 - [ ] No Padding - [ ] ZerosPadding diff --git a/src/encryption/aes.rs b/src/encryption/aes.rs new file mode 100644 index 0000000..f54b1de --- /dev/null +++ b/src/encryption/aes.rs @@ -0,0 +1,133 @@ +use aes::Aes256; +use cipher::{BlockDecryptMut, BlockEncryptMut, KeyIvInit}; + +type AesEncryptor = cbc::Encryptor; +type AesDecryptor = cbc::Decryptor; + +/// 利用Sha256生成32字节的密钥 +/// +/// - `key` 原始密钥 +fn generate_key>(key: T) -> [u8; 32] { + let mut hasher = hmac_sha256::Hash::new(); + hasher.update(key); + let result = hasher.finalize(); + result +} + +/// 利用给定的密钥生成16字节的初始向量 +fn generate_iv(key: &[u8; 32]) -> [u8; 16] { + let mut result = [0u8; 16]; + for i in 0..16 { + result[i] = key[i] ^ key[i + 16]; + } + result +} + +/// 使用指定的密钥和填充方式对数据进行加密。 +/// 如果需要字符串形式的密文,可以配合使用`hex`或者`base64`等函数。 +/// +/// - `key` 密钥 +/// - `padding` 填充方式 +/// - `plain_data` 明文数据 +pub fn encrypt, D: AsRef<[u8]>>( + key: T, + padding: super::Padding, + plain_data: D, +) -> Vec { + let key = generate_key(key); + let iv = generate_iv(&key); + let encryptor = AesEncryptor::new(&key.into(), &iv.into()); + let result = match padding { + super::Padding::NoPadding => encryptor + .encrypt_padded_vec_mut::(plain_data.as_ref()), + super::Padding::ZeroPadding => encryptor + .encrypt_padded_vec_mut::(plain_data.as_ref()), + super::Padding::Pkcs7Padding => { + encryptor.encrypt_padded_vec_mut::(plain_data.as_ref()) + } + }; + result +} + +/// 使用指定的密钥和填充方式对数据进行解密。 +/// +/// - `key` 密钥 +/// - `padding` 填充方式 +/// - `cipher_data` 密文数据 +pub fn decrypt, D: AsRef<[u8]>>( + key: T, + padding: super::Padding, + cipher_data: D, +) -> Result, super::DecryptFailedError> { + let key = generate_key(key); + let iv = generate_iv(&key); + let decryptor = AesDecryptor::new(&key.into(), &iv.into()); + match padding { + super::Padding::NoPadding => decryptor + .decrypt_padded_vec_mut::(cipher_data.as_ref()) + .map_err(|_| super::DecryptFailedError {}), + super::Padding::ZeroPadding => decryptor + .decrypt_padded_vec_mut::(cipher_data.as_ref()) + .map_err(|_| super::DecryptFailedError {}), + super::Padding::Pkcs7Padding => decryptor + .decrypt_padded_vec_mut::(cipher_data.as_ref()) + .map_err(|_| super::DecryptFailedError {}), + } +} + +/// 快捷无填充加密函数 +/// +/// - `key` 密钥 +/// - `plain_data` 明文数据 +pub fn encrypt_no_padding, D: AsRef<[u8]>>(key: T, plain_data: D) -> Vec { + encrypt(key, super::Padding::NoPadding, plain_data) +} + +/// 快捷无填充解密函数 +/// +/// - `key` 密钥 +/// - `cipher_data` 密文数据 +pub fn decrypt_no_padding, D: AsRef<[u8]>>( + key: T, + cipher_data: D, +) -> Result, super::DecryptFailedError> { + decrypt(key, super::Padding::NoPadding, cipher_data) +} + +/// 快捷零填充加密函数 +/// +/// - `key` 密钥 +/// - `plain_data` 明文数据 +pub fn encrypt_zero_padding, D: AsRef<[u8]>>(key: T, plain_data: D) -> Vec { + encrypt(key, super::Padding::ZeroPadding, plain_data) +} + +/// 快捷零填充解密函数 +/// +/// - `key` 密钥 +/// - `cipher_data` 密文数据 +pub fn decrypt_zero_padding, D: AsRef<[u8]>>( + key: T, + cipher_data: D, +) -> Result, super::DecryptFailedError> { + decrypt(key, super::Padding::ZeroPadding, cipher_data) +} + +/// 快捷Pkcs7填充加密函数 +/// +/// - `key` 密钥 +/// - `plain_data` 明文数据 +pub fn encrypt_pkcs7_padding, D: AsRef<[u8]>>(key: T, plain_data: D) -> Vec { + encrypt(key, super::Padding::Pkcs7Padding, plain_data) +} + +/// 快捷Pkcs7填充解密函数 +/// +/// - `key` 密钥 +/// - `cipher_data` 密文数据 +pub fn decrypt_pkcs7_padding, D: AsRef<[u8]>>( + key: T, + cipher_data: D, +) -> Result, super::DecryptFailedError> { + decrypt(key, super::Padding::Pkcs7Padding, cipher_data) +} diff --git a/src/encryption/mod.rs b/src/encryption/mod.rs index e69de29..2abc4bd 100644 --- a/src/encryption/mod.rs +++ b/src/encryption/mod.rs @@ -0,0 +1,13 @@ +use thiserror::Error; + +pub mod aes; + +pub enum Padding { + NoPadding, + ZeroPadding, + Pkcs7Padding, +} + +#[derive(Debug, Error)] +#[error("Decrypt failed")] +pub struct DecryptFailedError {} diff --git a/tests/aes_cryption.rs b/tests/aes_cryption.rs new file mode 100644 index 0000000..907d579 --- /dev/null +++ b/tests/aes_cryption.rs @@ -0,0 +1,25 @@ +#[cfg(test)] +mod aes_test { + #[test] + fn encrypt_zero_padding() { + let cipher_data = + rs_toolbox::encryption::aes::encrypt_zero_padding("123456", "Hello world."); + let cipher_hex = rs_toolbox::serialize::to_hex(cipher_data); + assert_eq!(cipher_hex, "722e10838a6c770d631701ee7c37c334"); + } + + #[test] + fn decrypt_zero_padding() { + let plain_data = rs_toolbox::encryption::aes::decrypt_zero_padding( + "123456", + rs_toolbox::serialize::from_hex("722e10838a6c770d631701ee7c37c334").unwrap(), + ); + if plain_data.is_err() { + panic!("Decrypt failed"); + } + assert_eq!( + String::from_utf8(plain_data.unwrap()).unwrap(), + "Hello world." + ); + } +}