From d9d24dbb5422cd581e78def71db0281bf9c22a65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BE=90=E6=B6=9B?= Date: Mon, 3 Jul 2023 17:27:27 +0800 Subject: [PATCH] =?UTF-8?q?feat(crypto):=E5=A2=9E=E5=8A=A0=E8=9E=BA?= =?UTF-8?q?=E6=97=8B=E8=87=AA=E8=A7=A3=E5=AF=86=E5=8A=A0=E5=AF=86=E7=AE=97?= =?UTF-8?q?=E6=B3=95=E6=94=AF=E6=8C=81=E5=87=BD=E6=95=B0=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/encryption/mod.rs | 1 + src/encryption/spiral.rs | 59 ++++++++++++++++++++++++++++++++++++++++ src/hash/mod.rs | 21 ++++++++++++++ tests/spiral_cryption.rs | 26 ++++++++++++++++++ 4 files changed, 107 insertions(+) create mode 100644 src/encryption/spiral.rs create mode 100644 tests/spiral_cryption.rs diff --git a/src/encryption/mod.rs b/src/encryption/mod.rs index 9c0a042..d946f4b 100644 --- a/src/encryption/mod.rs +++ b/src/encryption/mod.rs @@ -3,6 +3,7 @@ use thiserror::Error; pub mod aes; pub mod des; pub mod rsa; +pub mod spiral; pub mod tdes; pub enum Padding { diff --git a/src/encryption/spiral.rs b/src/encryption/spiral.rs new file mode 100644 index 0000000..432eb24 --- /dev/null +++ b/src/encryption/spiral.rs @@ -0,0 +1,59 @@ +use aes::Aes256; +use cipher::{BlockDecryptMut, BlockEncryptMut, KeyIvInit}; +use thiserror::Error; + +type AesEncryptor = cbc::Encryptor; +type AesDecryptor = cbc::Decryptor; + +#[derive(Debug, Error)] +pub enum SpiralCipherError { + #[error("Encrypted data corrupted")] + CorruptedCipherData, + #[error("Decrypt failed")] + DecryptFailed, +} + +/// 生成一个随机密钥 +fn gen_key(seed: &str) -> [u8; 32] { + let hash = crate::hash::sha512::hash_hex(seed); + hash.as_slice()[4..36].try_into().unwrap() +} + +/// 对给定的内容进行加密 +/// +/// - `data` 待加密的内容 +pub fn encrypt(data: String) -> String { + let mut result = String::from("["); + let rand_key = crate::verifiy_code::random_verify_code(20); + let key = gen_key(&rand_key); + let iv: [u8; 16] = key[0..16].try_into().unwrap(); + let encryptor = AesEncryptor::new(&key.into(), &iv.into()); + let encrypted_data = + encryptor.encrypt_padded_vec_mut::(data.as_bytes()); + result.push_str(rand_key.as_ref()); + result.push_str(crate::serialize::to_base64_str(&encrypted_data).as_ref()); + result +} + +/// 对给定的内容进行解密 +/// +/// - `data` 待解密的内容 +pub fn decrypt(data: String) -> Result { + if !data.starts_with("[") || data.len() <= 21 { + return Err(SpiralCipherError::CorruptedCipherData); + } + let data = data[1..].to_string(); + let key_seed = data[0..20].to_string(); + let key = gen_key(&key_seed); + let iv: [u8; 16] = key[0..16].try_into().unwrap(); + let decryptor = AesDecryptor::new(&key.into(), &iv.into()); + let encrypted_data = crate::serialize::from_base64_str(&data[20..]) + .map_err(|_| SpiralCipherError::CorruptedCipherData)?; + let decrypted_data = decryptor + .decrypt_padded_vec_mut::(encrypted_data.as_slice()) + .map_err(|e| { + println!("error: {}", e); + SpiralCipherError::DecryptFailed + })?; + Ok(String::from_utf8_lossy(decrypted_data.as_slice()).to_string()) +} diff --git a/src/hash/mod.rs b/src/hash/mod.rs index 3c090c1..da74a13 100644 --- a/src/hash/mod.rs +++ b/src/hash/mod.rs @@ -6,6 +6,13 @@ pub mod md5 { let result = hasher.finalize(); crate::serialize::to_hex(result.as_slice()) } + + pub fn hash_hex>(input: T) -> Vec { + let mut hasher = md5::Md5::new(); + hasher.update(input); + let result = hasher.finalize(); + result.to_vec() + } } pub mod sha1 { @@ -16,6 +23,13 @@ pub mod sha1 { let result = hasher.finalize(); crate::serialize::to_hex(result.as_slice()) } + + pub fn hash_hex>(input: T) -> Vec { + let mut hasher = sha1::Sha1::new(); + hasher.update(input); + let result = hasher.finalize(); + result.to_vec() + } } pub mod sha512 { @@ -25,6 +39,13 @@ pub mod sha512 { let result = hasher.finalize(); crate::serialize::to_hex(result.as_slice()) } + + pub fn hash_hex>(input: T) -> Vec { + let mut hasher = hmac_sha512::Hash::new(); + hasher.update(input); + let result = hasher.finalize(); + result.to_vec() + } } pub mod image_hash { diff --git a/tests/spiral_cryption.rs b/tests/spiral_cryption.rs new file mode 100644 index 0000000..20cd49e --- /dev/null +++ b/tests/spiral_cryption.rs @@ -0,0 +1,26 @@ +#[cfg(test)] +mod spriral_test { + #[test] + fn encrypt_and_decrypt() { + let origin_text = "Hello, world!".to_string(); + let encrypted_text = rs_toolbox::encryption::spiral::encrypt(origin_text.clone()); + println!("encrypted_text: {}", encrypted_text); + let decrypted_text = + rs_toolbox::encryption::spiral::decrypt(encrypted_text).expect("decrypt failed"); + assert_eq!(origin_text, decrypted_text); + } + + #[test] + fn decrypt_foreign() { + let encrypted = "[13WOHv6CLGoIcqX5se6WvHM3pGNBH7wVJONahG7k0Q==".to_string(); + let decrypted_text = match rs_toolbox::encryption::spiral::decrypt(encrypted) { + Ok(text) => text, + Err(e) => { + println!("error: {}", e); + panic!("decrypt failed"); + } + }; + println!("decrypted_text: {}", decrypted_text); + assert_eq!("cxfh@83864830", decrypted_text); + } +}