Compare commits

20 Commits

Author SHA1 Message Date
徐涛
c94d95f5fb docs(readme): 更新 UUIDv7 功能完成状态
将 README.md 中的 UUIDv7 相关功能项从待办状态更新为已完成状态,
包括 UUIDv7 生成器、比较排序功能以及基于 Base36 的短 UUIDv7 转换器。
2025-10-09 17:10:07 +08:00
徐涛
07e0d3938a feat(serial_code): 添加UUIDv7生成器实现
新增UUIDv7生成器模块,支持基于自定义纪元的时间戳、节点ID和序列号生成
UUIDv7,并提供Base64、Base36及标准字符串格式的编码与解码功能。
该生成器具备线程安全性和全局单例初始化机制,确保分布式环境下的唯一性。
2025-10-09 17:09:41 +08:00
徐涛
21892e977f feat(time): 替换 chrono 为 time 库以优化时间处理
- 移除 chrono 依赖,引入 time 库并启用相关特性
- 重构时间工具模块,使用 OffsetDateTime 替代 DateTime
- 更新时间生成、转换和解析逻辑,提升代码一致性与可维护性
- 调整日期构造函数参数类型,增强类型安全
- 修正时间戳生成方式,确保东八区时间正确表示
2025-10-09 15:04:44 +08:00
徐涛
cc05fc9a40 docs(README): 更新 Base36 算法完成状态
将 README.md 中的 Base36 算法状态从未完成更新为已完成
2025-10-09 13:55:35 +08:00
徐涛
7b1834479f feat(serialize): 添加Base36编解码模块
新增Base36编码和解码功能,支持字节数据与Base36字符串之间的相互转换,
并提供对i64整数的Base36编解码支持。同时更新了相关依赖版本以提升安全性
和性能。

- 新增 `base36` 模块,实现完整的Base36编解码逻辑
- 支持去除填充字符 `=` 后的容错处理
- 提供 `encode`, `decode`, `encode_int64`, `decode_to_int64` 等公共接口
- 更新 Cargo.toml 中多项依赖至最新稳定版本
2025-10-09 13:38:20 +08:00
徐涛
ea194a1fd1 docs(readme): 更新已实现的校验和算法列表
将 BLAKE2b 和 BLAKE3 校验和算法标记为已完成状态,
反映这些算法的便捷封装已在工具箱中实现。
2025-10-09 13:16:52 +08:00
徐涛
5b4dff402c feat(hash): 添加 Blake3 哈希算法支持
新增 blake3 模块,提供多种长度的 Blake3 哈希计算功能,
包括 224、256、384 和 512 位输出格式,支持字节数组和文件输入,
并可选择返回字节数组或十六进制字符串。同时在 hash 模块中导出该功能。
2025-10-09 13:14:43 +08:00
徐涛
0697e61f35 feat(hash): 添加 Blake2b 哈希算法支持
新增 blake2b 模块,提供多种长度的 Blake2b 哈希计算功能,
包括 224、256、384 和 512 位版本,并支持对字节数组和文件进行哈希计算。
同时支持返回字节数组和十六进制字符串两种格式。
在 Cargo.toml 中添加了 blake2b_simd 依赖以实现该功能。
2025-10-09 11:18:58 +08:00
徐涛
a89f9aff15 docs(readme): 更新功能列表描述并添加新特性支持说明
- 为散列算法和 UUID 生成器添加便捷封装说明
- 新增 BLAKE2b 和 BLAKE3 校验和算法(待实现)
- 添加 UUIDv7 生成器及相关功能(待实现)
- 新增 Base36 序列化算法(待实现)
2025-10-09 10:49:52 +08:00
徐涛
51a7a48962 enhance(time):快速调整时区的函数增加泛型支持。 2023-07-07 13:42:07 +08:00
徐涛
3f86e75518 enhance(spiral):统一螺旋算法的特性,如果起始位和长度检测失败,则直接返回密文。 2023-07-04 14:59:28 +08:00
徐涛
dbcdfc426e fix(hail):尝试修复冰雹算法中可能存在的死锁问题。 2023-07-04 09:07:13 +08:00
徐涛
d1c19355a5 doc:补充一些函数的文档。 2023-07-03 22:39:32 +08:00
徐涛
e6447fdd43 feat(serial):基本完成冰雹ID生成器设计,基本完成全部计划中功能设计。 2023-07-03 22:33:15 +08:00
徐涛
3f3191fcea feat(utils):增加常用的日期时间函数。 2023-07-03 21:23:41 +08:00
徐涛
6f20341c85 doc(crypto):修改相应的文档。 2023-07-03 17:29:03 +08:00
徐涛
d9d24dbb54 feat(crypto):增加螺旋自解密加密算法支持函数。 2023-07-03 17:27:27 +08:00
徐涛
9a913b4bf4 feat(rsa):基本完成RSA系列加密算法和签名算法的函数。 2023-07-03 15:45:14 +08:00
徐涛
551209d4f1 feat(crypt):完成3DES加密算法的工具函数。 2023-07-02 17:56:12 +08:00
徐涛
56fef4c3de feat(crypt):完成DES便捷加密函数。 2023-07-02 17:32:49 +08:00
19 changed files with 1701 additions and 27 deletions

