1
1
#!/usr/bin/env python3
2
2
# -*- coding: utf-8 -*-
3
3
import os
4
+ from typing import Any
4
5
5
6
from cryptography .hazmat .backends .openssl import backend
6
7
from cryptography .hazmat .primitives import padding
7
8
from cryptography .hazmat .primitives .ciphers import Cipher , algorithms , modes
9
+ from itsdangerous import URLSafeSerializer
10
+
11
+ from backend .app .common .log import log
8
12
9
13
10
14
class AESCipher :
@@ -14,13 +18,15 @@ def __init__(self, key: bytes | str):
14
18
"""
15
19
self .key = key if isinstance (key , bytes ) else bytes .fromhex (key )
16
20
17
- def encrypt (self , plaintext : bytes ) -> bytes :
21
+ def encrypt (self , plaintext : bytes | str ) -> bytes :
18
22
"""
19
23
AES 加密
20
24
21
25
:param plaintext: 加密前的明文
22
26
:return:
23
27
"""
28
+ if not isinstance (plaintext , bytes ):
29
+ plaintext = str (plaintext ).encode ('utf-8' )
24
30
iv = os .urandom (16 )
25
31
cipher = Cipher (algorithms .AES (self .key ), modes .CBC (iv ), backend = backend )
26
32
encryptor = cipher .encryptor ()
@@ -29,7 +35,7 @@ def encrypt(self, plaintext: bytes) -> bytes:
29
35
ciphertext = encryptor .update (padded_plaintext ) + encryptor .finalize ()
30
36
return iv + ciphertext
31
37
32
- def decrypt (self , ciphertext : bytes | str ) -> bytes :
38
+ def decrypt (self , ciphertext : bytes | str ) -> str :
33
39
"""
34
40
AES 解密
35
41
@@ -44,7 +50,7 @@ def decrypt(self, ciphertext: bytes | str) -> bytes:
44
50
unpadder = padding .PKCS7 (cipher .algorithm .block_size ).unpadder () # type: ignore
45
51
padded_plaintext = decryptor .update (ciphertext ) + decryptor .finalize ()
46
52
plaintext = unpadder .update (padded_plaintext ) + unpadder .finalize ()
47
- return plaintext
53
+ return plaintext . decode ( 'utf-8' )
48
54
49
55
50
56
class Md5Cipher :
@@ -59,8 +65,45 @@ def encrypt(plaintext: bytes | str) -> str:
59
65
import hashlib
60
66
61
67
md5 = hashlib .md5 ()
62
- if isinstance (plaintext , str ):
63
- md5 .update (plaintext .encode ('utf-8' ))
64
- else :
65
- md5 .update (plaintext )
68
+ if not isinstance (plaintext , bytes ):
69
+ plaintext = str (plaintext ).encode ('utf-8' )
70
+ md5 .update (plaintext )
66
71
return md5 .hexdigest ()
72
+
73
+
74
+ class ItsDCipher :
75
+ def __init__ (self , key : bytes | str ):
76
+ """
77
+ :param key: 密钥,16/24/32 bytes 或 16 进制字符串
78
+ """
79
+ self .key = key if isinstance (key , bytes ) else bytes .fromhex (key )
80
+
81
+ def encrypt (self , plaintext : Any ) -> str :
82
+ """
83
+ ItsDangerous 加密 (可能失败,如果 plaintext 无法序列化,则会加密为 MD5)
84
+
85
+ :param plaintext: 加密前的明文
86
+ :return:
87
+ """
88
+ serializer = URLSafeSerializer (self .key )
89
+ try :
90
+ ciphertext = serializer .dumps (plaintext )
91
+ except Exception as e :
92
+ log .error (f'ItsDangerous encrypt failed: { e } ' )
93
+ ciphertext = Md5Cipher .encrypt (plaintext )
94
+ return ciphertext
95
+
96
+ def decrypt (self , ciphertext : str ) -> Any :
97
+ """
98
+ ItsDangerous 解密 (可能失败,如果 ciphertext 无法反序列化,则解密失败, 返回原始密文)
99
+
100
+ :param ciphertext: 解密前的密文
101
+ :return:
102
+ """
103
+ serializer = URLSafeSerializer (self .key )
104
+ try :
105
+ plaintext = serializer .loads (ciphertext )
106
+ except Exception as e :
107
+ log .error (f'ItsDangerous decrypt failed: { e } ' )
108
+ plaintext = ciphertext
109
+ return plaintext
0 commit comments