dev_tool/
secure_util.rs

1use crate::HexUtil;
2use base64::{prelude::BASE64_STANDARD, DecodeError, Engine};
3use base64ct::LineEnding;
4use hmac::{Hmac, Mac};
5use rsa::{
6    pkcs8::{DecodePrivateKey, DecodePublicKey, EncodePrivateKey, EncodePublicKey},
7    Pkcs1v15Encrypt, RsaPrivateKey, RsaPublicKey,
8};
9use sha1::Sha1;
10use sha2::{Digest, Sha256};
11
12/// 加解密工具,摘要算法等也归集次此工具类中
13pub struct SecureUtil;
14
15impl SecureUtil {
16    /// TODO 待完善
17    pub fn aes_random_key() -> String {
18        "".to_string()
19    }
20
21    /// TODO 待完善
22    pub fn aes_encode(bytes: &[u8], key: &str) -> String {
23        "".to_string()
24    }
25
26    /// TODO 待完善
27    pub fn aes_decode(decode_str: &str, key: &str) -> Vec<u8> {
28        vec![]
29    }
30
31    /// 生成RSA随机密钥对
32    ///
33    /// 该函数使用系统随机数生成器创建一个2048位的RSA密钥对。
34    ///
35    /// # 返回值
36    /// * `RsaPublicKey` - RSA公钥
37    /// * `RsaPrivateKey` - RSA私钥
38    ///
39    /// # Panics
40    /// 当密钥生成失败时会panic
41    pub fn rsa_random_key() -> (RsaPublicKey, RsaPrivateKey) {
42        let mut rng = rand::thread_rng(); // rand@0.8
43        let bits = 2048;
44        // 生成RSA私钥
45        let priv_key = RsaPrivateKey::new(&mut rng, bits).expect("failed to generate a key");
46        // 从私钥导出公钥
47        let pub_key = RsaPublicKey::from(&priv_key);
48        (pub_key, priv_key)
49    }
50
51    /// 使用RSA公钥对字节数据进行加密
52    ///
53    /// 该函数使用PKCS#1 v1.5填充方案对输入的字节数据进行RSA加密操作。
54    /// 加密过程中会使用随机数生成器来确保加密的安全性。
55    ///
56    /// # 参数
57    /// * `pub_key` - RSA公钥引用,用于执行加密操作
58    /// * `bytes` - 需要加密的原始字节数据
59    ///
60    /// # 返回值
61    /// 返回加密后的字节数据向量
62    ///
63    /// # Panics
64    /// 当加密操作失败时会panic,例如输入数据过长等情况
65    pub fn rsa_encode(pub_key: &RsaPublicKey, bytes: &[u8]) -> Vec<u8> {
66        let mut rng = rand::thread_rng(); // rand@0.8
67        let enc_data = pub_key
68            .encrypt(&mut rng, Pkcs1v15Encrypt, bytes)
69            .expect("failed to encrypt");
70        enc_data
71    }
72
73    /// 使用RSA私钥解密数据
74    ///
75    /// # 参数
76    /// * `priv_key` - RSA私钥引用,用于解密操作
77    /// * `enc_data` - 待解密的加密数据字节切片
78    ///
79    /// # 返回值
80    /// 返回解密后的原始数据字节向量
81    ///
82    /// # Panics
83    /// 当解密操作失败时会panic
84    pub fn rsa_decode(priv_key: &RsaPrivateKey, enc_data: &[u8]) -> Vec<u8> {
85        // 使用PKCS#1 v1.5填充方案进行RSA解密
86        let dec_data = priv_key
87            .decrypt(Pkcs1v15Encrypt, &enc_data)
88            .expect("failed to decrypt");
89        dec_data
90    }
91
92    /// 将RSA私钥转换为PKCS#8格式的PEM字符串
93    ///
94    /// 该函数接收一个RSA私钥对象,将其序列化为PKCS#8格式的PEM编码字符串。
95    /// PKCS#8是一种标准的私钥存储格式,使用PEM编码便于文本传输和存储。
96    ///
97    /// # 参数
98    /// * `priv_key` - 要转换的RSA私钥引用
99    ///
100    /// # 返回值
101    /// 返回PKCS#8格式的PEM编码字符串
102    ///
103    /// # Panics
104    /// 当私钥转换失败时会panic,因为使用了unwrap()
105    pub fn rsa_private_key_to_pkcs8(priv_key: &RsaPrivateKey) -> String {
106        let x = priv_key.to_pkcs8_pem(LineEnding::LF).unwrap();
107        x.to_string()
108    }
109
110    /// 将RSA公钥转换为PKCS#8格式的PEM字符串
111    ///
112    /// 该函数接收一个RSA公钥对象,将其序列化为PEM格式的字符串,
113    /// 使用LF作为换行符
114    ///
115    /// # 参数
116    /// * `pub_key` - 要转换的RSA公钥引用
117    ///
118    /// # 返回值
119    /// 返回PEM格式的PKCS#8公钥字符串
120    ///
121    /// # Panics
122    /// 当公钥转换失败时会panic(通过unwrap调用)
123    pub fn rsa_public_key_to_pkcs8(pub_key: &RsaPublicKey) -> String {
124        let x = pub_key.to_public_key_pem(LineEnding::LF).unwrap();
125        x
126    }
127
128    /// 从PKCS#8格式的PEM字符串中解析RSA私钥
129    ///
130    /// 该函数接收一个PKCS#8格式的PEM编码字符串,将其解析为RsaPrivateKey对象。
131    ///
132    /// # 参数
133    /// * `pkcs8_string` - 包含PKCS#8格式RSA私钥的PEM编码字符串
134    ///
135    /// # 返回值
136    /// 返回解析得到的RsaPrivateKey对象
137    ///
138    /// # Panics
139    /// 当PEM字符串格式不正确或无法解析时,函数会panic
140    pub fn rsa_private_key_from_pkcs8(pkcs8_string: &str) -> RsaPrivateKey {
141        // 从PKCS#8 PEM字符串解析RSA私钥
142        let res = RsaPrivateKey::from_pkcs8_pem(pkcs8_string).unwrap();
143        res
144    }
145    /// 从PKCS8格式的字符串创建RSA公钥
146    ///
147    /// 该函数接收一个PKCS8格式的PEM编码字符串,将其解析为RSA公钥对象。
148    ///
149    /// # 参数
150    /// * `pkcs8_string` - PKCS8格式的PEM编码字符串
151    ///
152    /// # 返回值
153    /// * `RsaPublicKey` - 解析得到的RSA公钥对象
154    ///
155    /// # 注意
156    /// 该函数使用unwrap()处理结果,如果解析失败会panic
157    pub fn rsa_public_key_from_pkcs8(pkcs8_string: &str) -> RsaPublicKey {
158        let res = RsaPublicKey::from_public_key_pem(pkcs8_string).unwrap();
159        res
160    }
161
162    /// 计算字节数组的SHA256哈希值并返回十六进制字符串
163    ///
164    /// 固定生成256 位(32 字节) 的哈希值,以 64 位十六进制字符串形式展示
165    ///
166    /// # 参数
167    /// * `bytes` - 需要计算哈希值的字节数组切片
168    ///
169    /// # 返回值
170    /// 返回SHA256哈希值的十六进制字符串表示
171    pub fn sha256_string(bytes: &[u8]) -> String {
172        // 计算SHA256哈希值
173        let result = Sha256::digest(bytes);
174        let result = &result[..];
175        // 将哈希值转换为十六进制字符串
176        HexUtil::to_hex(result)
177    }
178
179    pub fn md5_string(bytes: &[u8]) -> String {
180        // 计算输入数据的MD5哈希值
181        let data_md5 = md5::compute(bytes);
182        // 将MD5哈希值格式化为十六进制字符串
183        let md5_string = format!("{:x}", data_md5);
184        md5_string
185    }
186
187    /// 对字节数组进行Base64编码
188    ///
189    /// # 参数
190    /// * `bytes` - 需要编码的字节数组切片
191    ///
192    /// # 返回值
193    /// 返回编码后的Base64字符串
194    pub fn base64_encode(bytes: &[u8]) -> String {
195        BASE64_STANDARD.encode(bytes)
196    }
197
198    /// 对Base64编码的字符串进行解码
199    ///
200    /// # 参数
201    /// * `base64_str` - 需要解码的Base64编码字符串
202    ///
203    /// # 返回值
204    /// * `Ok(Vec<u8>)` - 解码成功,返回解码后的字节数据
205    /// * `Err(DecodeError)` - 解码失败,返回错误信息
206    ///
207    /// # 示例
208    /// ```
209    /// let decoded = base64_decode("SGVsbG8=").unwrap();
210    /// assert_eq!(decoded, b"Hello");
211    /// ```
212    pub fn base64_decode(base64_str: &str) -> Result<Vec<u8>, DecodeError> {
213        BASE64_STANDARD.decode(base64_str)
214    }
215
216    /// 使用HMAC-SHA1算法对数据进行签名
217    ///
218    /// 该函数接收待签名的数据和密钥,使用HMAC-SHA1算法生成数字签名。
219    ///
220    /// # 参数
221    /// * `data` - 待签名的字节数据切片
222    /// * `key` - 用于签名的密钥字符串
223    ///
224    /// # 返回值
225    /// 返回HMAC-SHA1签名结果的字节向量
226    ///
227    /// # Panics
228    /// 当密钥长度无效时会panic,但在实际中HMAC可以接受任意长度的密钥
229    pub fn hmac_sha1(data: &[u8], key: &str) -> Vec<u8> {
230        let key = key.as_bytes();
231        // 创建HMAC-SHA1实例并初始化
232        let mut hmac = Hmac::<Sha1>::new_from_slice(key).expect("HMAC can take key of any size");
233        // 更新HMAC状态,处理输入数据
234        hmac.update(data);
235        // 完成HMAC计算并获取结果
236        let result = hmac.finalize();
237        let hmac_bytes = result.into_bytes();
238        hmac_bytes.to_vec()
239    }
240
241    /// 将字节数组转换为MD5哈希字符串
242    ///
243    /// 该函数接收一个字节切片,计算其MD5哈希值,并将结果格式化为十六进制字符串。
244    ///
245    /// # 参数
246    /// * `bytes` - 需要计算MD5哈希的字节数据切片
247    ///
248    /// # 返回值
249    /// 返回表示MD5哈希值的十六进制字符串
250    ///
251    /// # 示例
252    /// ```
253    /// let data = b"hello world";
254    /// let md5_str = to_md5_str(data);
255    /// assert_eq!(md5_str, "5eb63bbbe01eeed093cb22bb8f5acdc3");
256    /// ```
257    #[deprecated(note = "This function is deprecated, please use md5_string instead")]
258    pub fn to_md5_str(bytes: &[u8]) -> String {
259        Self::md5_string(bytes)
260    }
261
262    /// 计算字节数组的MD5哈希值
263    ///
264    /// # 参数
265    /// * `bytes` - 需要计算MD5哈希值的字节数组切片
266    ///
267    /// # 返回值
268    /// 返回计算得到的MD5哈希值,以字节数组形式表示
269    ///
270    /// # 示例
271    /// ```
272    /// let data = b"hello world";
273    /// let hash = to_md5(data);
274    /// ```
275    pub fn to_md5(bytes: &[u8]) -> Vec<u8> {
276        // 使用md5库计算输入数据的哈希值并转换为Vec<u8>
277        let data_md5 = md5::compute(bytes).to_vec();
278        data_md5
279    }
280}
281
282#[cfg(test)]
283mod tests {
284
285    use super::*;
286
287    #[test]
288    fn test_base64() {
289        let bytes = "hello, rust!".as_bytes();
290        let base64_str = SecureUtil::base64_encode(bytes);
291        println!("{}", base64_str);
292    }
293
294    #[test]
295    fn test_sha256() {
296        let sha256_string = SecureUtil::sha256_string(b"hello world");
297        println!("{}", sha256_string);
298        assert_eq!(
299            sha256_string,
300            "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9"
301        );
302    }
303
304    #[test]
305    fn test_rsa() {
306        let (pub_key, priv_key) = SecureUtil::rsa_random_key();
307        // let data = "hello world";
308        // let enc_data = SecureUtil::rsa_encode(&pub_key, data.as_bytes());
309        // let dec_data = SecureUtil::rsa_decode(&priv_key, &enc_data);
310        // assert_eq!(data, std::str::from_utf8(&dec_data).unwrap());
311        // println!("{:?}", pub_key);
312        // let x = priv_key.to_pkcs8_pem(LineEnding::LF).unwrap();
313        // let y = (*x).clone();
314        // let x = x.to_string();
315        // println!("{}", y);
316
317        let pub_pkcs8_string = SecureUtil::rsa_public_key_to_pkcs8(&pub_key);
318        let priv_pkcs8_string = SecureUtil::rsa_private_key_to_pkcs8(&priv_key);
319
320        println!("pub_pkcs8_string => {}", pub_pkcs8_string);
321        println!("priv_pkcs8_string => {}", priv_pkcs8_string);
322
323        let pub_key = SecureUtil::rsa_public_key_from_pkcs8(&pub_pkcs8_string);
324        let priv_key = SecureUtil::rsa_private_key_from_pkcs8(&priv_pkcs8_string);
325
326        let data = "hello world";
327        let enc_data = SecureUtil::rsa_encode(&pub_key, data.as_bytes());
328        let dec_data = SecureUtil::rsa_decode(&priv_key, &enc_data);
329        println!("解密后{}", std::str::from_utf8(&dec_data).unwrap())
330    }
331
332    #[test]
333    fn test_rsa2() {
334        // https://www.metools.info/code/c80.html 生成RSA密钥对
335        let pub_pkcs8_string = r#"-----BEGIN PUBLIC KEY-----
336MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6HvM5v45WMgCVCM7gLyU
337q8Xi0fqwvfge7JU9C6niP+liQHyMALr9n+IQm76v/CnvfAYYnDJ1VYhLpGkPKJ2Q
33856InmEOSAcx9vfgGQcPkkTSqpH/vDHEgPysFsBAGVBvXfBxa9FBF8afrAmdqM3DO
339ygnWWCaSux0js2hkQB0+wUk3Lkw9yxcT+cK9D7aNaB3vVjxRVvGOuFVMuTFzLjis
340/1INfltSSvnCB4QPxA/h9YUrZ26itw7yQgGIiUbNydLx3X+qvWCGVOnYwX9z6wsF
3414Ch3VwlYF+H/y0zyjIuCpdJDy80D36lErcwmRpJhMciT4lXnLMTyZvlN0UFl492L
3421wIDAQAB
343-----END PUBLIC KEY-----"#;
344        let priv_pkcs8_string = r#"-----BEGIN PRIVATE KEY-----
345MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDoe8zm/jlYyAJU
346IzuAvJSrxeLR+rC9+B7slT0LqeI/6WJAfIwAuv2f4hCbvq/8Ke98BhicMnVViEuk
347aQ8onZDnoieYQ5IBzH29+AZBw+SRNKqkf+8McSA/KwWwEAZUG9d8HFr0UEXxp+sC
348Z2ozcM7KCdZYJpK7HSOzaGRAHT7BSTcuTD3LFxP5wr0Pto1oHe9WPFFW8Y64VUy5
349MXMuOKz/Ug1+W1JK+cIHhA/ED+H1hStnbqK3DvJCAYiJRs3J0vHdf6q9YIZU6djB
350f3PrCwXgKHdXCVgX4f/LTPKMi4Kl0kPLzQPfqUStzCZGkmExyJPiVecsxPJm+U3R
351QWXj3YvXAgMBAAECggEATgrBDgnpVlRN89Cf+OdVQRR8v+BX1G2mc+TlSTUOLkY6
352JUup89TRrwpEaQPqL8wkCI5DVKvbl4rZWaeq3weFzTwx7ntAWDo9O7g24XzRDa2Q
353WwhXRuXy3UGj9yZp+XIfNBqQrdMEp8qmqXftvrbvtAL5YT4Ro550jZVNkfg/SMKX
354VptR+ZGpjSWsQfLM+Q8i9GEo3FV1dpT41Uea96cfX2siaaNNhCUM3MYgVDRjp7gj
355N9qxHOil3ZmvJU2yRLBlwgtLO+5fQzGET/yOeoXJ9iCeyAz5MNweljdra4wNtriV
3569ECYR/d7R3Bz2DtaJ5ALyD80AeJ+1TTrLxa4exkHgQKBgQD7UXolf0J5qFMEn7yw
3570F7LNANX/Fx6T/ayf7MJEegHK0UYDc9wjyIQDcIdgauvqImseq7R5sQQbnAHdsZW
358f6bzb+1HjoUZr2c43QY4sBRDW7wfibtlgtaiMpIophlBwbvdcJRW65s7Ox8Czcl/
359JNqMdjXjHLSiEFND6v8Of68LFQKBgQDs0IByiZm7qJQaR8WOoXku5C0XLA5zCLyh
360jXTqla5m0qAFZU8abrvBl/o0+nhmGsMkQR0ssvLJLX/a0t1IWBq+WmIDB3YC4IVU
361eKoHY7AlDhMa0dJ+nbuvrPQdFsRAfH9CRhtMmQPCVsx41AXsQa/OKwUQJuNvhwMg
362AioMthWGOwKBgG6tvTtSRjZJuPXqWzELMxQOfgJ7s0ZyfNSzhGdUKXkuxykGu/p4
363LqofRQO1naSodqktBlyOYn5SBKhk2Igzg5TmD/tZeqiLJMxYGmtQsDvR5JGHGK5l
3645pxb5R5dt/XLmi61a76z2BNHwCp98mU6F72QOb8hXzOYOPNKRLVf6fjZAoGBAJD2
3652YpDvT3o5jBoOwEiy4Hu38NNjtLQSFhEtYtccVQ0HwzuhUvS+VB67gk8QjOOsmIh
366EfDo4kJQffHAHwFIHabkwRbFnHIKatPYwYygc5VbVkqWotorSFcz8oNUCnLHQ0eY
367juGG0YxHggd9EtsbIrl8EC9g/tyoszsG2CLL28U9AoGAbZsQM7989SiKtLJ652uw
3686kaRWItbBdVKPr5galsBhbe/eEEE6ePbJTeLroQ31u/jGZJNSyUjwfBq9k1OBfpL
369s7+EjYm9Yg5hcep499C2eRyqoX+2j8am2CYYy3rDPj8lYt+u/99oUyAyGYVKAByb
370j27x2gyifpYUwtDqYU5DwDU=
371-----END PRIVATE KEY-----"#;
372
373        println!("pub_pkcs8_string => {}", pub_pkcs8_string);
374        println!("priv_pkcs8_string => {}", priv_pkcs8_string);
375
376        let pub_key = SecureUtil::rsa_public_key_from_pkcs8(&pub_pkcs8_string);
377        let priv_key = SecureUtil::rsa_private_key_from_pkcs8(&priv_pkcs8_string);
378
379        let data = "hello world";
380        let enc_data = SecureUtil::rsa_encode(&pub_key, data.as_bytes());
381        let dec_data = SecureUtil::rsa_decode(&priv_key, &enc_data);
382        println!("解密后{}", std::str::from_utf8(&dec_data).unwrap())
383    }
384}