View File

@@ -9,18 +9,31 @@ crate-type = ["dylib", "rlib"]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
aes = "0.8.3"
base64 = "0.21.2"
blockhash = "0.5.0"
aes = "0.8.4"
base64 = "0.22.1"
blake2b_simd = "1.0.3"
blake3 = { version = "1.8.2", features = ["serde", "digest"] }
blockhash = "1.0.0"
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"
hmac-sha256 = "1.1.12"
hmac-sha512 = "1.1.7"
image = "0.25.8"
md-5 = "0.10.6"
rand = "0.8.5"
sha1 = "0.10.5"
thiserror = "1.0.40"
uuid = { version = "1.4.0", features = ["v4", "fast-rng"] }
rsa = { version = "0.9.2", features = ["sha2"] }
sha1 = "0.10.6"
sha2 = "0.10.9"
thiserror = "2.0.17"
time = { version = "0.3.44", features = [
"formatting",
"local-offset",
"macros",
"parsing",
"rand",
"serde",
"serde-human-readable",
] }
uuid = { version = "1.18.1", features = ["v4", "fast-rng"] }

View File

@@ -3,35 +3,46 @@
Rust 中可以使用的常用辅助功能工具箱。主要配备以下功能:
- 加解密算法
- [ ] 随机密钥自解密算法
- [x] 螺旋随机密钥自解密算法
- [x] AES-CBC 便捷加解密算法
- [x] No Padding
- [x] ZerosPadding
- [x] Pkcs7Padding
- [ ] DES-CBC 便捷加解密算法
- [ ] No Padding
- [ ] ZerosPadding
- [ ] Pkcs7Padding
- [ ] 3DES 便捷加解密算法
- [ ] RSA 加解密算法
- [ ] 1024 位长
- [ ] 2048 位长
- [ ] KeyPair 生成器
- [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] 图像感知散列算法
- [x] Sha512 散列算法(便捷封装)
- [x] Sha1 散列算法(便捷封装)
- [x] MD5 散列算法(便捷封装)
- [x] 图像感知散列算法(便捷封装)
- [x] BLAKE2b 校验和算法(便捷封装)
- [x] BLAKE3 校验和算法(便捷封装)
- 唯一序列号生成器
- [ ] 改进版雪花 ID 生成器(短主机精简日期版)
- [x] UUID 生成器
- [x] 冰雹 ID 生成器(短主机精简日期版雪花 ID)
- [x] UUIDv4 生成器
- [x] UUIDv7 生成器(自定义时间戳分布式版本)
- [x] UUIDv7 比较及排序
- [x] 基于 Base36 的 short UUIDv7 转换器
- [x] short UUID 生成器
- 签名算法
- [ ] RSA 签名算法
- [x] RSA 签名算法
- 验证码生成器
- [x] 随机验证码生成算法
- 序列化算法
- [x] Base64 算法
- [x] Base36 算法
- [x] Hex 直转
- 常用工具函数
- [x] 日期时间函数
本工具箱仅可支持于 Rust 程序中使用,可以编译为`rlib`或者`dylib`

128
src/encryption/des.rs Normal file
View 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)
}

View File

@@ -1,6 +1,10 @@
use thiserror::Error;
pub mod aes;
pub mod des;
pub mod rsa;
pub mod spiral;
pub mod tdes;
pub enum Padding {
NoPadding,

338
src/encryption/rsa.rs Normal file
View 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
View 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
View 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)
}

97
src/hash/blake2b/mod.rs Normal file
View File

