11#!/usr/bin/env python3
22# -*- coding: utf-8 -*-
33import os
4+ from typing import Any
45
56from cryptography .hazmat .backends .openssl import backend
67from cryptography .hazmat .primitives import padding
78from cryptography .hazmat .primitives .ciphers import Cipher , algorithms , modes
9+ from itsdangerous import URLSafeSerializer
10+
11+ from backend .app .common .log import log
812
913
1014class AESCipher :
@@ -14,13 +18,15 @@ def __init__(self, key: bytes | str):
1418 """
1519 self .key = key if isinstance (key , bytes ) else bytes .fromhex (key )
1620
17- def encrypt (self , plaintext : bytes ) -> bytes :
21+ def encrypt (self , plaintext : bytes | str ) -> bytes :
1822 """
1923 AES 加密
2024
2125 :param plaintext: 加密前的明文
2226 :return:
2327 """
28+ if not isinstance (plaintext , bytes ):
29+ plaintext = str (plaintext ).encode ('utf-8' )
2430 iv = os .urandom (16 )
2531 cipher = Cipher (algorithms .AES (self .key ), modes .CBC (iv ), backend = backend )
2632 encryptor = cipher .encryptor ()
@@ -29,7 +35,7 @@ def encrypt(self, plaintext: bytes) -> bytes:
2935 ciphertext = encryptor .update (padded_plaintext ) + encryptor .finalize ()
3036 return iv + ciphertext
3137
32- def decrypt (self , ciphertext : bytes | str ) -> bytes :
38+ def decrypt (self , ciphertext : bytes | str ) -> str :
3339 """
3440 AES 解密
3541
@@ -44,7 +50,7 @@ def decrypt(self, ciphertext: bytes | str) -> bytes:
4450 unpadder = padding .PKCS7 (cipher .algorithm .block_size ).unpadder () # type: ignore
4551 padded_plaintext = decryptor .update (ciphertext ) + decryptor .finalize ()
4652 plaintext = unpadder .update (padded_plaintext ) + unpadder .finalize ()
47- return plaintext
53+ return plaintext . decode ( 'utf-8' )
4854
4955
5056class Md5Cipher :
@@ -59,8 +65,45 @@ def encrypt(plaintext: bytes | str) -> str:
5965 import hashlib
6066
6167 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 )
6671 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