Compare commits
13 Commits
31d5129a8a
...
0.1.3
Author | SHA1 | Date | |
---|---|---|---|
|
51a7a48962 | ||
|
3f86e75518 | ||
|
dbcdfc426e | ||
|
d1c19355a5 | ||
|
e6447fdd43 | ||
|
3f3191fcea | ||
|
6f20341c85 | ||
|
d9d24dbb54 | ||
|
9a913b4bf4 | ||
|
551209d4f1 | ||
|
56fef4c3de | ||
|
8cbb7f5269 | ||
|
a19dfd1e1b |
@@ -12,13 +12,19 @@ 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"] }
|
||||
chrono = "0.4.26"
|
||||
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"
|
||||
once_cell = "1.18.0"
|
||||
rand = "0.8.5"
|
||||
rsa = { version = "0.9.2", features = ["sha2"] }
|
||||
sha1 = "0.10.5"
|
||||
sha2 = "0.10.7"
|
||||
thiserror = "1.0.40"
|
||||
uuid = { version = "1.4.0", features = ["v4", "fast-rng"] }
|
||||
|
35
README.md
35
README.md
@@ -3,33 +3,40 @@
|
||||
Rust 中可以使用的常用辅助功能工具箱。主要配备以下功能:
|
||||
|
||||
- 加解密算法
|
||||
- [ ] 随机密钥自解密算法
|
||||
- [ ] AES-CBC 便捷加解密算法
|
||||
- [ ] ZerosPadding
|
||||
- [ ] Pkcs7Padding
|
||||
- [ ] DES-CBC 便捷加解密算法
|
||||
- [ ] ZerosPadding
|
||||
- [ ] Pkcs7Padding
|
||||
- [ ] 3DES 便捷加解密算法
|
||||
- [ ] RSA 加解密算法
|
||||
- [ ] 1024 位长
|
||||
- [ ] 2048 位长
|
||||
- [ ] KeyPair 生成器
|
||||
- [x] 螺旋随机密钥自解密算法
|
||||
- [x] AES-CBC 便捷加解密算法
|
||||
- [x] No Padding
|
||||
- [x] ZerosPadding
|
||||
- [x] Pkcs7Padding
|
||||
- [x] DES-CBC 便捷加解密算法
|
||||
- [x] No Padding
|
||||
- [x] ZerosPadding
|
||||
- [x] Pkcs7Padding
|
||||
- [x] 3DES-CBC 便捷加解密算法
|
||||
- [x] No Padding
|
||||
- [x] ZerosPadding
|
||||
- [x] Pkcs7Padding
|
||||
- [x] RSA 加解密算法
|
||||
- [x] 1024 位长
|
||||
- [x] 2048 位长
|
||||
- [x] KeyPair 生成器
|
||||
- 散列算法。
|
||||
- [x] Sha512 散列算法
|
||||
- [x] Sha1 散列算法
|
||||
- [x] MD5 散列算法
|
||||
- [x] 图像感知散列算法
|
||||
- 唯一序列号生成器
|
||||
- [ ] 改进版雪花 ID 生成器(短主机精简日期版)
|
||||
- [x] 冰雹 ID 生成器(短主机精简日期版雪花 ID)
|
||||
- [x] UUID 生成器
|
||||
- [x] short UUID 生成器
|
||||
- 签名算法
|
||||
- [ ] RSA 签名算法
|
||||
- [x] RSA 签名算法
|
||||
- 验证码生成器
|
||||
- [x] 随机验证码生成算法
|
||||
- 序列化算法
|
||||
- [x] Base64 算法
|
||||
- [x] Hex 直转
|
||||
- 常用工具函数
|
||||
- [x] 日期时间函数
|
||||
|
||||
本工具箱仅可支持于 Rust 程序中使用,可以编译为`rlib`或者`dylib`。
|
||||
|
133
src/encryption/aes.rs
Normal file
133
src/encryption/aes.rs
Normal file
@@ -0,0 +1,133 @@
|
||||
use aes::Aes256;
|
||||
use cipher::{BlockDecryptMut, BlockEncryptMut, KeyIvInit};
|
||||
|
||||
type AesEncryptor = cbc::Encryptor<Aes256>;
|
||||
type AesDecryptor = cbc::Decryptor<Aes256>;
|
||||
|
||||
/// 利用Sha256生成32字节的密钥
|
||||
///
|
||||
/// - `key` 原始密钥
|
||||
fn generate_key<T: AsRef<[u8]>>(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<T: AsRef<[u8]>, D: AsRef<[u8]>>(
|
||||
key: T,
|
||||
padding: super::Padding,
|
||||
plain_data: D,
|
||||
) -> Vec<u8> {
|
||||
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::<cipher::block_padding::NoPadding>(plain_data.as_ref()),
|
||||
super::Padding::ZeroPadding => encryptor
|
||||
.encrypt_padded_vec_mut::<cipher::block_padding::ZeroPadding>(plain_data.as_ref()),
|
||||
super::Padding::Pkcs7Padding => {
|
||||
encryptor.encrypt_padded_vec_mut::<cipher::block_padding::Pkcs7>(plain_data.as_ref())
|
||||
}
|
||||
};
|
||||
result
|
||||
}
|
||||
|
||||
/// 使用指定的密钥和填充方式对数据进行解密。
|
||||
///
|
||||
/// - `key` 密钥
|
||||
/// - `padding` 填充方式
|
||||
/// - `cipher_data` 密文数据
|
||||
pub fn decrypt<T: AsRef<[u8]>, D: AsRef<[u8]>>(
|
||||
key: T,
|
||||
padding: super::Padding,
|
||||
cipher_data: D,
|
||||
) -> Result<Vec<u8>, 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::block_padding::NoPadding>(cipher_data.as_ref())
|
||||
.map_err(|_| super::DecryptFailedError {}),
|
||||
super::Padding::ZeroPadding => decryptor
|
||||
.decrypt_padded_vec_mut::<cipher::block_padding::ZeroPadding>(cipher_data.as_ref())
|
||||
.map_err(|_| super::DecryptFailedError {}),
|
||||
super::Padding::Pkcs7Padding => decryptor
|
||||
.decrypt_padded_vec_mut::<cipher::block_padding::Pkcs7>(cipher_data.as_ref())
|
||||
.map_err(|_| super::DecryptFailedError {}),
|
||||
}
|
||||
}
|
||||
|
||||
/// 快捷无填充加密函数
|
||||
///
|
||||
/// - `key` 密钥
|
||||
/// - `plain_data` 明文数据
|
||||
pub fn encrypt_no_padding<T: AsRef<[u8]>, D: AsRef<[u8]>>(key: T, plain_data: D) -> Vec<u8> {
|
||||
encrypt(key, super::Padding::NoPadding, plain_data)
|
||||
}
|
||||
|
||||
/// 快捷无填充解密函数
|
||||
///
|
||||
/// - `key` 密钥
|
||||
/// - `cipher_data` 密文数据
|
||||
pub fn decrypt_no_padding<T: AsRef<[u8]>, D: AsRef<[u8]>>(
|
||||
key: T,
|
||||
cipher_data: D,
|
||||
) -> Result<Vec<u8>, super::DecryptFailedError> {
|
||||
decrypt(key, super::Padding::NoPadding, cipher_data)
|
||||
}
|
||||
|
||||
/// 快捷零填充加密函数
|
||||
///
|
||||
/// - `key` 密钥
|
||||
/// - `plain_data` 明文数据
|
||||
pub fn encrypt_zero_padding<T: AsRef<[u8]>, D: AsRef<[u8]>>(key: T, plain_data: D) -> Vec<u8> {
|
||||
encrypt(key, super::Padding::ZeroPadding, plain_data)
|
||||
}
|
||||
|
||||
/// 快捷零填充解密函数
|
||||
///
|
||||
/// - `key` 密钥
|
||||
/// - `cipher_data` 密文数据
|
||||
pub fn decrypt_zero_padding<T: AsRef<[u8]>, D: AsRef<[u8]>>(
|
||||
key: T,
|
||||
cipher_data: D,
|
||||
) -> Result<Vec<u8>, super::DecryptFailedError> {
|
||||
decrypt(key, super::Padding::ZeroPadding, cipher_data)
|
||||
}
|
||||
|
||||
/// 快捷Pkcs7填充加密函数
|
||||
///
|
||||
/// - `key` 密钥
|
||||
/// - `plain_data` 明文数据
|
||||
pub fn encrypt_pkcs7_padding<T: AsRef<[u8]>, D: AsRef<[u8]>>(key: T, plain_data: D) -> Vec<u8> {
|
||||
encrypt(key, super::Padding::Pkcs7Padding, plain_data)
|
||||
}
|
||||
|
||||
/// 快捷Pkcs7填充解密函数
|
||||
///
|
||||
/// - `key` 密钥
|
||||
/// - `cipher_data` 密文数据
|
||||
pub fn decrypt_pkcs7_padding<T: AsRef<[u8]>, D: AsRef<[u8]>>(
|
||||
key: T,
|
||||
cipher_data: D,
|
||||
) -> Result<Vec<u8>, super::DecryptFailedError> {
|
||||
decrypt(key, super::Padding::Pkcs7Padding, cipher_data)
|
||||
}
|
128
src/encryption/des.rs
Normal file
128
src/encryption/des.rs
Normal file
@@ -0,0 +1,128 @@
|
||||
use cipher::{BlockDecryptMut, BlockEncryptMut, KeyIvInit};
|
||||
use des::Des;
|
||||
|
||||
type DesEncryptor = cbc::Encryptor<Des>;
|
||||
type DesDecryptor = cbc::Decryptor<Des>;
|
||||
|
||||
/// 利用Sha512生成8字节的密钥
|
||||
///
|
||||
/// - `key` 原始密钥
|
||||
fn generate_key<T: AsRef<[u8]>>(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<T: AsRef<[u8]>, D: AsRef<[u8]>>(
|
||||
key: T,
|
||||
padding: super::Padding,
|
||||
plain_data: D,
|
||||
) -> Vec<u8> {
|
||||
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::<cipher::block_padding::NoPadding>(plain_data.as_ref()),
|
||||
super::Padding::ZeroPadding => encryptor
|
||||
.encrypt_padded_vec_mut::<cipher::block_padding::ZeroPadding>(plain_data.as_ref()),
|
||||
super::Padding::Pkcs7Padding => {
|
||||
encryptor.encrypt_padded_vec_mut::<cipher::block_padding::Pkcs7>(plain_data.as_ref())
|
||||
}
|
||||
};
|
||||
result
|
||||
}
|
||||
|
||||
/// 使用指定的密钥和填充方式对数据进行解密。
|
||||
///
|
||||
/// - `key` 密钥
|
||||
/// - `padding` 填充方式
|
||||
/// - `cipher_data` 密文数据
|
||||
fn decrypt<T: AsRef<[u8]>, D: AsRef<[u8]>>(
|
||||
key: T,
|
||||
padding: super::Padding,
|
||||
cipher_data: D,
|
||||
) -> Result<Vec<u8>, 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::block_padding::NoPadding>(cipher_data.as_ref()),
|
||||
super::Padding::ZeroPadding => decryptor
|
||||
.decrypt_padded_vec_mut::<cipher::block_padding::ZeroPadding>(cipher_data.as_ref()),
|
||||
super::Padding::Pkcs7Padding => {
|
||||
decryptor.decrypt_padded_vec_mut::<cipher::block_padding::Pkcs7>(cipher_data.as_ref())
|
||||
}
|
||||
};
|
||||
result.map_err(|_| super::DecryptFailedError {})
|
||||
}
|
||||
|
||||
/// 快捷无填充加密函数
|
||||
///
|
||||
/// - `key` 密钥
|
||||
/// - `plain_data` 明文数据
|
||||
pub fn encrypt_no_padding<T: AsRef<[u8]>, D: AsRef<[u8]>>(key: T, plain_data: D) -> Vec<u8> {
|
||||
encrypt(key, super::Padding::NoPadding, plain_data)
|
||||
}
|
||||
|
||||
/// 快捷无填充解密函数
|
||||
///
|
||||
/// - `key` 密钥
|
||||
/// - `cipher_data` 密文数据
|
||||
pub fn decrypt_no_padding<T: AsRef<[u8]>, D: AsRef<[u8]>>(
|
||||
key: T,
|
||||
cipher_data: D,
|
||||
) -> Result<Vec<u8>, super::DecryptFailedError> {
|
||||
decrypt(key, super::Padding::NoPadding, cipher_data)
|
||||
}
|
||||
|
||||
/// 快捷零填充加密函数
|
||||
///
|
||||
/// - `key` 密钥
|
||||
/// - `plain_data` 明文数据
|
||||
pub fn encrypt_zero_padding<T: AsRef<[u8]>, D: AsRef<[u8]>>(key: T, plain_data: D) -> Vec<u8> {
|
||||
encrypt(key, super::Padding::ZeroPadding, plain_data)
|
||||
}
|
||||
|
||||
/// 快捷零填充解密函数
|
||||
///
|
||||
/// - `key` 密钥
|
||||
/// - `cipher_data` 密文数据
|
||||
pub fn decrypt_zero_padding<T: AsRef<[u8]>, D: AsRef<[u8]>>(
|
||||
key: T,
|
||||
cipher_data: D,
|
||||
) -> Result<Vec<u8>, super::DecryptFailedError> {
|
||||
decrypt(key, super::Padding::ZeroPadding, cipher_data)
|
||||
}
|
||||
|
||||
/// 快捷Pkcs7填充加密函数
|
||||
///
|
||||
/// - `key` 密钥
|
||||
/// - `plain_data` 明文数据
|
||||
pub fn encrypt_pkcs7_padding<T: AsRef<[u8]>, D: AsRef<[u8]>>(key: T, plain_data: D) -> Vec<u8> {
|
||||
encrypt(key, super::Padding::Pkcs7Padding, plain_data)
|
||||
}
|
||||
|
||||
/// 快捷Pkcs7填充解密函数
|
||||
///
|
||||
/// - `key` 密钥
|
||||
/// - `cipher_data` 密文数据
|
||||
pub fn decrypt_pkcs7_padding<T: AsRef<[u8]>, D: AsRef<[u8]>>(
|
||||
key: T,
|
||||
cipher_data: D,
|
||||
) -> Result<Vec<u8>, super::DecryptFailedError> {
|
||||
decrypt(key, super::Padding::Pkcs7Padding, cipher_data)
|
||||
}
|
@@ -0,0 +1,17 @@
|
||||
use thiserror::Error;
|
||||
|
||||
pub mod aes;
|
||||
pub mod des;
|
||||
pub mod rsa;
|
||||
pub mod spiral;
|
||||
pub mod tdes;
|
||||
|
||||
pub enum Padding {
|
||||
NoPadding,
|
||||
ZeroPadding,
|
||||
Pkcs7Padding,
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
#[error("Decrypt failed")]
|
||||
pub struct DecryptFailedError {}
|
||||
|
338
src/encryption/rsa.rs
Normal file
338
src/encryption/rsa.rs
Normal file
@@ -0,0 +1,338 @@
|
||||
use rsa::{
|
||||
pkcs1::{DecodeRsaPrivateKey, DecodeRsaPublicKey, EncodeRsaPrivateKey, EncodeRsaPublicKey},
|
||||
pkcs8::{DecodePrivateKey, DecodePublicKey},
|
||||
signature::{Keypair, RandomizedSigner, SignatureEncoding, Verifier},
|
||||
Pkcs1v15Encrypt,
|
||||
};
|
||||
use sha2::Sha256;
|
||||
use thiserror::Error;
|
||||
|
||||
pub enum RsaBitSize {
|
||||
Bit1024,
|
||||
Bit2048,
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum RsaCryptionError {
|
||||
#[error("Invalid public key")]
|
||||
InvalidPublicKey,
|
||||
#[error("Invalid private key")]
|
||||
InvalidPrivateKey,
|
||||
#[error("Unrecognized private key encoding or encrypted private key")]
|
||||
UnrecognizedPrivateKeyEncoding,
|
||||
#[error("Unrecognized public key encoding")]
|
||||
UnrecognizedPublicKeyEncoding,
|
||||
#[error("Private key required")]
|
||||
PrivateKeyRequired,
|
||||
#[error("Public key required")]
|
||||
PublicKeyRequired,
|
||||
#[error("Signing key required")]
|
||||
SigningKeyRequired,
|
||||
#[error("Verifying key required")]
|
||||
VerifyingKeyRequired,
|
||||
#[error("Failed to process data: {0}")]
|
||||
CryptionFailed(#[from] rsa::errors::Error),
|
||||
#[error("Unable to load signature")]
|
||||
UnableToLoadSignature,
|
||||
#[error("Signature verification failed")]
|
||||
VerificationFailed,
|
||||
#[error("Unable to export private key")]
|
||||
UnableToExportPrivateKey,
|
||||
#[error("Unable to export public key")]
|
||||
UnableToExportPublicKey,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RsaCryptor {
|
||||
private_key: Option<rsa::RsaPrivateKey>,
|
||||
public_key: Option<rsa::RsaPublicKey>,
|
||||
signing_key: Option<rsa::pkcs1v15::SigningKey<Sha256>>,
|
||||
verifying_key: Option<rsa::pkcs1v15::VerifyingKey<Sha256>>,
|
||||
}
|
||||
|
||||
fn load_binary_private_key(key: &[u8]) -> Result<rsa::RsaPrivateKey, RsaCryptionError> {
|
||||
let private_key = rsa::RsaPrivateKey::from_pkcs1_der(&key);
|
||||
if let Ok(private_key) = private_key {
|
||||
if private_key.validate().is_err() {
|
||||
return Err(RsaCryptionError::InvalidPrivateKey);
|
||||
}
|
||||
return Ok(private_key);
|
||||
}
|
||||
let private_key = rsa::RsaPrivateKey::from_pkcs8_der(&key);
|
||||
if let Ok(private_key) = private_key {
|
||||
if private_key.validate().is_err() {
|
||||
return Err(RsaCryptionError::InvalidPrivateKey);
|
||||
}
|
||||
return Ok(private_key);
|
||||
}
|
||||
Err(RsaCryptionError::UnrecognizedPrivateKeyEncoding)
|
||||
}
|
||||
|
||||
fn load_text_private_key(pem: &str) -> Result<rsa::RsaPrivateKey, RsaCryptionError> {
|
||||
let private_key = rsa::RsaPrivateKey::from_pkcs1_pem(pem);
|
||||
if let Ok(private_key) = private_key {
|
||||
if private_key.validate().is_err() {
|
||||
return Err(RsaCryptionError::InvalidPrivateKey);
|
||||
}
|
||||
return Ok(private_key);
|
||||
}
|
||||
let private_key = rsa::RsaPrivateKey::from_pkcs8_pem(pem);
|
||||
if let Ok(private_key) = private_key {
|
||||
if private_key.validate().is_err() {
|
||||
return Err(RsaCryptionError::InvalidPrivateKey);
|
||||
}
|
||||
return Ok(private_key);
|
||||
}
|
||||
Err(RsaCryptionError::UnrecognizedPrivateKeyEncoding)
|
||||
}
|
||||
|
||||
fn load_binary_public_key(key: &[u8]) -> Result<rsa::RsaPublicKey, RsaCryptionError> {
|
||||
let public_key = rsa::RsaPublicKey::from_pkcs1_der(&key);
|
||||
if let Ok(public_key) = public_key {
|
||||
return Ok(public_key);
|
||||
}
|
||||
let public_key = rsa::RsaPublicKey::from_public_key_der(&key);
|
||||
if let Ok(public_key) = public_key {
|
||||
return Ok(public_key);
|
||||
}
|
||||
Err(RsaCryptionError::UnrecognizedPublicKeyEncoding)
|
||||
}
|
||||
|
||||
fn load_text_public_key(pem: &str) -> Result<rsa::RsaPublicKey, RsaCryptionError> {
|
||||
let public_key = rsa::RsaPublicKey::from_pkcs1_pem(pem);
|
||||
if let Ok(public_key) = public_key {
|
||||
return Ok(public_key);
|
||||
}
|
||||
let public_key = rsa::RsaPublicKey::from_public_key_pem(pem);
|
||||
if let Ok(public_key) = public_key {
|
||||
return Ok(public_key);
|
||||
}
|
||||
Err(RsaCryptionError::UnrecognizedPublicKeyEncoding)
|
||||
}
|
||||
|
||||
impl RsaCryptor {
|
||||
/// 创建一个完全空白的 RSA 加密器。其中私钥、公钥、签名私钥和签名公钥都是空的,需要通过其他方法加载后方可使用。
|
||||
pub fn new_empty() -> Self {
|
||||
Self {
|
||||
private_key: None,
|
||||
public_key: None,
|
||||
signing_key: None,
|
||||
verifying_key: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// 创建一个指定位数的 RSA 加密器,同时生成一套随机密钥。
|
||||
/// 如果不能正常生成私钥,则直接返回错误。
|
||||
///
|
||||
/// - `bit_size`:密钥位数,目前支持 1024 位和 2048 位。
|
||||
pub fn new(bit_size: RsaBitSize) -> Result<Self, RsaCryptionError> {
|
||||
let mut rng = rand::thread_rng();
|
||||
let bit_size = match bit_size {
|
||||
RsaBitSize::Bit1024 => 1024,
|
||||
RsaBitSize::Bit2048 => 2048,
|
||||
};
|
||||
let private_key = rsa::RsaPrivateKey::new(&mut rng, bit_size)
|
||||
.map_err(|_| RsaCryptionError::InvalidPublicKey)?;
|
||||
let public_key = rsa::RsaPublicKey::from(&private_key);
|
||||
let signing_key = rsa::pkcs1v15::SigningKey::<Sha256>::new(private_key.clone());
|
||||
let verify_key = signing_key.verifying_key();
|
||||
Ok(Self {
|
||||
private_key: Some(private_key),
|
||||
public_key: Some(public_key),
|
||||
signing_key: Some(signing_key),
|
||||
verifying_key: Some(verify_key),
|
||||
})
|
||||
}
|
||||
|
||||
/// 从字节数组中加载私钥,如果加载失败,则返回错误。
|
||||
/// 私钥加载成功后,公钥、签名私钥和签名公钥也会被同时自动生成。
|
||||
///
|
||||
/// - `key`:私钥内容。
|
||||
pub fn load_binary_private_key<T: AsRef<[u8]>>(
|
||||
&mut self,
|
||||
key: T,
|
||||
) -> Result<(), RsaCryptionError> {
|
||||
let private_key = load_binary_private_key(key.as_ref())?;
|
||||
let public_key = rsa::RsaPublicKey::from(&private_key);
|
||||
let signing_key = rsa::pkcs1v15::SigningKey::<Sha256>::new(private_key.clone());
|
||||
let verify_key = signing_key.verifying_key();
|
||||
self.private_key = Some(private_key);
|
||||
self.public_key = Some(public_key);
|
||||
self.signing_key = Some(signing_key);
|
||||
self.verifying_key = Some(verify_key);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 从文本中加载私钥,如果加载失败,则返回错误。
|
||||
/// 私钥加载成功后,公钥、签名私钥和签名公钥也会被同时自动生成。
|
||||
///
|
||||
/// - `pem`:私钥内容。
|
||||
pub fn load_text_private_key(&mut self, pem: &str) -> Result<(), RsaCryptionError> {
|
||||
let private_key = load_text_private_key(pem)?;
|
||||
let public_key = rsa::RsaPublicKey::from(&private_key);
|
||||
let signing_key = rsa::pkcs1v15::SigningKey::<Sha256>::new(private_key.clone());
|
||||
let verify_key = signing_key.verifying_key();
|
||||
self.private_key = Some(private_key);
|
||||
self.public_key = Some(public_key);
|
||||
self.signing_key = Some(signing_key);
|
||||
self.verifying_key = Some(verify_key);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 从字节数组中加载公钥,如果加载失败,则返回错误。
|
||||
/// 公钥加载成功后,签名公钥也会被同时自动生成。私钥与签名私钥会被置为`None`。
|
||||
/// ! 没有私钥的情况下,无法对内容进行解密。
|
||||
///
|
||||
/// - `key`:公钥内容。
|
||||
pub fn load_binary_public_key<T: AsRef<[u8]>>(
|
||||
&mut self,
|
||||
key: T,
|
||||
) -> Result<(), RsaCryptionError> {
|
||||
let public_key = load_binary_public_key(key.as_ref())?;
|
||||
let verify_key = rsa::pkcs1v15::VerifyingKey::<Sha256>::from(public_key.clone());
|
||||
self.private_key = None;
|
||||
self.public_key = Some(public_key);
|
||||
self.signing_key = None;
|
||||
self.verifying_key = Some(verify_key);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 从文本中加载公钥,如果加载失败,则返回错误。
|
||||
/// 公钥加载成功后,签名公钥也会被同时自动生成。私钥与签名私钥会被置为`None`。
|
||||
/// ! 没有私钥的情况下,无法对内容进行解密。
|
||||
///
|
||||
/// - `pem`:公钥内容。
|
||||
pub fn load_text_public_key(&mut self, pem: &str) -> Result<(), RsaCryptionError> {
|
||||
let public_key = load_text_public_key(pem)?;
|
||||
let verify_key = rsa::pkcs1v15::VerifyingKey::<Sha256>::from(public_key.clone());
|
||||
self.private_key = None;
|
||||
self.public_key = Some(public_key);
|
||||
self.signing_key = None;
|
||||
self.verifying_key = Some(verify_key);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 对指定内容进行加密,返回加密后的内容。
|
||||
///
|
||||
/// - `data`:待加密的内容。
|
||||
pub fn encrypt<T: AsRef<[u8]>>(&self, data: T) -> Result<Vec<u8>, RsaCryptionError> {
|
||||
if self.public_key.is_none() {
|
||||
return Err(RsaCryptionError::PublicKeyRequired);
|
||||
}
|
||||
let mut rng = rand::thread_rng();
|
||||
let encrypted_data = self
|
||||
.public_key
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.encrypt(&mut rng, Pkcs1v15Encrypt, data.as_ref())
|
||||
.map_err(|e| RsaCryptionError::CryptionFailed(e))?;
|
||||
Ok(encrypted_data)
|
||||
}
|
||||
|
||||
/// 对指定内容进行解密,返回解密后的内容。如果没有私钥,则返回错误。
|
||||
///
|
||||
/// - `data`:待解密的内容。
|
||||
pub fn decrypt<T: AsRef<[u8]>>(&self, data: T) -> Result<Vec<u8>, RsaCryptionError> {
|
||||
if self.private_key.is_none() {
|
||||
return Err(RsaCryptionError::PrivateKeyRequired);
|
||||
}
|
||||
let decrypted_data = self
|
||||
.private_key
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.decrypt(Pkcs1v15Encrypt, data.as_ref())
|
||||
.map_err(|e| RsaCryptionError::CryptionFailed(e))?;
|
||||
Ok(decrypted_data)
|
||||
}
|
||||
|
||||
/// 对指定内容进行签名,返回签名后的内容。如果没有签名私钥,则返回错误。
|
||||
///
|
||||
/// - `data`:待签名的内容。
|
||||
pub fn sign<T: AsRef<[u8]>>(&self, data: T) -> Result<Vec<u8>, RsaCryptionError> {
|
||||
if self.signing_key.is_none() {
|
||||
return Err(RsaCryptionError::SigningKeyRequired);
|
||||
}
|
||||
let mut rng = rand::thread_rng();
|
||||
let sign_data = self
|
||||
.signing_key
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.sign_with_rng(&mut rng, data.as_ref())
|
||||
.to_vec();
|
||||
Ok(sign_data)
|
||||
}
|
||||
|
||||
/// 对指定内容和签名进行验证,如果验证失败,则返回错误。
|
||||
///
|
||||
/// - `signature`:签名内容。
|
||||
/// - `data`:待验证的内容。
|
||||
pub fn verify<T: AsRef<[u8]>>(&self, signature: T, data: T) -> Result<(), RsaCryptionError> {
|
||||
if self.verifying_key.is_none() {
|
||||
return Err(RsaCryptionError::VerifyingKeyRequired);
|
||||
}
|
||||
let signature = rsa::pkcs1v15::Signature::try_from(signature.as_ref())
|
||||
.map_err(|_| RsaCryptionError::UnableToLoadSignature)?;
|
||||
self.verifying_key
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.verify(data.as_ref(), &signature)
|
||||
.map_err(|_| RsaCryptionError::VerificationFailed)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 以字节数组方式导出私钥,如果没有私钥,则返回错误。
|
||||
pub fn export_private_key_binary(&self) -> Result<Vec<u8>, RsaCryptionError> {
|
||||
if self.private_key.is_none() {
|
||||
return Err(RsaCryptionError::PrivateKeyRequired);
|
||||
}
|
||||
let doc = self
|
||||
.private_key
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.to_pkcs1_der()
|
||||
.map_err(|_| RsaCryptionError::UnableToExportPrivateKey)?;
|
||||
Ok(doc.as_bytes().to_vec())
|
||||
}
|
||||
|
||||
/// 以PEM文本方式导出私钥,如果没有私钥,则返回错误。
|
||||
pub fn export_private_key_pem(&self) -> Result<String, RsaCryptionError> {
|
||||
if self.private_key.is_none() {
|
||||
return Err(RsaCryptionError::PrivateKeyRequired);
|
||||
}
|
||||
let doc = self
|
||||
.private_key
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.to_pkcs1_pem(rsa::pkcs1::LineEnding::CRLF)
|
||||
.map_err(|_| RsaCryptionError::UnableToExportPrivateKey)?;
|
||||
Ok(doc.to_string())
|
||||
}
|
||||
|
||||
/// 以字节数组的方式导出公钥,如果没有公钥,则返回错误。
|
||||
pub fn export_public_key_binary(&self) -> Result<Vec<u8>, RsaCryptionError> {
|
||||
if self.public_key.is_none() {
|
||||
return Err(RsaCryptionError::PublicKeyRequired);
|
||||
}
|
||||
let doc = self
|
||||
.public_key
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.to_pkcs1_der()
|
||||
.map_err(|_| RsaCryptionError::UnableToExportPublicKey)?;
|
||||
Ok(doc.into_vec())
|
||||
}
|
||||
|
||||
/// 以PEM文本方式导出公钥,如果没有公钥,则返回错误。
|
||||
pub fn export_public_key_pem(&self) -> Result<String, RsaCryptionError> {
|
||||
if self.public_key.is_none() {
|
||||
return Err(RsaCryptionError::PublicKeyRequired);
|
||||
}
|
||||
let doc = self
|
||||
.public_key
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.to_pkcs1_pem(rsa::pkcs1::LineEnding::CRLF)
|
||||
.map_err(|_| RsaCryptionError::UnableToExportPublicKey)?;
|
||||
Ok(doc)
|
||||
}
|
||||
}
|
59
src/encryption/spiral.rs
Normal file
59
src/encryption/spiral.rs
Normal file
@@ -0,0 +1,59 @@
|
||||
use aes::Aes256;
|
||||
use cipher::{BlockDecryptMut, BlockEncryptMut, KeyIvInit};
|
||||
use thiserror::Error;
|
||||
|
||||
type AesEncryptor = cbc::Encryptor<Aes256>;
|
||||
type AesDecryptor = cbc::Decryptor<Aes256>;
|
||||
|
||||
#[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::<cipher::block_padding::Pkcs7>(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<String, SpiralCipherError> {
|
||||
if !data.starts_with("[") || data.len() <= 21 {
|
||||
return Ok(data);
|
||||
}
|
||||
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::<cipher::block_padding::Pkcs7>(encrypted_data.as_slice())
|
||||
.map_err(|e| {
|
||||
println!("error: {}", e);
|
||||
SpiralCipherError::DecryptFailed
|
||||
})?;
|
||||
Ok(String::from_utf8_lossy(decrypted_data.as_slice()).to_string())
|
||||
}
|
128
src/encryption/tdes.rs
Normal file
128
src/encryption/tdes.rs
Normal file
@@ -0,0 +1,128 @@
|
||||
use cipher::{BlockDecryptMut, BlockEncryptMut, KeyIvInit};
|
||||
use des::TdesEde3;
|
||||
|
||||
type TripleDesEncryptor = cbc::Encryptor<TdesEde3>;
|
||||
type TripleDesDecryptor = cbc::Decryptor<TdesEde3>;
|
||||
|
||||
/// 利用Sha512生成8字节的密钥
|
||||
///
|
||||
/// - `key` 原始密钥
|
||||
fn generate_key<T: AsRef<[u8]>>(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` 明文数据
|
||||
pub fn encrypt<T: AsRef<[u8]>, D: AsRef<[u8]>>(
|
||||
key: T,
|
||||
padding: super::Padding,
|
||||
plain_data: D,
|
||||
) -> Vec<u8> {
|
||||
let key = generate_key(key);
|
||||
let encryptor = TripleDesEncryptor::new(key.as_slice().into(), &key.into());
|
||||
let result = match padding {
|
||||
super::Padding::NoPadding => encryptor
|
||||
.encrypt_padded_vec_mut::<cipher::block_padding::NoPadding>(plain_data.as_ref()),
|
||||
super::Padding::ZeroPadding => encryptor
|
||||
.encrypt_padded_vec_mut::<cipher::block_padding::ZeroPadding>(plain_data.as_ref()),
|
||||
super::Padding::Pkcs7Padding => {
|
||||
encryptor.encrypt_padded_vec_mut::<cipher::block_padding::Pkcs7>(plain_data.as_ref())
|
||||
}
|
||||
};
|
||||
result
|
||||
}
|
||||
|
||||
/// 使用指定的密钥和填充方式对数据进行解密。
|
||||
///
|
||||
/// - `key` 密钥
|
||||
/// - `padding` 填充方式
|
||||
/// - `cipher_data` 密文数据
|
||||
pub fn decrypt<T: AsRef<[u8]>, D: AsRef<[u8]>>(
|
||||
key: T,
|
||||
padding: super::Padding,
|
||||
cipher_data: D,
|
||||
) -> Result<Vec<u8>, super::DecryptFailedError> {
|
||||
let key = generate_key(key);
|
||||
let decryptor = TripleDesDecryptor::new(key.as_slice().into(), &key.into());
|
||||
let result = match padding {
|
||||
super::Padding::NoPadding => decryptor
|
||||
.decrypt_padded_vec_mut::<cipher::block_padding::NoPadding>(cipher_data.as_ref()),
|
||||
super::Padding::ZeroPadding => decryptor
|
||||
.decrypt_padded_vec_mut::<cipher::block_padding::ZeroPadding>(cipher_data.as_ref()),
|
||||
super::Padding::Pkcs7Padding => {
|
||||
decryptor.decrypt_padded_vec_mut::<cipher::block_padding::Pkcs7>(cipher_data.as_ref())
|
||||
}
|
||||
};
|
||||
result.map_err(|_| super::DecryptFailedError {})
|
||||
}
|
||||
|
||||
/// 快捷无填充加密函数
|
||||
///
|
||||
/// - `key` 密钥
|
||||
/// - `plain_data` 明文数据
|
||||
pub fn encrypt_no_padding<T: AsRef<[u8]>, D: AsRef<[u8]>>(key: T, plain_data: D) -> Vec<u8> {
|
||||
encrypt(key, super::Padding::NoPadding, plain_data)
|
||||
}
|
||||
|
||||
/// 快捷无填充解密函数
|
||||
///
|
||||
/// - `key` 密钥
|
||||
/// - `cipher_data` 密文数据
|
||||
pub fn decrypt_no_padding<T: AsRef<[u8]>, D: AsRef<[u8]>>(
|
||||
key: T,
|
||||
cipher_data: D,
|
||||
) -> Result<Vec<u8>, super::DecryptFailedError> {
|
||||
decrypt(key, super::Padding::NoPadding, cipher_data)
|
||||
}
|
||||
|
||||
/// 快捷零填充加密函数
|
||||
///
|
||||
/// - `key` 密钥
|
||||
/// - `plain_data` 明文数据
|
||||
pub fn encrypt_zero_padding<T: AsRef<[u8]>, D: AsRef<[u8]>>(key: T, plain_data: D) -> Vec<u8> {
|
||||
encrypt(key, super::Padding::ZeroPadding, plain_data)
|
||||
}
|
||||
|
||||
/// 快捷零填充解密函数
|
||||
///
|
||||
/// - `key` 密钥
|
||||
/// - `cipher_data` 密文数据
|
||||
pub fn decrypt_zero_padding<T: AsRef<[u8]>, D: AsRef<[u8]>>(
|
||||
key: T,
|
||||
cipher_data: D,
|
||||
) -> Result<Vec<u8>, super::DecryptFailedError> {
|
||||
decrypt(key, super::Padding::ZeroPadding, cipher_data)
|
||||
}
|
||||
|
||||
/// 快捷Pkcs7填充加密函数
|
||||
///
|
||||
/// - `key` 密钥
|
||||
/// - `plain_data` 明文数据
|
||||
pub fn encrypt_pkcs7_padding<T: AsRef<[u8]>, D: AsRef<[u8]>>(key: T, plain_data: D) -> Vec<u8> {
|
||||
encrypt(key, super::Padding::Pkcs7Padding, plain_data)
|
||||
}
|
||||
|
||||
/// 快捷Pkcs7填充解密函数
|
||||
///
|
||||
/// - `key` 密钥
|
||||
/// - `cipher_data` 密文数据
|
||||
pub fn decrypt_pkcs7_padding<T: AsRef<[u8]>, D: AsRef<[u8]>>(
|
||||
key: T,
|
||||
cipher_data: D,
|
||||
) -> Result<Vec<u8>, super::DecryptFailedError> {
|
||||
decrypt(key, super::Padding::Pkcs7Padding, cipher_data)
|
||||
}
|
@@ -1,30 +1,72 @@
|
||||
pub mod md5 {
|
||||
use md5::Digest;
|
||||
|
||||
/// 计算输入内容的MD5哈希值,返回十六进制字符串。
|
||||
///
|
||||
/// - `input` 输入内容。
|
||||
pub fn hash<T: AsRef<[u8]>>(input: T) -> String {
|
||||
let mut hasher = md5::Md5::new();
|
||||
hasher.update(input);
|
||||
let result = hasher.finalize();
|
||||
crate::serialize::to_hex(result.as_slice())
|
||||
}
|
||||
|
||||
/// 计算输入内容的MD5哈希值,返回字节向量。
|
||||
///
|
||||
/// - `input` 输入内容。
|
||||
pub fn hash_hex<T: AsRef<[u8]>>(input: T) -> Vec<u8> {
|
||||
let mut hasher = md5::Md5::new();
|
||||
hasher.update(input);
|
||||
let result = hasher.finalize();
|
||||
result.to_vec()
|
||||
}
|
||||
}
|
||||
|
||||
pub mod sha1 {
|
||||
use sha1::Digest;
|
||||
|
||||
/// 计算输入内容的SHA1哈希值,返回十六进制字符串。
|
||||
///
|
||||
/// - `input` 输入内容。
|
||||
pub fn hash<T: AsRef<[u8]>>(input: T) -> String {
|
||||
let mut hasher = sha1::Sha1::new();
|
||||
hasher.update(input);
|
||||
let result = hasher.finalize();
|
||||
crate::serialize::to_hex(result.as_slice())
|
||||
}
|
||||
|
||||
/// 计算输入内容的SHA1哈希值,返回字节向量。
|
||||
///
|
||||
/// - `input` 输入内容。
|
||||
pub fn hash_hex<T: AsRef<[u8]>>(input: T) -> Vec<u8> {
|
||||
let mut hasher = sha1::Sha1::new();
|
||||
hasher.update(input);
|
||||
let result = hasher.finalize();
|
||||
result.to_vec()
|
||||
}
|
||||
}
|
||||
|
||||
pub mod sha512 {
|
||||
|
||||
/// 计算输入内容的SHA512哈希值,返回十六进制字符串。
|
||||
///
|
||||
/// - `input` 输入内容。
|
||||
pub fn hash<T: AsRef<[u8]>>(input: T) -> String {
|
||||
let mut hasher = hmac_sha512::Hash::new();
|
||||
hasher.update(input);
|
||||
let result = hasher.finalize();
|
||||
crate::serialize::to_hex(result.as_slice())
|
||||
}
|
||||
|
||||
/// 计算输入内容的SHA512哈希值,返回字节向量。
|
||||
///
|
||||
/// - `input` 输入内容。
|
||||
pub fn hash_hex<T: AsRef<[u8]>>(input: T) -> Vec<u8> {
|
||||
let mut hasher = hmac_sha512::Hash::new();
|
||||
hasher.update(input);
|
||||
let result = hasher.finalize();
|
||||
result.to_vec()
|
||||
}
|
||||
}
|
||||
|
||||
pub mod image_hash {
|
||||
@@ -35,6 +77,10 @@ pub mod image_hash {
|
||||
Detailed = 32,
|
||||
}
|
||||
|
||||
/// 计算输入图片的区块感知哈希值,返回十六进制字符串。
|
||||
///
|
||||
/// - `input` 输入图片。
|
||||
/// - `precision` 感知精度,感知精度越高,越能区分图片的细节,但是计算时间也越长。
|
||||
pub fn hash_image<T: image::GenericImage<Pixel = image::Rgb<u8>>>(
|
||||
input: &T,
|
||||
precision: Precision,
|
||||
|
@@ -5,4 +5,5 @@ pub mod hash;
|
||||
pub mod serial_code;
|
||||
pub mod serialize;
|
||||
pub mod signature;
|
||||
pub mod time;
|
||||
pub mod verifiy_code;
|
||||
|
114
src/serial_code/hail.rs
Normal file
114
src/serial_code/hail.rs
Normal file
@@ -0,0 +1,114 @@
|
||||
use core::time;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use chrono::NaiveDateTime;
|
||||
use once_cell::sync::{Lazy, OnceCell};
|
||||
use thiserror::Error;
|
||||
|
||||
const HAIL_PERIOD_START: Lazy<i64> = Lazy::new(|| {
|
||||
crate::time::date(2022, 2, 22)
|
||||
.map(|d| d.and_hms_opt(22, 22, 22))
|
||||
.flatten()
|
||||
.map(|dt| crate::time::attach_asia_shanghai(dt))
|
||||
.map(|dt| dt.timestamp())
|
||||
.unwrap_or_else(|| NaiveDateTime::MIN.timestamp())
|
||||
});
|
||||
type TimestampValidator = fn(i64) -> bool;
|
||||
type TimestampGenerator = fn() -> i64;
|
||||
|
||||
static INSTANCE: OnceCell<HailSerialCodeAlgorithm> = OnceCell::new();
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum HailSerialCodeAlgorithmError {
|
||||
#[error("Algorithm is already initialized")]
|
||||
AlgorithmAlreadyInitialized,
|
||||
}
|
||||
|
||||
/// 冰雹序列ID算法。
|
||||
/// 缩减了时间戳的位数,相比雪花算法可以额外支持近40年。
|
||||
pub struct HailSerialCodeAlgorithm {
|
||||
validator: Option<TimestampValidator>,
|
||||
generator: Option<TimestampGenerator>,
|
||||
host_id: i64,
|
||||
last_timestamp: Arc<Mutex<i64>>,
|
||||
counter: Arc<Mutex<i64>>,
|
||||
}
|
||||
|
||||
impl HailSerialCodeAlgorithm {
|
||||
/// 获取一个算法实例用于获取序列ID。
|
||||
pub fn get() -> &'static Self {
|
||||
INSTANCE.get().unwrap()
|
||||
}
|
||||
|
||||
/// 初始化整个序列ID算法。
|
||||
/// ! 注意,如果选择使用内置的主机独立时间戳生成器和验证器,那么将不能保证多主机状态下的序列ID一致性。可能会存在个别主机时间回拨现象。
|
||||
///
|
||||
/// - `host_id`:主机ID,取值范围为0~65535。
|
||||
/// - `timestamp_generator`:时间戳生成器,用于生成时间戳。如果不提供,则使用算法内置的主机独立时间戳生成器。
|
||||
/// - `timestamp_validatoe`:时间戳验证器,用于验证时间戳是否有效。如果不提供,则使用算法内置的主机独立时间戳验证器。
|
||||
pub fn initialize_algorithm(
|
||||
host_id: i64,
|
||||
timestamp_generator: Option<TimestampGenerator>,
|
||||
timestamp_validatoe: Option<TimestampValidator>,
|
||||
) -> Result<(), HailSerialCodeAlgorithmError> {
|
||||
let algorithm = HailSerialCodeAlgorithm {
|
||||
validator: timestamp_validatoe,
|
||||
generator: timestamp_generator,
|
||||
host_id,
|
||||
last_timestamp: Arc::new(Mutex::new(0)),
|
||||
counter: Arc::new(Mutex::new(0)),
|
||||
};
|
||||
INSTANCE
|
||||
.set(algorithm)
|
||||
.map_err(|_| HailSerialCodeAlgorithmError::AlgorithmAlreadyInitialized)
|
||||
}
|
||||
|
||||
/// 生成一个自计时起点以来的时间戳。
|
||||
fn generate_timestamp(&self) -> i64 {
|
||||
let current_time = crate::time::now_asia_shanghai().timestamp();
|
||||
current_time - *HAIL_PERIOD_START
|
||||
}
|
||||
|
||||
/// 生成一个64位长整型序列ID。
|
||||
pub fn generate_serial(&self) -> i64 {
|
||||
let last_timestamp = self.last_timestamp.clone();
|
||||
let mut last_timestamp = last_timestamp.lock().unwrap();
|
||||
let counter = self.counter.clone();
|
||||
let mut counter = counter.lock().unwrap();
|
||||
loop {
|
||||
let timestamp = if let Some(generator) = self.generator {
|
||||
generator()
|
||||
} else {
|
||||
self.generate_timestamp()
|
||||
};
|
||||
if let Some(validator) = self.validator {
|
||||
if !validator(timestamp) {
|
||||
std::thread::sleep(time::Duration::from_secs(1));
|
||||
continue;
|
||||
}
|
||||
} else if timestamp < *last_timestamp {
|
||||
std::thread::sleep(time::Duration::from_secs(1));
|
||||
continue;
|
||||
}
|
||||
if *last_timestamp < timestamp {
|
||||
// 对齐时间戳并重置序列计数器
|
||||
*last_timestamp = timestamp;
|
||||
*counter = 0;
|
||||
}
|
||||
*counter += 1;
|
||||
return (timestamp << 20) | ((self.host_id & 0xFFFF) << 16) | (*counter & 0xFFFF_FFFF);
|
||||
}
|
||||
}
|
||||
|
||||
/// 生成一个17位长前补零的序列ID字符串。
|
||||
pub fn generate_string_serial(&self) -> String {
|
||||
let serial = self.generate_serial();
|
||||
format!("{:017}", serial)
|
||||
}
|
||||
|
||||
/// 生成一个带字符串前缀17位长前补零的序列ID字符串。
|
||||
pub fn generate_prefixed_string_serial(&self, prefix: &str) -> String {
|
||||
let serial = self.generate_serial();
|
||||
format!("{}{:017}", prefix, serial)
|
||||
}
|
||||
}
|
@@ -1,4 +1,7 @@
|
||||
pub mod hail;
|
||||
|
||||
pub mod uuid {
|
||||
/// 生成一个UUID v4字符串。
|
||||
pub fn new() -> Box<String> {
|
||||
Box::from(uuid::Uuid::new_v4().to_string())
|
||||
}
|
||||
@@ -6,6 +9,8 @@ pub mod uuid {
|
||||
|
||||
pub mod short_uuid {
|
||||
const STR_SRC: &str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
|
||||
|
||||
/// 生成一个基于UUID v4的短UUID字符串。
|
||||
pub fn new(length: i16) -> Box<String> {
|
||||
let length = if length < 2 {
|
||||
2
|
||||
|
147
src/time/mod.rs
Normal file
147
src/time/mod.rs
Normal file
@@ -0,0 +1,147 @@
|
||||
use chrono::{DateTime, Datelike, Duration, FixedOffset, NaiveDate, NaiveDateTime, TimeZone, Utc};
|
||||
|
||||
/// 获取一个类型为`chrono::DateTime<chrono::FixedOffset>`类型的当前日期时间的实例。时间时区将自动被设置为东八区。
|
||||
pub fn now_asia_shanghai() -> DateTime<FixedOffset> {
|
||||
let utc_now = Utc::now();
|
||||
shift_to_asia_shanghai(utc_now)
|
||||
}
|
||||
|
||||
/// 将一个类型为`chrono::DateTime<chrono::Utc>`类型的日期时间转换到指定时区的时间实例。
|
||||
pub fn shift_tz<T: TimeZone>(datetime: DateTime<T>, zone: i64) -> DateTime<FixedOffset> {
|
||||
if zone.is_positive() {
|
||||
datetime.with_timezone(
|
||||
&FixedOffset::east_opt(Duration::hours(zone.abs()).num_seconds() as i32).unwrap(),
|
||||
)
|
||||
} else {
|
||||
datetime.with_timezone(
|
||||
&FixedOffset::west_opt(Duration::hours(zone.abs()).num_seconds() as i32).unwrap(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// 将一个类型为`chrono::DateTime<chrono::Utc>`类型的日期时间转换到东八区的时间实例。
|
||||
pub fn shift_to_asia_shanghai<T: TimeZone>(datetime: DateTime<T>) -> DateTime<FixedOffset> {
|
||||
shift_tz(datetime, 8)
|
||||
}
|
||||
|
||||
/// 直接给一个原生日期时间附加东八区的时区信息。
|
||||
pub fn attach_asia_shanghai(datetime: NaiveDateTime) -> DateTime<FixedOffset> {
|
||||
DateTime::<FixedOffset>::from_local(
|
||||
datetime,
|
||||
FixedOffset::east_opt(Duration::hours(8).num_seconds() as i32).unwrap(),
|
||||
)
|
||||
}
|
||||
|
||||
/// 从一个64位时间戳生成东八区的时间实例。这个函数主要用于处理使用`timestamp`方法直接返回的时间戳。
|
||||
///
|
||||
/// - `timestamp`:64位时间戳。
|
||||
pub fn from_utc_timestamp(timestamp: i64) -> DateTime<FixedOffset> {
|
||||
let request_time = NaiveDateTime::from_timestamp_micros(timestamp).unwrap();
|
||||
DateTime::<FixedOffset>::from_utc(
|
||||
request_time,
|
||||
FixedOffset::east_opt(Duration::hours(8).num_seconds() as i32).unwrap(),
|
||||
)
|
||||
}
|
||||
|
||||
/// 根据指定的日期生成一个时间对象,如果给定的日期不合法将返回空白内容。
|
||||
///
|
||||
/// - `year`:日期的年份。
|
||||
/// - `month`:日期的月份,从`1`开始。
|
||||
/// - `day`:日期的天数。
|
||||
pub fn date(year: i32, month: u32, day: u32) -> Option<NaiveDate> {
|
||||
NaiveDate::from_ymd_opt(year, month, day)
|
||||
}
|
||||
|
||||
/// 根据指定日期生成一个指定日期最开始时间的时间,精度为毫秒。
|
||||
///
|
||||
/// - `year`:指定日期的年份。
|
||||
/// - `month`:指定日期的月份,从`1`开始。
|
||||
/// - `day`:指定日期的天数。
|
||||
pub fn date_beginning(year: i32, month: u32, day: u32) -> Option<DateTime<FixedOffset>> {
|
||||
let timezone = FixedOffset::east_opt(Duration::hours(8).num_seconds() as i32).unwrap();
|
||||
NaiveDate::from_ymd_opt(year, month, day)
|
||||
.map(|d| d.and_hms_micro_opt(0, 0, 0, 0).unwrap())
|
||||
.map(|dt| DateTime::<FixedOffset>::from_local(dt, timezone))
|
||||
}
|
||||
|
||||
/// 根据给定的日期,返回其当天最开始的时间,精度为毫秒。
|
||||
///
|
||||
/// - `date`:给定的原始日期,注意:原始日期将被消耗掉。
|
||||
pub fn begin_of_date(date: NaiveDate) -> Option<DateTime<FixedOffset>> {
|
||||
let timezone = FixedOffset::east_opt(Duration::hours(8).num_seconds() as i32).unwrap();
|
||||
date.and_hms_micro_opt(0, 0, 0, 0)
|
||||
.map(|dt| DateTime::<FixedOffset>::from_local(dt, timezone))
|
||||
}
|
||||
|
||||
/// 根据给定的日期,返回其当天即将结束的时间,精度为毫秒。
|
||||
///
|
||||
/// - `date`:给定的原始日期,注意:原始日期将被消耗掉。
|
||||
pub fn end_of_date(date: NaiveDate) -> Option<DateTime<FixedOffset>> {
|
||||
let timezone = FixedOffset::east_opt(Duration::hours(8).num_seconds() as i32).unwrap();
|
||||
date.and_hms_micro_opt(23, 59, 59, 999_999)
|
||||
.map(|dt| DateTime::<FixedOffset>::from_local(dt, timezone))
|
||||
}
|
||||
|
||||
/// 根据指定日期生成一个指定日期结束时间的时间,精度为毫秒。
|
||||
///
|
||||
/// - `year`:指定日期的年份。
|
||||
/// - `month`:指定日期的月份,从`1`开始。
|
||||
/// - `day`:指定日期的天数。
|
||||
pub fn date_ending(year: i32, month: u32, day: u32) -> Option<DateTime<FixedOffset>> {
|
||||
let timezone = FixedOffset::east_opt(Duration::hours(8).num_seconds() as i32).unwrap();
|
||||
NaiveDate::from_ymd_opt(year, month, day)
|
||||
.map(|d| d.and_hms_micro_opt(23, 59, 59, 999_999).unwrap())
|
||||
.map(|dt| DateTime::<FixedOffset>::from_local(dt, timezone))
|
||||
}
|
||||
|
||||
/// 返回两个日期之间的月份差值。
|
||||
///
|
||||
/// - `control`:基准月份。
|
||||
/// - `test`:测试月份。
|
||||
pub fn difference_month(control: NaiveDate, test: NaiveDate) -> i32 {
|
||||
let difference_year = test.year() - control.year();
|
||||
let difference_month = (test.month() - control.month()) as i32;
|
||||
difference_year * 12 + difference_month
|
||||
}
|
||||
|
||||
/// 测试指定月份是否是基准月份的前一个月份。
|
||||
///
|
||||
/// - `control`:基准月份。
|
||||
/// - `test`:待测试的指定月份。
|
||||
pub fn is_previous_month(control: NaiveDate, test: NaiveDate) -> bool {
|
||||
difference_month(control, test) == 1
|
||||
}
|
||||
|
||||
/// 测试指定月份是否是基准月份的下一个月份。
|
||||
///
|
||||
/// - `control`:基准月份。
|
||||
/// - `test`:待测试的指定月份。
|
||||
pub fn is_next_month(control: NaiveDate, test: NaiveDate) -> bool {
|
||||
difference_month(control, test) == -1
|
||||
}
|
||||
|
||||
/// 生成符合Postgresql中日期类型最小值的日期。
|
||||
pub fn min_date() -> NaiveDate {
|
||||
NaiveDate::from_ymd_opt(1970, 1, 1).unwrap()
|
||||
}
|
||||
|
||||
/// 生成符合Postgresql中日期类型最小值的日期时间。
|
||||
pub fn min_datetime() -> DateTime<FixedOffset> {
|
||||
NaiveDate::from_ymd_opt(1970, 1, 1)
|
||||
.map(begin_of_date)
|
||||
.flatten()
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
/// 生成符合Postgresql中日期类型最大值的日期。
|
||||
pub fn max_date() -> NaiveDate {
|
||||
NaiveDate::from_ymd_opt(2099, 12, 31).unwrap()
|
||||
}
|
||||
|
||||
/// 生成符合Postgresql中日期类型最大值的日期时间。
|
||||
pub fn max_datetime() -> DateTime<FixedOffset> {
|
||||
NaiveDate::from_ymd_opt(2099, 12, 31)
|
||||
.map(end_of_date)
|
||||
.flatten()
|
||||
.unwrap()
|
||||
}
|
25
tests/aes_cryption.rs
Normal file
25
tests/aes_cryption.rs
Normal file
@@ -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."
|
||||
);
|
||||
}
|
||||
}
|
25
tests/des_cryption.rs
Normal file
25
tests/des_cryption.rs
Normal file
@@ -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."
|
||||
);
|
||||
}
|
||||
}
|
26
tests/spiral_cryption.rs
Normal file
26
tests/spiral_cryption.rs
Normal file
@@ -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);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user