@@ -0,0 +1,97 @@
use blake2b_simd::{blake2b as blake2b_hasher, Params, State};
use std::fs::File;
use std::io::{self, Read};
use std::path::Path;
/// 根据给定的位数返回一个Blake2b散列实例。
fn hasher_select(bit_size: usize) -> State {
match bit_size {
224 => Params::new().hash_length(28).to_state(), // 224 bits = 28 bytes
384 => Params::new().hash_length(48).to_state(), // 384 bits = 48 bytes
512 => Params::new().hash_length(64).to_state(), // 512 bits = 64 bytes
256 | _ => Params::new().hash_length(32).to_state(), // 256 bits = 32 bytes
}
}
/// 计算给定字节数组的Blake2b校验和返回字节数组。
pub fn blake2b(data: &[u8]) -> Vec<u8> {
blake2b_hasher(data).as_bytes().to_vec()
}
/// 计算给定字节数组的Blake2b/256校验和返回字节数组。
pub fn blake2b_256(data: &[u8]) -> Vec<u8> {
let mut hasher = hasher_select(256);
hasher.update(data);
hasher.finalize().as_bytes().to_vec()
}
/// 计算给定字节数组的Blake2b/384校验和返回字节数组。
pub fn blake2b_384(data: &[u8]) -> Vec<u8> {
let mut hasher = hasher_select(384);
hasher.update(data);
hasher.finalize().as_bytes().to_vec()
}
/// 计算给定字节数组的Blake2b/224校验和返回字节数组。
pub fn blake2b_224(data: &[u8]) -> Vec<u8> {
let mut hasher = hasher_select(224);
hasher.update(data);
hasher.finalize().as_bytes().to_vec()
}
/// 计算给定字节数组的Blake2b校验和返回十六进制字符串。
pub fn blake2b_hex(data: &[u8]) -> String {
hex::encode(blake2b(data))
}
/// 计算给定字节数组的Blake2b/256校验和返回十六进制字符串。
pub fn blake2b_256_hex(data: &[u8]) -> String {
hex::encode(blake2b_256(data))
}
/// 计算给定字节数组的Blake2b/384校验和返回十六进制字符串。
pub fn blake2b_384_hex(data: &[u8]) -> String {
hex::encode(blake2b_384(data))
}
/// 计算给定字节数组的Blake2b/224校验和返回十六进制字符串。
pub fn blake2b_224_hex(data: &[u8]) -> String {
hex::encode(blake2b_224(data))
}
/// 根据给定位数计算一个字节数组的Blake2b校验和返回字节数组。
pub fn sum(data: &[u8], bit_size: Option<usize>) -> Vec<u8> {
let size = bit_size.unwrap_or(512);
let mut hasher = hasher_select(size);
hasher.update(data);
hasher.finalize().as_bytes().to_vec()
}
/// 根据给定位数计算一个字节数组的Blake2b校验和返回十六进制字符串。
pub fn sum_hex(data: &[u8], bit_size: Option<usize>) -> String {
hex::encode(sum(data, bit_size))
}
/// 根据给定位数计算一个文件的Blake2b校验和返回字节数组。
pub fn sum_file<P: AsRef<Path>>(file_path: P, bit_size: Option<usize>) -> io::Result<Vec<u8>> {
let size = bit_size.unwrap_or(512);
let mut file = File::open(file_path)?;
let mut hasher = hasher_select(size);
let mut buffer = [0; 8192];
loop {
let bytes_read = file.read(&mut buffer)?;
if bytes_read == 0 {
break;
}
hasher.update(&buffer[..bytes_read]);
}
Ok(hasher.finalize().as_bytes().to_vec())
}
/// 根据给定位数计算一个文件的Blake2b校验和返回十六进制字符串。
pub fn sum_file_hex<P: AsRef<Path>>(file_path: P, bit_size: Option<usize>) -> io::Result<String> {
let hash = sum_file(file_path, bit_size)?;
Ok(hex::encode(hash))
}

109
src/hash/blake3/mod.rs Normal file
View File

