volcengine-python-sdk-aicc 0.0.41__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. bytedance/__init__.py +4 -0
  2. bytedance/jeddak_secure_channel/__init__.py +28 -0
  3. bytedance/jeddak_secure_channel/client.py +305 -0
  4. bytedance/jeddak_secure_channel/config.py +171 -0
  5. bytedance/jeddak_secure_channel/consts.py +5 -0
  6. bytedance/jeddak_secure_channel/crypto/__init__.py +14 -0
  7. bytedance/jeddak_secure_channel/crypto/aes.py +174 -0
  8. bytedance/jeddak_secure_channel/crypto/envelope.py +395 -0
  9. bytedance/jeddak_secure_channel/crypto/rsa.py +164 -0
  10. bytedance/jeddak_secure_channel/error.py +131 -0
  11. bytedance/jeddak_secure_channel/log/__init__.py +23 -0
  12. bytedance/jeddak_secure_channel/log/config.py +31 -0
  13. bytedance/jeddak_secure_channel/log/logger.py +88 -0
  14. bytedance/jeddak_secure_channel/logger_factory.py +134 -0
  15. bytedance/jeddak_secure_channel/ra.py +772 -0
  16. bytedance/jeddak_secure_channel/server.py +745 -0
  17. bytedance/jeddak_secure_channel/service/__init__.py +16 -0
  18. bytedance/jeddak_secure_channel/service/eps.py +133 -0
  19. bytedance/jeddak_secure_channel/service/eps_models.py +47 -0
  20. bytedance/jeddak_secure_channel/service/ras.py +88 -0
  21. bytedance/jeddak_secure_channel/service/tks.py +51 -0
  22. bytedance/jeddak_secure_channel/service/tks_models.py +334 -0
  23. bytedance/jeddak_secure_channel/utils.py +469 -0
  24. bytedance/jeddak_secure_model/model_automation_tool.py +181 -0
  25. bytedance/jeddak_secure_model/model_encryption.py +416 -0
  26. bytedance/jeddak_secure_model/model_hub_admin.py +116 -0
  27. bytedance/jeddak_secure_model/pcc_utils.py +279 -0
  28. bytedance/jeddak_secure_model/rds_utils.py +63 -0
  29. bytedance/tks/attester.py +41 -0
  30. bytedance/tks/client.py +629 -0
  31. bytedance/tks/consts.py +122 -0
  32. bytedance/tks/crypto/aes.py +47 -0
  33. bytedance/tks/crypto/ec.py +39 -0
  34. bytedance/tks/exceptions.py +22 -0
  35. bytedance/volcengine_aicc_sdk/__init__.py +14 -0
  36. bytedance/volcengine_aicc_sdk/aicc_client.py +277 -0
  37. bytedance/volcengine_aicc_sdk/aicc_inference.py +64 -0
  38. bytedance/volcengine_aicc_sdk/ark_inference_client.py +343 -0
  39. bytedance/volcengine_aicc_sdk/asr_inference_client.py +158 -0
  40. bytedance/volcengine_aicc_sdk/asr_websocket_client.py +705 -0
  41. bytedance/volcengine_aicc_sdk/auc_inference_client.py +305 -0
  42. bytedance/volcengine_aicc_sdk/common/__init__.py +0 -0
  43. bytedance/volcengine_aicc_sdk/common/aes.py +136 -0
  44. bytedance/volcengine_aicc_sdk/common/constant.py +4 -0
  45. bytedance/volcengine_aicc_sdk/common/error.py +21 -0
  46. bytedance/volcengine_aicc_sdk/common/log/__init__.py +24 -0
  47. bytedance/volcengine_aicc_sdk/common/log/config.py +31 -0
  48. bytedance/volcengine_aicc_sdk/common/log/logger.py +88 -0
  49. bytedance/volcengine_aicc_sdk/common/tos_utils.py +341 -0
  50. bytedance/volcengine_aicc_sdk/common/utils.py +45 -0
  51. bytedance/volcengine_aicc_sdk/cu_inference_client.py +292 -0
  52. bytedance/volcengine_aicc_sdk/deepseek_inference_client.py +501 -0
  53. bytedance/volcengine_aicc_sdk/secure_http_client.py +406 -0
  54. bytedance/volcengine_aicc_sdk/seedance_inference_client.py +500 -0
  55. bytedance/volcengine_aicc_sdk/seedream_inference_client.py +213 -0
  56. volcengine_python_sdk_aicc-0.0.41.dist-info/METADATA +79 -0
  57. volcengine_python_sdk_aicc-0.0.41.dist-info/RECORD +60 -0
  58. volcengine_python_sdk_aicc-0.0.41.dist-info/WHEEL +5 -0
  59. volcengine_python_sdk_aicc-0.0.41.dist-info/licenses/LICENSE +202 -0
  60. volcengine_python_sdk_aicc-0.0.41.dist-info/top_level.txt +1 -0
