@h-ai/crypto 1.0.0-beta.6 → 1.0.0-beta.8

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.
package/README.en.md CHANGED
@@ -156,6 +156,8 @@ if (hashed.success) {
156
156
 
157
157
  #### Transport encryption (crypto.transport)
158
158
 
159
+ Transport client `destroy()` invalidates and aborts an in-flight handshake; late results cannot restore keys or overwrite the next handshake. It clears local state; server registry entries retain their own expiry.
160
+
159
161
  See the [Transport v2 wire protocol](TRANSPORT-PROTOCOL.md) for canonical encoding, verification order and replay persistence.
160
162
 
161
163
  The `crypto.transport` namespace provides transport encryption, allowing `@h-ai/serv`, `@h-ai/kit`, and `@h-ai/api-client` to share protocol constants and payload formats.
package/README.ja.md CHANGED
@@ -21,6 +21,8 @@
21
21
 
22
22
  ### セキュリティに関する注意
23
23
 
24
+ 伝送クライアントの `destroy()` は進行中のハンドシェイクを無効化して中断し、遅延結果による鍵の復活や次回ハンドシェイクの上書きを防ぎます。サーバー registry は自身の期限で回収します。
25
+
24
26
  - **SM4 の既定の暗号化結果は構造化された暗号文**:`crypto.symmetric.encrypt(data, key)` は既定で CBC + ランダム IV を使用し、`{ mode, ciphertext, iv, encoding }` を返します。復号時はこのオブジェクトを `crypto.symmetric.decrypt(payload, key)` に渡します。
25
27
  - **SM4 にはランダムな鍵を使用してください**:`crypto.symmetric.generateKey()` で鍵を生成します。このモジュールはパスワードから暗号鍵を導出する KDF を提供しません。パスワードの保存にはサーバー専用の `crypto.password.hash(password)` を使用し、パスワードやそのハッシュを直接 SM4 の鍵にしないでください。
26
28
  - **IV は毎回一意にしてください**:同じ鍵で IV を再利用してはいけません。既定の CBC または `encryptWithIV()` による毎回の自動生成を推奨します。IV は暗号文と一緒に送信・保存します(公開可能で、秘密にする必要はありません)。
package/README.md CHANGED
@@ -156,6 +156,8 @@ if (hashed.success) {
156
156
 
157
157
  #### 传输加密(crypto.transport)
158
158
 
159
+ 传输客户端 `destroy()` 使在途握手失效并取消网络等待;迟到结果不能恢复密钥或覆盖下一次握手。它只清理本地会话,服务端 registry 仍按自己的租约回收。
160
+
159
161
  规范编码、验证顺序与 nonce 持久化要求见 [Transport v2 协议](TRANSPORT-PROTOCOL.md)。
160
162
 
161
163
  传输加密统一通过 `crypto.transport` 命名空间提供,供 `@h-ai/serv`、`@h-ai/kit` 与 `@h-ai/api-client` 复用同一套协议常量和载荷格式。
package/dist/index.js CHANGED
@@ -1125,7 +1125,9 @@ function createTransportClient(options) {
1125
1125
  let serverKeyId = null;
1126
1126
  let clientId = null;
1127
1127
  let initPromise = null;
1128
- async function doInit() {
1128
+ let generation = 0;
1129
+ let handshakeController;
1130
+ async function doInit(attemptGeneration) {
1129
1131
  const kpResult = options.crypto.asymmetric.generateKeyPair();
1130
1132
  if (!kpResult.success)
1131
1133
  return err(HaiCommonError.INTERNAL_ERROR, cryptoM("crypto_transportClientKeyGenerateFailed"), kpResult.error);
@@ -1133,6 +1135,7 @@ function createTransportClient(options) {
1133
1135
  if (new TextEncoder().encode(localKeyPair.publicKey).byteLength > TRANSPORT_BODY_LIMITS.publicKeyBytes)
1134
1136
  return err(HaiCommonError.INTERNAL_ERROR, cryptoM("crypto_transportClientKeyGenerateFailed"));
1135
1137
  const controller = new AbortController();
1138
+ handshakeController = controller;
1136
1139
  const timeout = setTimeout(() => controller.abort(new DOMException("Key exchange timed out", "TimeoutError")), 3e4);
1137
1140
  try {
1138
1141
  let response;
@@ -1169,6 +1172,8 @@ function createTransportClient(options) {
1169
1172
  } catch {
1170
1173
  return err(HaiCommonError.INTERNAL_ERROR, cryptoM("crypto_transportBodyLimitInvalid"));
1171
1174
  }
1175
+ if (attemptGeneration !== generation || controller.signal.aborted)
1176
+ return err(HaiCommonError.INTERNAL_ERROR, cryptoM("crypto_transportClientNotInitialized"));
1172
1177
  keyPair = localKeyPair;
1173
1178
  serverPublicKey = body.serverPublicKey;
1174
1179
  serverKeyId = body.serverKeyId;
@@ -1176,17 +1181,20 @@ function createTransportClient(options) {
1176
1181
  return ok(void 0);
1177
1182
  } finally {
1178
1183
  clearTimeout(timeout);
1184
+ if (handshakeController === controller)
1185
+ handshakeController = void 0;
1179
1186
  }
1180
1187
  }
1181
1188
  async function ensureReady() {
1182
1189
  if (clientId && serverPublicKey)
1183
1190
  return ok(void 0);
1184
1191
  if (!initPromise) {
1185
- initPromise = doInit().then((result) => {
1186
- if (!result.success)
1192
+ const pending = doInit(generation).then((result) => {
1193
+ if (!result.success && initPromise === pending)
1187
1194
  initPromise = null;
1188
1195
  return result;
1189
1196
  });
1197
+ initPromise = pending;
1190
1198
  }
1191
1199
  return initPromise;
1192
1200
  }
@@ -1360,6 +1368,9 @@ function createTransportClient(options) {
1360
1368
  encryptedFetch,
1361
1369
  ready: () => clientId !== null && serverPublicKey !== null,
1362
1370
  destroy() {
1371
+ generation++;
1372
+ handshakeController?.abort();
1373
+ handshakeController = void 0;
1363
1374
  keyPair = null;
1364
1375
  serverPublicKey = null;
1365
1376
  serverKeyId = null;