@@ -0,0 +1,109 @@
use blake3::Hasher;
use std::fs::File;
use std::io::{Read, Result as IoResult};
use std::path::Path;
/// 计算给定字节数组的Blake3/512校验和返回字节数组。
pub fn blake3(data: &[u8]) -> Vec<u8> {
let mut hasher = Hasher::new();
hasher.update(data);
let mut out = vec![0u8, 64];
hasher.finalize_xof().fill(&mut out);
out
}
/// 计算给定字节数组的Blake3/256校验和返回字节数组。
pub fn blake3_256(data: &[u8]) -> Vec<u8> {
let mut hasher = Hasher::new();
hasher.update(data);
hasher.finalize().as_bytes().to_vec()
}
/// 计算给定字节数组的Blake3/384校验和返回字节数组。
pub fn blake3_384(data: &[u8]) -> Vec<u8> {
let mut hasher = Hasher::new();
hasher.update(data);
let mut out = vec![0u8, 48];
hasher.finalize_xof().fill(&mut out);
out
}
/// 计算给定字节数组的Blake3/224校验和返回字节数组。
pub fn blake3_224(data: &[u8]) -> Vec<u8> {
let mut hasher = Hasher::new();
hasher.update(data);
let mut out = vec![0u8, 28];
hasher.finalize_xof().fill(&mut out);
out
}
/// 计算给定字节数组的Blake3校验和返回十六进制字符串。
pub fn blake3_hex(data: &[u8]) -> String {
hex::encode(blake3(data))
}
/// 计算给定字节数组的Blake3/256校验和返回十六进制字符串。
pub fn blake3_256_hex(data: &[u8]) -> String {
hex::encode(blake3_256(data))
}
/// 计算给定字节数组的Blake3/384校验和返回十六进制字符串。
pub fn blake3_384_hex(data: &[u8]) -> String {
hex::encode(blake3_384(data))
}
/// 计算给定字节数组的Blake3/224校验和返回十六进制字符串。
pub fn blake3_224_hex(data: &[u8]) -> String {
hex::encode(blake3_224(data))
}
/// 根据给定位数计算一个字节数组的Blake3校验和返回字节数组。
pub fn sum(data: &[u8], bit_size: Option<usize>) -> Vec<u8> {
match bit_size {
Some(bit_size) => match bit_size {
224 => blake3_224(data),
256 => blake3_256(data),
384 => blake3_384(data),
512 | _ => blake3(data),
},
None => blake3(data),
}
}
/// 根据给定位数计算一个字节数组的Blake3校验和返回十六进制字符串。
pub fn sum_hex(data: &[u8], bit_size: Option<usize>) -> String {
hex::encode(sum(data, bit_size))
}
/// 根据给定位数计算一个文件的Blake3校验和返回字节数组。
pub fn sum_file<P: AsRef<Path>>(file: P, bit_size: Option<usize>) -> IoResult<Vec<u8>> {
let mut f = File::open(file)?;
let mut hasher = Hasher::new();
let mut buffer = [0; 8192];
loop {
let bytes_read = f.read(&mut buffer)?;
if bytes_read == 0 {
break;
}
hasher.update(&buffer[..bytes_read]);
}
let mut out = match bit_size {
Some(bit_size) => match bit_size {
224 => vec![0u8, 28],
256 => vec![0u8, 32],
384 => vec![0u8, 48],
512 | _ => vec![0u8, 64],
},
None => vec![0u8, 64],
};
hasher.finalize_xof().fill(&mut out);
Ok(out)
}
/// 根据给定位数计算一个文件的Blake3校验和返回十六进制字符串。
pub fn sum_file_hex<P: AsRef<Path>>(file: P, bit_size: Option<usize>) -> IoResult<String> {
let hash = sum_file(file, bit_size)?;
Ok(hex::encode(hash))
}

View File

@@ -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,
@@ -47,3 +93,6 @@ pub mod image_hash {
}
}
}
pub mod blake2b;
pub mod blake3;

View File

@@ -5,4 +5,5 @@ pub mod hash;
pub mod serial_code;
pub mod serialize;
pub mod signature;
pub mod time;
pub mod verifiy_code;

112
src/serial_code/hail.rs Normal file
View File

@@ -0,0 +1,112 @@
use core::time;
use std::sync::{Arc, LazyLock, Mutex, OnceLock};
use ::time::{macros::datetime, OffsetDateTime};
use thiserror::Error;
const HAIL_PERIOD_START: LazyLock<i64> = LazyLock::new(|| {
crate::time::date(2022, 2, 22)
.map(|d| d.with_hms_nano(22, 22, 22, 222_222_222).unwrap())
.map(crate::time::attach_asia_shanghai)
.map(OffsetDateTime::unix_timestamp)
.unwrap_or_else(|| datetime!(1970-01-01 0:00 +8).unix_timestamp())
});
type TimestampValidator = fn(i64) -> bool;
type TimestampGenerator = fn() -> i64;
static INSTANCE: OnceLock<HailSerialCodeAlgorithm> = OnceLock::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().unix_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)
}
}

View File

