From 56fef4c3de7a4293444fb3401d3ea960db90bfd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BE=90=E6=B6=9B?= Date: Sun, 2 Jul 2023 17:32:49 +0800 Subject: [PATCH] =?UTF-8?q?feat(crypt):=E5=AE=8C=E6=88=90DES=E4=BE=BF?= =?UTF-8?q?=E6=8D=B7=E5=8A=A0=E5=AF=86=E5=87=BD=E6=95=B0=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 7 ++- src/encryption/des.rs | 128 ++++++++++++++++++++++++++++++++++++++++++ src/encryption/mod.rs | 1 + tests/des_cryption.rs | 25 +++++++++ 4 files changed, 159 insertions(+), 2 deletions(-) create mode 100644 src/encryption/des.rs create mode 100644 tests/des_cryption.rs diff --git a/README.md b/README.md index 9ba6bd3..2974944 100644 --- a/README.md +++ b/README.md @@ -8,11 +8,14 @@ Rust 中可以使用的常用辅助功能工具箱。主要配备以下功能: - [x] No Padding - [x] ZerosPadding - [x] Pkcs7Padding - - [ ] DES-CBC 便捷加解密算法 + - [x] DES-CBC 便捷加解密算法 + - [x] No Padding + - [x] ZerosPadding + - [x] Pkcs7Padding + - [ ] 3DES-CBC 便捷加解密算法 - [ ] No Padding - [ ] ZerosPadding - [ ] Pkcs7Padding - - [ ] 3DES 便捷加解密算法 - [ ] RSA 加解密算法 - [ ] 1024 位长 - [ ] 2048 位长 diff --git a/src/encryption/des.rs b/src/encryption/des.rs new file mode 100644 index 0000000..11f675c --- /dev/null +++ b/src/encryption/des.rs @@ -0,0 +1,128 @@ +use cipher::{BlockDecryptMut, BlockEncryptMut, KeyIvInit}; +use des::Des; + +type DesEncryptor = cbc::Encryptor; +type DesDecryptor = cbc::Decryptor; + +/// 利用Sha512生成24字节的密钥 +/// +/// - `key` 原始密钥 +fn generate_key>(key: T) -> [u8; 8] { + let mut hasher = hmac_sha256::Hash::new(); + hasher.update(key); + let result = hasher.finalize(); + let mut compressed_key = [0u8; 8]; + for i in 0..8 { + compressed_key[i] = result[i]; + for j in 1..4 { + compressed_key[i] ^= result[i + j * 8]; + } + } + compressed_key +} + +/// 使用指定的密钥和填充方式对数据进行加密。 +/// 如果需要字符串形式的密文,可以配合使用`hex`或者`base64`等函数。 +/// +/// - `key` 密钥 +/// - `padding` 填充方式 +/// - `plain_data` 明文数据 +fn encrypt, D: AsRef<[u8]>>( + key: T, + padding: super::Padding, + plain_data: D, +) -> Vec { + let key = generate_key(key); + let encryptor = DesEncryptor::new(key.as_slice().into(), &key.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` 密文数据 +fn decrypt, D: AsRef<[u8]>>( + key: T, + padding: super::Padding, + cipher_data: D, +) -> Result, super::DecryptFailedError> { + let key = generate_key(key); + let decryptor = DesDecryptor::new(key.as_slice().into(), &key.into()); + let result = match padding { + super::Padding::NoPadding => decryptor + .decrypt_padded_vec_mut::(cipher_data.as_ref()), + super::Padding::ZeroPadding => decryptor + .decrypt_padded_vec_mut::(cipher_data.as_ref()), + super::Padding::Pkcs7Padding => { + decryptor.decrypt_padded_vec_mut::(cipher_data.as_ref()) + } + }; + result.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 2abc4bd..b2b3e5f 100644 --- a/src/encryption/mod.rs +++ b/src/encryption/mod.rs @@ -1,6 +1,7 @@ use thiserror::Error; pub mod aes; +pub mod des; pub enum Padding { NoPadding, diff --git a/tests/des_cryption.rs b/tests/des_cryption.rs new file mode 100644 index 0000000..b55dbcf --- /dev/null +++ b/tests/des_cryption.rs @@ -0,0 +1,25 @@ +#[cfg(test)] +mod des_test { + #[test] + fn encrypt_zero_padding() { + let cipher_data = + rs_toolbox::encryption::des::encrypt_zero_padding("123456", "Hello world."); + let cipher_hex = rs_toolbox::serialize::to_hex(cipher_data); + assert_eq!(cipher_hex, "34115b8448d11e6d284576573a28629b"); + } + + #[test] + fn decrypt_zero_padding() { + let plain_data = rs_toolbox::encryption::des::decrypt_zero_padding( + "123456", + rs_toolbox::serialize::from_hex("34115b8448d11e6d284576573a28629b").unwrap(), + ); + if plain_data.is_err() { + panic!("Decrypt failed"); + } + assert_eq!( + String::from_utf8(plain_data.unwrap()).unwrap(), + "Hello world." + ); + } +}