@@ -0,0 +1,395 @@
1
+ """
2
+ 信封加密算法.
3
+ """
4
+
5
+ __all__ = [
6
+ "ClientSessionKey",
7
+ "EncryptedMessage",
8
+ "ResponseKey",
9
+ "ServerSessionKey",
10
+ ]
11
+
12
+ import base64
13
+ import dataclasses
14
+ import json
15
+ import logging
16
+ from dataclasses import dataclass, field
17
+ from datetime import datetime, timezone
18
+ from io import BytesIO
19
+ from threading import Lock
20
+
21
+ from typing_extensions import IO, TYPE_CHECKING, Optional, Self, Set, Tuple, Union
22
+
23
+ if TYPE_CHECKING:
24
+ from _typeshed import GenericPath
25
+ else:
26
+ GenericPath = str
27
+
28
+
29
+ from .. import error
30
+ from .aes import AES_KEY_LEN, AES_MAC_LEN, AES_NONCE_LEN, AesKey, FileMode
31
+ from .rsa import PrivateKey, PublicKey
32
+
33
+ logger = logging.getLogger(__name__)
34
+
35
+
36
+ @dataclass(eq=False, frozen=True)
37
+ class EncryptedMessage:
38
+ """
39
+ 信封加密数据.
40
+ 可作为数据发送方的请求, 及数据接收方的响应.
41
+
42
+ 本类不含可变状态, 所有方法是线程安全的.
43
+ """
44
+
45
+ nonce: bytes
46
+ """单次随机数."""
47
+
48
+ mac: bytes
49
+ """校验码."""
50
+
51
+ key: Optional[bytes] = None
52
+ """
53
+ 用公钥加密的对称密钥.
54
+ 在数据发送方的加密请求中使用, 在数据接收方的加密响应中为空.
55
+ """
56
+
57
+ ciphertext: Optional[bytes] = None
58
+ """
59
+ 加密数据.
60
+ 在字符串 / 二进制数据加密中使用, 在文件加密中为空.
61
+ """
62
+
63
+ def serialize(self) -> str:
64
+ """
65
+ 将消息序列化为字符串.
66
+ """
67
+ return json.dumps(
68
+ {
69
+ k: base64.b64encode(v).decode()
70
+ for k, v in self.__dict__.items()
71
+ if v is not None
72
+ },
73
+ separators=(",", ":"),
74
+ )
75
+
76
+ @classmethod
77
+ def deserialize(cls, data: Union[str, bytes]) -> Self:
78
+ """
79
+ 从字符串反序列化消息.
80
+ """
81
+ try:
82
+ return cls(**{k: base64.b64decode(v) for k, v in json.loads(data).items()})
83
+ except Exception:
84
+ raise error.DecryptionError("Invalid encoding") from None
85
+
86
+
87
+ @dataclass(eq=False, frozen=True)
88
+ class ResponseKey:
89
+ """
90
+ 对响应加解密的密钥.
91
+
92
+ 本类不含可变状态, 所有方法是线程安全的.
93
+ """
94
+
95
+ _key: AesKey
96
+
97
+ def encrypt(self, plaintext: Union[str, bytes]) -> str:
98
+ """
99
+ 加密响应 (由服务端使用).
100
+ """
101
+ if isinstance(plaintext, str):
102
+ plaintext = plaintext.encode("utf-8")
103
+
104
+ nonce, ciphertext, mac = self._key.encrypt(plaintext)
105
+ return EncryptedMessage(nonce=nonce, mac=mac, ciphertext=ciphertext).serialize()
106
+
107
+ def decrypt(self, response: Union[str, bytes]) -> bytes:
108
+ """
109
+ 解密响应 (由客户端使用).
110
+ """
111
+ message = EncryptedMessage.deserialize(response)
112
+
113
+ if message.ciphertext is None or message.key is not None:
114
+ raise error.ParamError("response", "Message is not server response")
115
+ if len(message.nonce) != AES_NONCE_LEN or len(message.mac) != AES_MAC_LEN:
116
+ raise error.DecryptionError("Invalid data length")
117
+
118
+ return self._key.decrypt(message.nonce, message.ciphertext, message.mac)
119
+
120
+ def encrypt_file(
121
+ self,
122
+ source_path: GenericPath,
123
+ dest_path: GenericPath,
124
+ mode: FileMode,
125
+ nonce: Optional[bytes] = None,
126
+ ) -> str:
127
+ """
128
+ 加密响应文件 (由服务端使用).
129
+ """
130
+ with open(source_path, f"r{mode}") as source, open(
131
+ dest_path, f"w{mode}"
132
+ ) as dest:
133
+ nonce, mac = self._key.encrypt_stream(source, dest, mode, nonce)
134
+
135
+ metadata = EncryptedMessage(nonce=nonce, mac=mac)
136
+
137
+ return metadata.serialize()
138
+
139
+ def decrypt_file(
140
+ self,
141
+ metadata: str,
142
+ source_path: GenericPath,
143
+ dest_path: GenericPath,
144
+ mode: FileMode,
145
+ ):
146
+ """
147
+ 解密响应文件 (由客户端使用).
148
+ """
149
+ message = EncryptedMessage.deserialize(metadata)
150
+
151
+ if message.ciphertext is not None or message.key is not None:
152
+ raise error.ParamError("response", "Message is not server response")
153
+ if len(message.nonce) != AES_NONCE_LEN or len(message.mac) != AES_MAC_LEN:
154
+ raise error.DecryptionError("Invalid data length")
155
+
156
+ return self.decrypt_file_with_nonce(
157
+ source_path, dest_path, message.nonce, message.mac, mode
158
+ )
159
+
160
+ def decrypt_file_with_nonce(
161
+ self,
162
+ source_path: GenericPath,
163
+ dest_path: GenericPath,
164
+ nonce: bytes,
165
+ mac: Optional[bytes],
166
+ mode: FileMode,
167
+ ):
168
+ """
169
+ 解密响应文件 (由客户端使用).
170
+ """
171
+ with open(source_path, f"r{mode}") as source, open(
172
+ dest_path, f"w{mode}"
173
+ ) as dest:
174
+ self._key.decrypt_stream(source, dest, nonce, mac, mode)
175
+
176
+
177
+ @dataclass(eq=False, frozen=True)
178
+ class ClientSessionKey:
179
+ """
180
+ 数据发送方持有的密钥.
181
+
182
+ 本类不含可变状态, 所有方法是线程安全的.
183
+ """
184
+
185
+ server_public_key: PublicKey
186
+ """数据接收方公钥."""
187
+
188
+ @classmethod
189
+ def load(cls, public_pem: Union[str, bytes]) -> Self:
190
+ """
191
+ 通过数据接收方的公钥产生发送方密钥.
192
+
193
+ Args:
194
+ private_pem: PEM 格式的 RSA 公钥.
195
+ """
196
+ public_key = PublicKey.from_public_pem(public_pem)
197
+
198
+ return cls(public_key)
199
+
200
+ def encrypt(
201
+ self, plaintext: Union[str, bytes], key: Optional[AesKey] = None
202
+ ) -> EncryptedMessage:
203
+ """
204
+ 信封加密.
205
+
206
+ Args:
207
+ key: 指定加密用的对称密钥. 默认为随机生成 (一次一密).
208
+ Returns:
209
+ 信封加密数据.
210
+ """
211
+ if isinstance(plaintext, str):
212
+ plaintext = plaintext.encode("utf-8")
213
+
214
+ with BytesIO(plaintext) as source, BytesIO() as dest:
215
+ message = self.encrypt_stream(source, dest, "b", key)
216
+ message = dataclasses.replace(message, ciphertext=dest.getvalue())
217
+
218
+ return message
219
+
220
+ def encrypt_with_response(
221
+ self, plaintext: Union[str, bytes], aes_key: AesKey = None
222
+ ) -> Tuple[EncryptedMessage, ResponseKey]:
223
+ """
224
+ 信封加密, 并获取用于解密响应的密钥.
225
+ """
226
+ if aes_key is None:
227
+ key = AesKey.generate()
228
+ else:
229
+ key = aes_key
230
+
231
+ return self.encrypt(plaintext, key), ResponseKey(key)
232
+
233
+ def encrypt_stream(
234
+ self, source: IO, dest: IO, mode: FileMode, key: Optional[AesKey] = None
235
+ ) -> EncryptedMessage:
236
+ """
237
+ 信封加密数据流.
238
+
239
+ Returns:
240
+ 信封加密元数据.
241
+ """
242
+ symmetric_key = key or AesKey.generate()
243
+
244
+ nonce, mac = symmetric_key.encrypt_stream(source, dest, mode)
245
+
246
+ encrypted_key = self.server_public_key.encrypt(symmetric_key.key)
247
+
248
+ return EncryptedMessage(key=encrypted_key, nonce=nonce, mac=mac)
249
+
250
+ def encrypt_stream_with_response(
251
+ self, source: IO, dest: IO, mode: FileMode
252
+ ) -> Tuple[EncryptedMessage, ResponseKey]:
253
+ """
254
+ 信封加密数据流, 并获取用于解密响应的密钥.
255
+ """
256
+ key = AesKey.generate()
257
+
258
+ # return self.encrypt_stream(source, dest, mode), ResponseKey(key)
259
+ return self.encrypt_stream(source, dest, mode, key), ResponseKey(key)
260
+
261
+
262
+ @dataclass(eq=False)
263
+ class ServerSessionKey:
264
+ """
265
+ 数据接收方持有的密钥.
266
+
267
+ 本类的所有方法是线程安全的.
268
+ """
269
+
270
+ private_key: PrivateKey
271
+ """私钥."""
272
+
273
+ expire_at: datetime
274
+ """【未启用】密钥对在此时间后无效."""
275
+
276
+ tks_version: Optional[int]
277
+ """【未启用】密钥版本, 用于判断获取的密钥是否变化. """
278
+
279
+ pem_md5: Optional[str] = None
280
+ """pem的MD5值."""
281
+
282
+ used_nonce: Set[bytes] = field(default_factory=set)
283
+ """已使用的单次随机数列表."""
284
+
285
+ used_nonce_lock: Lock = field(init=False, default_factory=Lock)
286
+ """线程安全: 修改 used_nonce 应该加锁."""
287
+
288
+ @classmethod
289
+ def load(
290
+ cls,
291
+ private_pem: Union[str, bytes],
292
+ expire_at: datetime,
293
+ tks_version: Optional[int],
294
+ pem_md5: Optional[str],
295
+ ) -> Self:
296
+ """
297
+ 通过 PEM 格式的 RSA 私钥产生接收方密钥.
298
+
299
+ Args:
300
+ private_pem: PEM 格式的 RSA 私钥.
301
+ :param pem_md5:
302
+ :param private_pem:
303
+ :param expire_at:
304
+ :param tks_version:
305
+ """
306
+ private_key = PrivateKey.from_private_pem(private_pem)
307
+
308
+ return cls(private_key, expire_at, tks_version, pem_md5)
309
+
310
+ @classmethod
311
+ def generate(cls, expire_at: datetime) -> Self:
312
+ """
313
+ 随机生成接收方密钥.
314
+ """
315
+ private_key = PrivateKey.generate()
316
+
317
+ return cls(private_key, expire_at, tks_version=None, pem_md5=None)
318
+
319
+ def is_expired(self) -> bool:
320
+ """
321
+ 是否已超过有效期.
322
+ """
323
+ now = datetime.now(timezone.utc)
324
+ if now > self.expire_at:
325
+ logger.warning("session key maybe expired")
326
+
327
+ return False # 服务端密钥暂时不考虑有效期
328
+
329
+ def get_public_key(self) -> str:
330
+ """
331
+ 获取 PEM 格式的公钥.
332
+ """
333
+ return self.private_key.public_pem()
334
+
335
+ def decrypt(
336
+ self, message: Union[str, bytes, EncryptedMessage]
337
+ ) -> Tuple[bytes, ResponseKey]:
338
+ """
339
+ 信封解密.
340
+
341
+ Returns:
342
+ 明文数据, 及用于加密响应的密钥.
343
+
344
+ Raises:
345
+ DecryptionError: 加密消息不合法, 或者加密使用的密钥不是本密钥.
346
+ """
347
+ if isinstance(message, (str, bytes)):
348
+ message = EncryptedMessage.deserialize(message)
349
+ if message.ciphertext is None:
350
+ raise error.ParamError("message", "Message has no data")
351
+
352
+ with BytesIO(message.ciphertext) as source, BytesIO() as dest:
353
+ response_key = self.decrypt_stream(message, source, dest, "b")
354
+ plaintext = dest.getvalue()
355
+
356
+ return plaintext, response_key
357
+
358
+ def decrypt_stream(
359
+ self,
360
+ metadata: Union[str, bytes, EncryptedMessage],
361
+ source: IO,
362
+ dest: IO,
363
+ mode: FileMode,
364
+ ) -> ResponseKey:
365
+ """
366
+ 信封解密数据流.
367
+
368
+ Returns:
369
+ 用于加密响应的密钥.
370
+
371
+ Raises:
372
+ DecryptionError: 加密消息不合法, 或者加密使用的密钥不是本密钥.
373
+ """
374
+ if isinstance(metadata, (str, bytes)):
375
+ metadata = EncryptedMessage.deserialize(metadata)
376
+ if metadata.key is None:
377
+ raise error.ParamError("metadata", "Message has no key")
378
+
379
+ # with self.used_nonce_lock:
380
+ # if metadata.nonce in self.used_nonce:
381
+ # raise error.NonceReusedError()
382
+ # self.used_nonce.add(metadata.nonce)
383
+
384
+ symmetric_key = self.private_key.decrypt(metadata.key)
385
+ if (
386
+ len(symmetric_key) != AES_KEY_LEN
387
+ or len(metadata.nonce) != AES_NONCE_LEN
388
+ or len(metadata.mac) != AES_MAC_LEN
389
+ ):
390
+ raise error.DecryptionError("Invalid data length")
391
+
392
+ symmetric_key = AesKey(symmetric_key)
393
+ symmetric_key.decrypt_stream(source, dest, metadata.nonce, metadata.mac, mode)
394
+
395
+ return ResponseKey(symmetric_key)
@@ -0,0 +1,164 @@
1
+ """
2
+ RSA 加密和签名算法.
3
+ """
4
+
5
+ __all__ = ["PublicKey", "PrivateKey"]
6
+
7
+ from dataclasses import dataclass
8
+
9
+ from cryptography.hazmat.primitives import hashes, serialization
10
+ from cryptography.hazmat.primitives.asymmetric import padding, rsa
11
+ from cryptography.hazmat.primitives.asymmetric.rsa import RSAPrivateKey, RSAPublicKey
12
+ from typing_extensions import Self, Union
13
+
14
+ from .. import error
15
+
16
+ ENCRYPT_PADDING = padding.OAEP(
17
+ mgf=padding.MGF1(hashes.SHA256()), algorithm=hashes.SHA256(), label=None
18
+ )
19
+ SIGN_PADDING = padding.PSS(
20
+ mgf=padding.MGF1(hashes.SHA256()), salt_length=padding.PSS.MAX_LENGTH
21
+ )
22
+ SIGN_HASH = hashes.SHA256()
23
+
24
+
25
+ @dataclass(eq=False, frozen=True)
26
+ class PublicKey:
27
+ """
28
+ RSA 公钥.
29
+
30
+ 本类不含可变状态, 所有方法是线程安全的.
31
+ """
32
+
33
+ public_key: RSAPublicKey
34
+
35
+ @classmethod
36
+ def from_public_pem(cls, public_pem: Union[str, bytes]) -> Self:
37
+ """
38
+ 读取 PEM 格式的 RSA 公钥.
39
+
40
+ Args:
41
+ private_pem: PEM 格式的 RSA 公钥.
42
+ """
43
+ if isinstance(public_pem, str):
44
+ public_pem = public_pem.encode("utf-8")
45
+ try:
46
+ public_key = serialization.load_pem_public_key(public_pem)
47
+ except Exception as e:
48
+ raise error.ParamError("public_pem", "Invalid RSA public key") from e
49
+ if not isinstance(public_key, RSAPublicKey):
50
+ raise error.ParamError("public_pem", "Key is not RSA")
51
+
52
+ return cls(public_key)
53
+
54
+ def encrypt(self, plaintext: bytes) -> bytes:
55
+ """
56
+ RSA 加密.
57
+
58
+ Raises:
59
+ EncryptionError:
60
+ """
61
+ try:
62
+ return self.public_key.encrypt(plaintext, ENCRYPT_PADDING)
63
+ except Exception as e:
64
+ raise error.EncryptionError("RSA encryption failed") from e
65
+
66
+ def public_pem(self) -> str:
67
+ """
68
+ 获取 PEM 格式的公钥.
69
+ """
70
+ return self.public_key.public_bytes(
71
+ encoding=serialization.Encoding.PEM,
72
+ format=serialization.PublicFormat.SubjectPublicKeyInfo,
73
+ ).decode("utf-8")
74
+
75
+ def verify(self, signature: bytes, message: Union[str, bytes]) -> bool:
76
+ """
77
+ 公钥验签.
78
+
79
+ Raises:
80
+ SignatureError:
81
+ """
82
+ if isinstance(message, str):
83
+ message = message.encode("utf-8")
84
+ try:
85
+ self.public_key.verify(signature, message, SIGN_PADDING, SIGN_HASH)
86
+ return True
87
+ except Exception as e:
88
+ print(e)
89
+ return False
90
+
91
+
92
+ @dataclass(init=False, eq=False, frozen=True)
93
+ class PrivateKey(PublicKey):
94
+ """
95
+ RSA 密钥对.
96
+ """
97
+
98
+ private_key: RSAPrivateKey
99
+
100
+ def __init__(self, private_key: RSAPrivateKey):
101
+ # Workaround frozen class
102
+ object.__setattr__(self, "private_key", private_key)
103
+ object.__setattr__(self, "public_key", private_key.public_key())
104
+
105
+ @classmethod
106
+ def from_private_pem(cls, private_pem: Union[str, bytes]) -> Self:
107
+ """
108
+ 读取 PEM 格式的 RSA 密钥对.
109
+
110
+ Args:
111
+ private_pem: PEM 格式的 RSA 私钥.
112
+ """
113
+ if isinstance(private_pem, str):
114
+ private_pem = private_pem.encode("utf-8")
115
+ private_key = serialization.load_pem_private_key(private_pem, password=None)
116
+ if not isinstance(private_key, RSAPrivateKey):
117
+ raise error.ParamError("private_pem", "Key is not RSA")
118
+
119
+ return cls(private_key)
120
+
121
+ @classmethod
122
+ def generate(cls) -> Self:
123
+ """
124
+ 随机生成密钥对.
125
+ """
126
+ private_key = rsa.generate_private_key(public_exponent=65537, key_size=4096)
127
+ return cls(private_key)
128
+
129
+ def private_pem(self) -> str:
130
+ """
131
+ 获取 PEM 格式的私钥.
132
+ """
133
+ return self.private_key.private_bytes(
134
+ encoding=serialization.Encoding.PEM,
135
+ format=serialization.PrivateFormat.TraditionalOpenSSL,
136
+ encryption_algorithm=serialization.NoEncryption(),
137
+ ).decode("utf-8")
138
+
139
+ def decrypt(self, plaintext: bytes) -> bytes:
140
+ """
141
+ RSA 解密.
142
+
143
+ Raises:
144
+ DecryptionError:
145
+ """
146
+ try:
147
+ return self.private_key.decrypt(plaintext, ENCRYPT_PADDING)
148
+ except Exception as e:
149
+ raise error.DecryptionError("RSA decryption failed") from e
150
+
151
+ def sign(self, message: Union[str, bytes]) -> bytes:
152
+ """
153
+ 私钥签名.
154
+
155
+ Raises:
156
+ SignatureError:
157
+ """
158
+ if isinstance(message, str):
159
+ message = message.encode("utf-8")
160
+ try:
161
+ signature = self.private_key.sign(message, SIGN_PADDING, SIGN_HASH)
162
+ return signature
163
+ except Exception as e:
164
+ raise error.SignatureError("RSA signing failed") from e
@@ -0,0 +1,131 @@
1
+ """
2
+ 安全通信错误类型.
3
+ """
4
+
5
+ from dataclasses import dataclass, field
6
+ from enum import Enum
7
+
8
+ from typing_extensions import Literal, Optional
9
+
10
+
11
+ class ErrorKind(Enum):
12
+ CONFIG = "config"
13
+ PARAM = "param"
14
+
15
+ NETWORK = "network"
16
+ SERVICE = "service"
17
+
18
+ ENCRYPTION = "encryption"
19
+ DECRYPTION = "decryption"
20
+ SIGNATURE = "signature"
21
+ KEY_MISSING = "key_missing"
22
+ KEY_EXPIRED = "key_expired"
23
+ NONCE_REUSED = "nonce_reused"
24
+
25
+
26
+ class SecureChannelError(Exception):
27
+ kind: ErrorKind
28
+
29
+
30
+ @dataclass
31
+ class ConfigError(SecureChannelError):
32
+ kind: ErrorKind = field(init=False, repr=False, default=ErrorKind.CONFIG)
33
+
34
+ config_object: object
35
+ message: str
36
+
37
+ def __str__(self) -> str:
38
+ return f"{self.config_object}: {self.message}"
39
+
40
+
41
+ @dataclass
42
+ class ParamError(SecureChannelError):
43
+ kind: ErrorKind = field(init=False, repr=False, default=ErrorKind.PARAM)
44
+
45
+ param: str
46
+ message: str
47
+
48
+ def __str__(self) -> str:
49
+ return f"{self.param}: {self.message}"
50
+
51
+
52
+ @dataclass
53
+ class NetworkError(SecureChannelError):
54
+ kind: ErrorKind = field(init=False, repr=False, default=ErrorKind.NETWORK)
55
+
56
+ service_name: Literal["EPS", "RA", "RAS", "TKS"]
57
+ service: str
58
+ endpoint: Optional[str]
59
+
60
+ def _service(self) -> str:
61
+ if self.endpoint is None:
62
+ return f"{self.service_name} service {self.service}"
63
+ else:
64
+ return f"endpoint {self.endpoint} of {self.service_name} service {self.service}"
65
+
66
+ def __str__(self) -> str:
67
+ return f"Cannot access {self._service()}"
68
+
69
+
70
+ @dataclass
71
+ class ServiceError(NetworkError):
72
+ kind: ErrorKind = field(init=False, repr=False, default=ErrorKind.SERVICE)
73
+
74
+ message: str
75
+
76
+ def __str__(self) -> str:
77
+ return f"{self._service().capitalize()} returned error: {self.message}"
78
+
79
+
80
+ @dataclass
81
+ class EncryptionError(SecureChannelError):
82
+ kind: ErrorKind = field(init=False, repr=False, default=ErrorKind.ENCRYPTION)
83
+
84
+ message: str
85
+
86
+ def __str__(self) -> str:
87
+ return self.message
88
+
89
+
90
+ @dataclass
91
+ class DecryptionError(SecureChannelError):
92
+ kind: ErrorKind = field(init=False, repr=False, default=ErrorKind.DECRYPTION)
93
+
94
+ message: str
95
+
96
+ def __str__(self) -> str:
97
+ return self.message
98
+
99
+
100
+ @dataclass
101
+ class SignatureError(SecureChannelError):
102
+ kind: ErrorKind = field(init=False, repr=False, default=ErrorKind.SIGNATURE)
103
+
104
+ message: str
105
+
106
+ def __str__(self) -> str:
107
+ return self.message
108
+
109
+
110
+ @dataclass
111
+ class KeyMissingError(SecureChannelError):
112
+ kind: ErrorKind = field(init=False, repr=False, default=ErrorKind.KEY_MISSING)
113
+
114
+ def __str__(self) -> str:
115
+ return "Can not get key, Please check your config !"
116
+
117
+
118
+ @dataclass
119
+ class KeyExpiredError(SecureChannelError):
120
+ kind: ErrorKind = field(init=False, repr=False, default=ErrorKind.KEY_EXPIRED)
121
+
122
+ def __str__(self) -> str:
123
+ return "Key has expired"
124
+
125
+
126
+ @dataclass
127
+ class NonceReusedError(SecureChannelError):
128
+ kind: ErrorKind = field(init=False, repr=False, default=ErrorKind.NONCE_REUSED)
129
+
130
+ def __str__(self) -> str:
131
+ return "Nonce is reused"
@@ -0,0 +1,23 @@
1
+ __all__ = [
2
+ "DEBUG",
3
+ "INFO",
4
+ "WARNING",
5
+ "ERROR",
6
+ "CRITICAL",
7
+ "FORMAT",
8
+ "LogConfig",
9
+ "debug",
10
+ "info",
11
+ "warning",
12
+ "error",
13
+ "critical",
14
+ "init_log_config",
15
+ ]
16
+ from .config import DEBUG, INFO, WARNING, ERROR, CRITICAL, FORMAT, LogConfig
17
+ from .logger import init_log_config, info, debug, warning, error, critical
18
+
19
+ _initialized = False
20
+ if not _initialized:
21
+ config = LogConfig()
22
+ init_log_config(config)
23
+ _initialized = True