@@ -1,4 +1,8 @@
pub mod hail;
pub mod uuidv7;
pub mod uuid {
/// 生成一个UUID v4字符串。
pub fn new() -> Box<String> {
Box::from(uuid::Uuid::new_v4().to_string())
}
@@ -6,6 +10,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

291
src/serial_code/uuidv7.rs Normal file
View File

@@ -0,0 +1,291 @@
use std::{
sync::{Mutex, OnceLock},
thread,
time::Duration,
};
use thiserror::Error;
use time::UtcDateTime;
#[derive(Debug, Error)]
pub enum UuidV7Error {
#[error("UUIDv7 Generator not initialized")]
GeneratorNotInitialized,
#[error("UUIDv7 Node ID exceeded the maximum supports")]
NodeIdExceeded,
#[error("Invalid UUIDv7 string format")]
InvalidStringFormat,
#[error("Invalid Base64 format string")]
InvalidBase64Format,
}
const EPOCH: i64 = 1645566142222; // 自定义纪元2022-02-22 22:22:22.222 UTC
const NODE_BITS: u8 = 5; // 主机编号容量为032
const SEQUENCE_BITS: u8 = 18; // 每毫秒生成序列号最大为2^18-1即262144个
const MAX_NODE_ID: u16 = (1 << NODE_BITS) - 1;
const MAX_SEQUENCE: u32 = (1 << SEQUENCE_BITS) - 1;
const TIMESTAMP_SHIFTS: u8 = NODE_BITS + SEQUENCE_BITS;
const NODE_SHIFTS: u8 = SEQUENCE_BITS;
pub struct Uuidv7Generator {
node_id: u16,
last_timestamp: i64,
sequence: u32,
}
#[allow(dead_code)]
pub struct Uuidv7Components {
timestamp: i64, // 毫秒时间戳(相对于自定义纪元)
node_id: u16, // 5位节点ID
sequence: u32, // 18位序列号
version: u8, // 版本号应为7
variant: u8, // 变体应为2表示10xx
raw_bytes: [u8; 16], // 原始字节
}
static GENERATOR: OnceLock<Mutex<Uuidv7Generator>> = OnceLock::new();
/// 获取UUIDv7生成器实例如果实例未初始化则返回错误。
pub fn generator<'a>() -> Result<&'a Mutex<Uuidv7Generator>, UuidV7Error> {
GENERATOR.get().ok_or(UuidV7Error::GeneratorNotInitialized)
}
/// 初始化UUIDv7生成器实例。
///
/// - `node_id`节点ID取值范围032。
pub fn init_generator(node_id: u16) -> Result<(), UuidV7Error> {
if node_id > MAX_NODE_ID {
return Err(UuidV7Error::NodeIdExceeded);
}
GENERATOR
.set(Mutex::new(Uuidv7Generator::new(node_id)))
.map_err(|_| UuidV7Error::GeneratorNotInitialized)
}
impl Uuidv7Generator {
pub fn new(node_id: u16) -> Self {
Self {
node_id,
last_timestamp: EPOCH,
sequence: 0,
}
}
fn now(&self) -> i64 {
(UtcDateTime::now().unix_timestamp_nanos() / 1_000_000 - EPOCH as i128) as i64
}
pub fn next(&mut self) -> Uuidv7Components {
let mut now = self.now();
if now < self.last_timestamp {
now = self.last_timestamp;
}
if now == self.last_timestamp {
self.sequence += 1;
if self.sequence > MAX_SEQUENCE {
thread::sleep(Duration::from_secs(1));
now = self.now();
self.sequence = 0;
}
} else {
self.sequence = 0;
}
self.last_timestamp = now;
Uuidv7Components {
timestamp: now,
node_id: self.node_id,
sequence: self.sequence,
version: 7,
variant: 2,
raw_bytes: [0; 16],
}
}
}
impl Uuidv7Components {
pub fn bytes(&self) -> [u8; 16] {
let mut uuid = [0u8; 16];
// 时间戳48 位)
let timestamp = (self.timestamp as u64) << TIMESTAMP_SHIFTS;
let seq_and_node = ((self.sequence as u64) << NODE_SHIFTS) | (self.node_id as u64);
// 写入高位时间戳
uuid[0] = (timestamp >> 56) as u8;
uuid[1] = (timestamp >> 48) as u8;
uuid[2] = (timestamp >> 40) as u8;
uuid[3] = (timestamp >> 32) as u8;
uuid[4] = (timestamp >> 24) as u8;
uuid[5] = (timestamp >> 16) as u8;
// 写入低位时间戳 + 版本号4 位)
uuid[6] = ((timestamp >> 8) as u8) | 0x70; // version 7
// 写入 seq + node
uuid[7] = timestamp as u8;
uuid[8] = ((seq_and_node >> 16) as u8) | 0x80; // variant 10xx
uuid[9] = (seq_and_node >> 8) as u8;
uuid[10] = seq_and_node as u8;
// 剩余位使用随机数填充
use rand::RngCore;
let mut rng = rand::thread_rng();
rng.fill_bytes(&mut uuid[11..16]);
uuid
}
pub fn to_base64(&self) -> String {
let uuid = self.bytes();
crate::serialize::to_base64_str(uuid)
}
pub fn try_from_base64<S: AsRef<str>>(uuid_str: S) -> Result<Self, UuidV7Error> {
let bytes = crate::serialize::from_base64_str(uuid_str.as_ref())
.map_err(|_| UuidV7Error::InvalidBase64Format)?;
if bytes.len() != 16 {
return Err(UuidV7Error::InvalidStringFormat);
}
let mut uuid_bytes = [0u8; 16];
uuid_bytes.copy_from_slice(&bytes);
Uuidv7Components::try_from(uuid_bytes)
}
pub fn to_base36(&self) -> String {
let uuid = self.bytes();
crate::serialize::base36::encode(&uuid)
}
pub fn try_from_base36<S: AsRef<str>>(uuid_str: S) -> Result<Self, UuidV7Error> {
let bytes = crate::serialize::base36::decode(uuid_str.as_ref())
.map_err(|_| UuidV7Error::InvalidStringFormat)?;
if bytes.len() != 16 {
return Err(UuidV7Error::InvalidStringFormat);
}
let mut uuid_bytes = [0u8; 16];
uuid_bytes.copy_from_slice(&bytes);
Uuidv7Components::try_from(uuid_bytes)
}
}
impl ToString for Uuidv7Components {
fn to_string(&self) -> String {
let uuid = self.bytes();
format!(
"{}-{}-{}-{}-{}",
hex::encode(&uuid[0..4]),
hex::encode(&uuid[4..6]),
hex::encode(&uuid[6..8]),
hex::encode(&uuid[8..10]),
hex::encode(&uuid[10..16])
)
}
}
impl PartialEq for Uuidv7Components {
fn eq(&self, other: &Self) -> bool {
self.timestamp == other.timestamp
&& self.node_id == other.node_id
&& self.sequence == other.sequence
}
}
impl Eq for Uuidv7Components {}
impl PartialOrd for Uuidv7Components {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
if self.timestamp != other.timestamp {
return Some(self.timestamp.cmp(&other.timestamp));
}
if self.sequence != other.sequence {
return Some(self.sequence.cmp(&other.sequence));
}
if self.node_id != other.node_id {
// 注意这里与时间戳和序列号不同node_id的比较逻辑是反的
// 这与Go代码中的Compare方法保持一致
return Some(other.node_id.cmp(&self.node_id));
}
Some(std::cmp::Ordering::Equal)
}
}
impl Ord for Uuidv7Components {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.partial_cmp(other).unwrap()
}
}
impl TryFrom<[u8; 16]> for Uuidv7Components {
type Error = UuidV7Error;
fn try_from(value: [u8; 16]) -> Result<Self, Self::Error> {
// 提取时间戳前48位
let timestamp = ((value[0] as i64) << 40)
| ((value[1] as i64) << 32)
| ((value[2] as i64) << 24)
| ((value[3] as i64) << 16)
| ((value[4] as i64) << 8)
| (value[5] as i64);
// 提取版本号第6字节的高4位
let version = (value[6] >> 4) as u8;
// 提取变体第8字节的高2位
let variant = (value[8] >> 6) as u8;
// 提取序列号和节点ID
// 第8字节的低6位 + 第9字节 + 第10字节组成23位
let seq_and_node = (((value[8] & 0x3F) as i64) << 16) // 第8字节低6位
| ((value[9] as i64) << 8) // 第9字节
| (value[10] as i64); // 第10字节
// 分离序列号高18位和节点ID低5位
let sequence = (seq_and_node >> 5) as u32;
let node_id = (seq_and_node & 0x1F) as u16;
Ok(Uuidv7Components {
timestamp,
node_id,
sequence,
version,
variant,
raw_bytes: value,
})
}
}
impl TryFrom<String> for Uuidv7Components {
type Error = UuidV7Error;
fn try_from(value: String) -> Result<Self, Self::Error> {
// 移除连字符
let clean_str = value.replace("-", "");
// 验证长度
if clean_str.len() != 32 {
return Err(UuidV7Error::InvalidStringFormat);
}
// 解码十六进制字符串
let bytes = hex::decode(&clean_str).map_err(|_| UuidV7Error::InvalidStringFormat)?;
// 转换为数组
if bytes.len() != 16 {
return Err(UuidV7Error::InvalidStringFormat);
}
let mut uuid_bytes = [0u8; 16];
uuid_bytes.copy_from_slice(&bytes);
Uuidv7Components::try_from(uuid_bytes)
}
}

144
src/serialize/base36.rs Normal file
View File

@@ -0,0 +1,144 @@
use thiserror::Error;
const BASE36_CHARS: &[u8] = b"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
#[derive(Debug, Error)]
pub enum Base36Error {
#[error("number too large for i64")]
NumberTooLarge,
#[error("invalid character '{0}'")]
InvalidCharacter(char),
}
/// 将字节数据编码为Base36字符串(大写),使用=作为padding字符
pub fn encode(src: &[u8]) -> String {
if src.is_empty() {
return String::new();
}
// 将字节转换为大数表示这里使用Vec<u8>模拟大整数运算
let mut num = src.to_vec();
// 去除前导零但保留至少一个字节
while num.len() > 1 && num[0] == 0 {
num.remove(0);
}
// 如果输入为全零字节,则直接返回"0"
if num.iter().all(|&b| b == 0) {
return "0".to_string();
}
// 进行Base36编码
let mut result = Vec::new();
let base = 36u8;
// 重复除以36获取余数作为字符
while !num.is_empty() && !(num.len() == 1 && num[0] == 0) {
let mut remainder: u16 = 0;
let mut new_num = Vec::new();
let mut first = true;
for &byte in &num {
remainder = remainder * 256 + byte as u16;
let quotient = remainder / base as u16;
remainder %= base as u16;
if quotient > 0 || !first {
new_num.push(quotient as u8);
first = false;
}
}
// 如果new_num为空说明这是最后一次除法
if !new_num.is_empty() || num.len() > 1 {
num = new_num;
} else {
num.clear();
}
result.push(BASE36_CHARS[remainder as usize]);
}
// 反转字符串,因为我们是从低位开始计算的
result.reverse();
String::from_utf8(result).unwrap()
}
/// 将Base36字符串(可为任意大小写)解码为字节数组
pub fn decode(src: &str) -> Result<Vec<u8>, Base36Error> {
if src.is_empty() {
return Ok(Vec::new());
}
// 移除padding字符并转换为大写
let cleaned: String = src.chars().filter(|&c| c != '=').collect();
let cleaned = cleaned.to_uppercase();
// 使用Vec<u8>模拟大整数进行解码
let mut num = Vec::new();
let base = 36u16;
for c in cleaned.chars() {
let digit = match c {
'0'..='9' => c as u16 - '0' as u16,
'A'..='Z' => c as u16 - 'A' as u16 + 10,
_ => return Err(Base36Error::InvalidCharacter(c)),
};
// num = num * 36 + digit
let mut carry = digit as u32;
for byte in num.iter_mut() {
let product = *byte as u32 * base as u32 + carry;
*byte = (product % 256) as u8;
carry = product / 256;
}
while carry > 0 {
num.push((carry % 256) as u8);
carry /= 256;
}
}
// 反转字节数组,因为我们的计算是从低位开始的
num.reverse();
// 如果结果为空,返回单个零字节
if num.is_empty() {
num.push(0);
}
Ok(num)
}
/// Encode的别名用于保持与标准库一致的命名
pub fn encode_to_string(src: &[u8]) -> String {
encode(src)
}
/// Decode的别名用于保持与标准库一致的命名
pub fn decode_string(src: &str) -> Result<Vec<u8>, Base36Error> {
decode(src)
}
/// 将int64转换为Base36字符串
pub fn encode_int64(num: i64) -> String {
let bytes = num.to_be_bytes().to_vec();
encode(&bytes)
}
/// 将Base36字符串解码为int64
pub fn decode_to_int64(src: &str) -> Result<i64, Base36Error> {
let bytes = decode(src)?;
if bytes.len() > 8 {
return Err(Base36Error::NumberTooLarge);
}
let mut array = [0u8; 8];
let start = 8 - bytes.len();
for (i, &byte) in bytes.iter().enumerate() {
array[start + i] = byte;
}
Ok(i64::from_be_bytes(array))
}

View File

@@ -1,6 +1,8 @@
use base64::Engine;
use thiserror::Error;
pub mod base36;
#[derive(Debug, Error)]
pub enum HexSerializeError {
#[error("Invalid hex char: {0}")]

131
src/time/mod.rs Normal file
View File

@@ -0,0 +1,131 @@
use std::i64;
use time::{macros::offset, Date, Month, OffsetDateTime, PrimitiveDateTime, Time, UtcOffset};
/// 获取一个类型为`chrono::DateTime<chrono::FixedOffset>`类型的当前日期时间的实例。时间时区将自动被设置为东八区。
pub fn now_asia_shanghai() -> OffsetDateTime {
let utc_now = OffsetDateTime::now_utc();
shift_to_asia_shanghai(utc_now)
}
/// 将一个类型为`chrono::DateTime<chrono::Utc>`类型的日期时间转换到指定时区的时间实例。
pub fn shift_tz(datetime: OffsetDateTime, zone: i8) -> OffsetDateTime {
datetime.to_offset(UtcOffset::from_hms(zone.clamp(-25, 25), 0, 0).unwrap())
}
/// 将一个类型为`chrono::DateTime<chrono::Utc>`类型的日期时间转换到东八区的时间实例。
pub fn shift_to_asia_shanghai(datetime: OffsetDateTime) -> OffsetDateTime {
datetime.to_offset(offset!(+8))
}
/// 直接给一个原生日期时间附加东八区的时区信息。
pub fn attach_asia_shanghai(datetime: PrimitiveDateTime) -> OffsetDateTime {
let utc_date_time = datetime.as_utc();
let offseted_date_time = OffsetDateTime::from(utc_date_time);
offseted_date_time.replace_offset(offset!(+8))
}
/// 从一个64位时间戳生成东八区的时间实例。这个函数主要用于处理使用`timestamp`方法直接返回的时间戳。
///
/// - `timestamp`64位时间戳。
pub fn from_utc_timestamp(timestamp: i64) -> OffsetDateTime {
let request_time = OffsetDateTime::from_unix_timestamp(timestamp.clamp(0, i64::MAX)).unwrap();
request_time.to_offset(offset!(+8))
}
/// 根据指定的日期生成一个时间对象,如果给定的日期不合法将返回空白内容。
///
/// - `year`:日期的年份。
/// - `month`:日期的月份,从`1`开始。
/// - `day`:日期的天数。
pub fn date(year: i32, month: u8, day: u8) -> Option<Date> {
Date::from_calendar_date(year, Month::try_from(month.clamp(1, 12)).unwrap(), day).ok()
}
/// 根据指定日期生成一个指定日期最开始时间的时间,精度为毫秒。
///
/// - `year`:指定日期的年份。
/// - `month`:指定日期的月份,从`1`开始。
/// - `day`:指定日期的天数。
pub fn date_beginning(year: i32, month: u8, day: u8) -> OffsetDateTime {
OffsetDateTime::new_in_offset(
Date::from_calendar_date(year, Month::try_from(month.clamp(1, 12)).unwrap(), day).unwrap(),
Time::MIDNIGHT,
offset!(+8),
)
}
/// 根据给定的日期,返回其当天最开始的时间,精度为毫秒。
///
/// - `date`:给定的原始日期,注意:原始日期将被消耗掉。
pub fn begin_of_date(date: Date) -> OffsetDateTime {
OffsetDateTime::new_in_offset(date, Time::MIDNIGHT, offset!(+8))
}
/// 根据给定的日期,返回其当天即将结束的时间,精度为毫秒。
///
/// - `date`:给定的原始日期,注意:原始日期将被消耗掉。
pub fn end_of_date(date: Date) -> OffsetDateTime {
OffsetDateTime::new_in_offset(date, Time::MAX, offset!(+8))
}
/// 根据指定日期生成一个指定日期结束时间的时间,精度为毫秒。
///
/// - `year`:指定日期的年份。
/// - `month`:指定日期的月份,从`1`开始。
/// - `day`:指定日期的天数。
pub fn date_ending(year: i32, month: u8, day: u8) -> Option<OffsetDateTime> {
Date::from_calendar_date(year, Month::try_from(month.clamp(1, 12)).unwrap(), day)
.ok()
.map(end_of_date)
}
/// 返回两个日期之间的月份差值。
///
/// - `control`:基准月份。
/// - `test`:测试月份。
pub fn difference_month(control: Date, test: Date) -> i32 {
let difference_year = test.year() - control.year();
let difference_month = u8::from(test.month()) as i32 - u8::from(control.month()) as i32;
difference_year * 12 + difference_month
}
/// 测试指定月份是否是基准月份的前一个月份。
///
/// - `control`:基准月份。
/// - `test`:待测试的指定月份。
pub fn is_previous_month(control: Date, test: Date) -> bool {
control.month().previous() == test.month()
}
/// 测试指定月份是否是基准月份的下一个月份。
///
/// - `control`:基准月份。
/// - `test`:待测试的指定月份。
pub fn is_next_month(control: Date, test: Date) -> bool {
control.month().next() == test.month()
}
/// 生成符合Postgresql中日期类型最小值的日期。
pub fn min_date() -> Date {
Date::from_calendar_date(1970, Month::January, 1).unwrap()
}
/// 生成符合Postgresql中日期类型最小值的日期时间。
pub fn min_datetime() -> OffsetDateTime {
Date::from_calendar_date(1970, Month::January, 1)
.map(begin_of_date)
.unwrap()
}
/// 生成符合Postgresql中日期类型最大值的日期。
pub fn max_date() -> Date {
Date::from_calendar_date(2099, Month::December, 31).unwrap()
}
/// 生成符合Postgresql中日期类型最大值的日期时间。
pub fn max_datetime() -> OffsetDateTime {
Date::from_calendar_date(2099, Month::December, 31)
.map(end_of_date)
.unwrap()
}

25
tests/des_cryption.rs Normal file
View 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
View 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);
}
}