回收 411 MB(470 M → 58.8 M),全部经回收站,可恢复: - 待清理/(146.2 M,含 relay 分片 128 M 与 42 项过程目录) - tmp/(32.4 M,按接续棒命名的过程临时区) - .workbuddy/tmp/(39.5 M) - 4 份 workbuddy.db 冗余副本(101 M,09-23 事故的坏副本 / 抢救产物) - tmp/im16/gw/centrifugo 二进制(63.9 M,可重下)+ 缓存残留 入库范围:常驻规则(CODEBUDDY.md / README.md / state.py)、在途接续入口与 接续包、docs/、交付物/、交接单/、归档/、scripts/、.codebuddy/、 .workbuddy/memory/;共 398 件,其中 >60 KB 的 26 件全为文档。 排除(.gitignore):tmp/、待清理/、运行态日志与缓存、*.db 与 DB 备份整目录、 打包二进制(*.tar.gz / *.tgz)、记忆修复前备份。
69 KiB
交接单 · 组密钥加密(块级共享与机密性兼得)
- 序号:覆盖网络线 序 ㉘ · 规划棒 → 单 B(执行棒待跑)
- 立单:2026-09-18 00:5x
- 用户拍板:「选 C 组密钥加密」(2026-09-17 23:2x,原话;⚠️ 该档位在 23:3x 的更正轮里明确未变)
- 上游依据:入口 §4 用户口径「按照连接稳定高效的方式 数据安全可加密传输」|
交接单_骨干稳定选路与加密_20260917.md(§4 加密属真取舍、已登记待评估)|交接单_内容分发块级寻址_20260917.md(序 ㉔ 块级内容寻址已落地) - 归档号:130(占号动作已执行,见 §11;⛔ 63 是空号、不补占)
- 状态:待执行
本单与
交接单/README.md §二8 段模板的对应:§1 目标|§2 只读前置|§3 范围|§4 步骤|§5 验收(模板 6)|§6 回滚(模板 7)|§7 决策点 + 影响面|§8 回报格式(留空给执行棒)|§9 回头条件|§10 未验证项|§11 指纹与状态。
§0 摘要
0.1 摘要(一句话)
给内容面加一层"组密钥"对称加密:同一个「内容组」共享一把对称密钥 ⇒ 组内密文逐字节一致 ⇒ 序 ㉔ 的「按哈希共享块」仍然成立(去重与同组 peer 命中不退化),同时中继进程读不到明文载荷。⇒ 相对「按接收者 E2E」(牺牲性能)与「保持现状」(牺牲对中继的机密性),本方案两者兼得。
0.2 🔴 本棒一条必须纠正的前人前提(取证得出,⛔ 请以本棒为准)
「块 id 用明文哈希 ⇒ 跨组也能共享同一块」 —— 这句在上游讨论里被当作明文哈希的主要优点。本棒取证判定:在本方案(组密钥加密)下它不成立。
理由(两条,均为可读源码事实):
- 序 ㉔ 的跨组共享今天本就是被显式拒绝的 ——
src/net/relay/content/peer.ts:64-72的sameGroup()是"跨组"的唯一判据处,配套计数器crossGroupDenied;验收E5的口径就是"跨组 0 穿透且crossGroupDenied ≥ 1"(参数表 §6OBS-17)。⇒ 明文哈希拿不到一个今天不存在的收益。 - 🔑 加密之后,"共享密文"这件事本身失去意义 —— 组密钥是组作用域的 ⇒ 组 B 即便取到组 A 的密文块,没有组 A 的密钥就解不开(强行用组 B 密钥解 ⇒ 校验失败)。⇒ 所谓"跨组共享同一块"只共享了一堆解不开的字节。
⇒ 结论:明文哈希的"跨组共享"优点在本方案下净收益 ≈ 0,而它的缺点(中继可对已知明文做存在性确认)仍在 ⇒ 本单推荐"密钥相关/密文相关哈希"(见 §7.3,⛔ 该处是真取舍,已给逐项优缺点与推荐理由)。
§1 目标
内容面(src/net/relay/content/** 及其装配点)新增组密钥加密层,满足三条:
- 组内密文一致:同一组、同一明文块,任意节点加密后密文逐字节相同(
md5相等); - 共享不退化:同组内第二次取块命中
local或peer档(⛔ 不许退化成"次次回源"); - 中继看不到明文载荷:relay 进程持有的任何持久/日志/
/status里不含明文块字节,且不持有可解密的密钥。
可判定的"做完了没有":§5 的 F1–F6 全绿 —— 特别是 F1(同组密文一致)+ F2(命中 local/peer)+ F3(跨组不可解)+ F4(明文不出现,且反向夹具证明 F4 有效**)+ F5(E1 主判据不退化)**。
§2 只读前置(执行前必须先核实,逐条给命令与期望输出)
全部只读;⛔ 不改任何文件、不改任何生产值。任一条与期望不符 ⇒ 停下报告。
| # | 核实内容 | 命令 | 期望输出 |
|---|---|---|---|
| 1 | 组定义现状(能否复用,⛔ 不新造) | cd D:/github/dsh_shenxian && grep -n -A3 "export function groupKeyOf" src/net/relay/content/peer.ts; grep -n "CONTENT_GROUP|DSHS_CONTENT_GROUP" src/web/server.ts src/net/relay/main.ts |
组键 = <network>|<group>(分隔符 |,:61)|平台侧缺省 'local'(web/server.ts)、relay 侧 'relay'(main.ts)—— 刻意分开(防"两个进程误以为同组")。⇒ "组" = (网, 组) 二元组,与序 ㉔ 同构 ⇒ 直接复用。 |
| 2 | 块 id 算法现状(本单取舍的起点) | grep -n -A3 "export function blockIdOf" src/net/relay/content/chunker.ts |
sha256(字节).slice(0, 32) = 对明文哈希(⚠️ 若已变成密钥相关 ⇒ 本单已被别人做过 ⇒ 停下报告)。 |
| 3 | 现有加密面(本线尚无内容层加密) | grep -rniE "encrypt|cipher|gcm|aes|chacha" src/net/relay/ --include=*.ts | wc -l |
0(本棒实测)。⇒ 加密层是纯新增,⛔ 不改既有行为。 |
| 4 | 密钥模型(四层,⛔ 不许引第二套) | sed -n '14,30p' src/net/relay/identity.ts; grep -n "asymmetricKeyType !== 'ed25519'" src/net/relay/identity.ts; ls -l /etc/dshs/overlay-signer-key.pem(47) |
四层 = 根(离线,只授权/撤销签名者)→ 签名者(在线,47)→ 节点密钥(每机一把 0600)→ 会话(内存)|🔴 节点密钥 = ed25519(identity.ts:197/318,纯签名、不能做公钥加密)⇒ 这是 §7.2 分发方案的决定性约束|签名者文件在 47 上存在。 |
| 5 | 既有对称封装(实现底座,⛔ 不新造算法栈) | sed -n '1,10p' src/crypto.ts |
AES-256-GCM + deriveKey(secret) = sha256(secret)(用于用户凭据 at-rest)。⇒ 本单的算法栈照此复用(同为 AES-256-GCM)。 |
| 6 | 中继是否能看到块 id 集合(决定 §7.3 取舍有无现实意义) | grep -n "PEER_COUNTER_KEYS|declarations|withdrawn" src/net/relay/content/peer.ts; sed -n '200,215p' src/net/relay/main.ts |
计数键含 declarations / withdrawn ⇒ 声明走 relay 消息 ⇒ 🔴 relay 进程持有 ContentPeerGroup 注册表,能看到"哪些块 id 存在"。 ⇒ §7.3 的取舍有现实意义(不是理论问题)。 |
| 7 | 基线三件套 + 参数表指纹 | cd D:/github/dsh_shenxian && npm.cmd test 2>&1 | tail -5;node scripts/overlay-probe.cjs --table;sed '/^## §10 指纹/,$d' "E:/ProgramData/AI技能/aliyun-dsh-server/参数表_覆盖网络_20260917.md" | md5sum |
npm test = 201 pass / 200 / 0 fail / 1 skip|overlay-probe --table = 19 PASS / 1 SKIP / 1 FAIL(1 FAIL = OBS-21,线内在册缺口、⛔ 非本单引入)|参数表指纹 = 7fc5889341b99fb26bd05cad0313960b(本棒 00:4x 现核)。⛔ 判据一律用现核值,本单写的是快照。 |
| 8 | OBS 编号现核(防撞号) |
grep -oE 'OBS-[0-9]+' scripts/overlay-probe.cjs | sort -u | tail -1 |
本棒实测 = OBS-21 ⇒ 本单预留 OBS-23(OBS-22 已分配给单 A);⚠️ 若执行时已被占用 ⇒ 顺延(序 ㉖ 踩过编号被前序占用)。 |
§3 范围
3.1 在册文件集
| 面 | 文件 | 说明 |
|---|---|---|
| 新增 | src/net/relay/content/crypto.ts |
组密钥装载(0600 文件)+ 加解密 + 组内确定性(收敛)加密 + epoch 管理 |
| 改动 | src/net/relay/content/chunker.ts |
块 id 口径(⛔ 仅在 §7.3 选定 β 时需要;选 α 则一行不改) |
| 改动 | src/net/relay/content/store.ts |
put/get 接入密文口径 + 新增 decryptRejected 计数 |
| 改动 | src/net/relay/content/source.ts |
五档链路的取回结果统一解密 + 失败留痕 |
| 改动 | src/net/relay/content/peer.ts |
同组判定与 epoch 一致性(⛔ 仍只认 sameGroup,不放松跨组) |
| 改动 | src/net/relay/content/runtime.ts |
装配组密钥(缺省不启用 ⇒ 行为不变) |
| 改动 | src/net/relay/main.ts |
relay 侧装配(第 5 条 contentRuntime,:208) |
| 改动 | src/web/server.ts |
平台侧装配(contentSource/contentPeers 一带) |
| 改动 | scripts/overlay-probe.cjs |
新增 OBS-23 |
| 改动 | test/overlay-content.test.mjs |
新增 F 组用例(⛔ 不改 package.json test 列表结构) |
| 改动 | 参数表_覆盖网络_20260917.md |
§3.6 新增加密键 + §6 新增 OBS-23 |
| 改动 | scripts/overlay-keyring.cjs |
扩展"组密钥"签发/验签子命令(复用既有仪式 CLI) |
3.2 ⛔ 不动什么(防顺手扩大)
- ⛔ 不引入第二套密钥体系 —— 不新根、不新签名链;组密钥的授权方仍是既有签名者(见 §7.2)。
- ⛔ 不动
wire.ts的帧格式与既有消息号(新增消息须另立单);⛔ 不动keys.ts/identity.ts的既有语义(只扩展)。 - ⛔ 不动
RELAY_FAILOVER_*/HB_SEC/ burst /switcher.ts的冷却语义。 - ⛔ 不放松跨组 ——
crossGroupDenied必须保持"跨组 0 穿透"(E5不得退化)。 - ⛔ 不改加密传输层(TLS 由 nginx 终结,已是现状)—— 本单只做内容载荷层。
- ⛔ 不新增公网监听口、不改
nft/nginx(R5)。 - ⛔ 不改任何生产值(D1);⛔ 不 commit / 不 push(R7)。
- ⛔ 不许顺手做:房间层 / 打洞实现(本线明令不做)。
§4 步骤(每步自带一次可执行的验证)
三条硬门贯穿全程:D1|R5|R7。
S0 · 开工对账
- 跑 §2 全部 8 条并原样留档。不符 ⇒ 停下报告。
- 抢锁:
bash "D:/github/dsh_shenxian/dsh-server-docs/scripts/handoff-guard.sh" --claim-exec "覆盖网络线-序28单B执行棒";抢不到 ⇒ 只报告并停(R9)。 - 验证:guard 返回「✓ 已持全局执行锁」。
S1 · 组密钥的定义与装载(复用四层模型,⛔ 零新信任根)
- 密钥形状:
groupKey = 32 字节随机对称密钥(与src/crypto.ts的 AES-256-GCM 口径一致);随密钥记录epoch(单调递增整数)。 - 装载:
src/net/relay/content/crypto.ts从一个0600文件读{ group, epoch, key(base64) };文件缺失 / 权限不对 / 组名不匹配 ⇒ 一律"不启用加密"并记一行判别器日志(⛔ 不静默降级成"以为加密了")。 - 授权:由既有签名者(47,
/etc/dshs/overlay-signer-key.pem)用既有签名载荷签发(group, epoch, keyId)三元组(⛔ 载荷内不含密钥本体);节点用既有验签链校验 ⇒ 认下当前 epoch。 - 验证:
node scripts/overlay-keyring.cjs <子命令>生成的凭据能被既有directory.ts/identity.ts的验签路径接受(rc=0);篡改epoch⇒ 验签失败(失败关闭)。
S2 · 组内确定性(收敛)加密 —— 本单的技术核心
- 目标:同组 + 同明文 ⇒ 同密文(否则"按哈希共享块"直接失效)。
- 做法(三行即可说清):
k_block = HKDF/HMAC(组密钥, 明文块)派生块级密钥;IV = HMAC(组密钥, 明文块) 的前 12 字节(确定性、不留随机数);密文 = AES-256-GCM(k_block, IV, 明文);认证标签一并存(篡改即读侧丢弃)。 - ⚠️ 必须同时落 AAD:把
(group, epoch)绑进 AAD ⇒ 跨 epoch / 跨组的密文在认证阶段就被拒(⛔ 不靠"解出来是乱码"来判)。 - 验证(先红后绿):对同一明文加密 2 次 ⇒ 密文
md5相等;换epoch⇒ 密文不等(且旧 epoch 密文用新密钥解 ⇒ 认证失败)。
S3 · 块 id 口径(⛔ §7.3 选定的那一项)
- 推荐项(β':密文哈希):
blockId = sha256(密文).slice(0,32)—— 因为 S2 已保证组内密文一致 ⇒ 组内 id 稳定、组外 id 不可预测。 - 验证(先红后绿):同组两次独立"切块 + 加密" ⇒ 块 id 序列逐字一致;换组密钥 ⇒ 全部 id 改变(这是"轮换 ⇒ 全量回源"的直接证据,必须留档,不得粉饰)。
S4 · store / source / peer 接入
store.put/id/get全程只处理密文(读回后 S2 解密 + 认证);get认证失败 ⇒ 丢弃 +decryptRejected += 1(⛔ 不静默返空)。source.ts五档链路的解密位置统一(⛔ 不许"local 档不解密、peer 档解密"这种双口径)。peer.ts:仍只认sameGroup;新增 epoch 一致性:声明(group, epoch),epoch 不一致不视为同组可用(⇒ 轮换过渡期由 S5 处理)。- 验证:
test/overlay-content.test.mjs原 27 例不退化;新增 F 组用例(§5)。
S5 · 轮换与过渡态
- 新成员获取:见 §7.2(密钥本体不经 relay)。
- 成员退出 / 例行轮换:签名者签新
epoch⇒ 节点加载新密钥(旧 epoch 保留为"仅解不写")⇒ 过渡窗口内新旧密文都能解;写入一律用新 epoch。 - 过渡窗口必须上界:参数化(建议
CONTENT_EPOCH_GRACE_MS,⚠️ 值格 ⛔ 必须纯数字,不得夹注 —— 夹注会被读成NaN⇒ 假红)。 - 验证:新旧 epoch 混存时,两种密文都能解;超窗口后旧 epoch 密文 ⇒
decryptRejected += 1且点名。
S6 · 判据(OBS-23 + 夹具 + 先红后绿)
- 夹具四段(照序 ㉔
--content-fixture的做法):OFF(无加密键)/ON(同组)/CROSS(跨组)/ROT(双 epoch)。 OBS-23三判据(见 §5):① 加解密计数键齐全(⛔ 缺一即 FAIL)② 同组密文一致 + 命中local/peer③ 明文不出现(对已知明文标记做字节级断言)。- 真机先红:新
OBS-23对旧生产 ⇒ FAIL(并打印可区分证据)。 - 验证:四段夹具的判定与预期逐段一致,且 OFF/CROSS/ROT 三段的 FAIL/PASS 互不混淆。
S7 · 部署 + 零回归 + 收口
npm run build⇒ 铺到四处(47/opt/dshs/lib+/opt/dsh-relay/lib、106/opt/dshs-cluster/lib+/opt/dsh-relay/lib)—— 🔴 relay 类产物必须两边都铺(序 ㉖ 踩过"dshs侧落后一个版本")。- 部署前建回滚点
/opt/dsh/backups/seq28-<ts>/(旧 md5 记录在 §8)。 - ⚠️ 密钥文件与 env 的铺发属运维动作:落地前先确认密钥文件权限 =
0600、属主正确(⚠️ 本线史上有"属主被改 ⇒ 实例全崩"的先例)。 - 重启
dshs-relay(两台)+dshs(47)+dshs-worker(106)(R8:动手前一句话说明)。 - 零回归:
npm.cmd test|--scene all --table= 12 PASS / 0 SKIP / 0 FAIL|--table= 基线 +1 行(OBS-21仍 FAIL = 线内在册缺口)。 - 回填 §8;推进
接续入口_覆盖网络线_20260916.md§0 + §2;写工作区日志(append-only)。
§5 验收判据(可机器断言、可被第三方复现)
| # | 判据 | 命令 / 口径 | 期望 | 为什么必须有它 |
|---|---|---|---|---|
| F1 | 同组密文一致(本单技术核心) | 夹具 ON:同一明文块独立加密 2 次 ⇒ md5 比对 |
相等 | 不等 ⇒ "按哈希共享块"直接失效(序 ㉔ 的 E1 崩) |
| F2 | 共享不退化 | 夹具 ON:第一次取块后第二次取块 ⇒ 两次 /status 的 content.store.hits / content.peer.peerHits 增量 ≥ 1 |
命中 local 或 peer |
只判 F1 不够 —— 加密对了但"次次回源"会全绿(这正是序 ㉔ OBS-17 判据③ 存在的理由) |
| F3 | 跨组不可解 | 夹具 CROSS:组 B 用自己密钥解组 A 的密文 | 认证失败 + decryptRejected +1 + crossGroupDenied 不减少 |
保证"加密 ≠ 放松隔离";E5(跨组 0 穿透)不得退化 |
| F4 | 🔴 明文不出现(+反向证明 F4 有效) | ① 用唯一标记串写一个块 ⇒ 在 relay 进程可见面(持久存储 / journalctl / /status)做字节级搜索 ⇒ 命中 0;② 反向夹具:关闭加密(OFF 段)⇒ 同一搜索 必须命中 ≥ 1 |
① 0 ② ≥ 1 |
🔴 只判 ① 是假绿风险 —— "没测到"和"真没有"必须可分(本线两处静默失效都栽在这里)。⇒ ② 是 ① 的有效性证明,不可省 |
| F5 | E1 主判据不退化 |
序 ㉔ 原口径:N=4 同组回源字节数 |
≤ 1 份 × 组数(序 ㉔ 收口值 = 1.0000×,⛔ 不许变成 4.00×) | 加密的最大风险就是"把块级共享打回去" |
| F6 | 失败关闭(⛔ 不静默降级) | 密钥缺失 / 权限错 / 组名不配 / epoch 超窗口 四种情形各跑一次 | 每种 都有具名判别器留痕 + 计数 +1;⛔ 不许出现"以为加密了其实没加" | 本线反复复发的那类病("配错了"伪装成"不通") |
| F7 | 零回归 | npm.cmd test|--scene all --table|--table |
不退化(§2-7 现核基线 + 探针 +1 行) | — |
OBS-23 的形状(进 scripts/overlay-probe.cjs;编号须现核顺延)
- 三判据:①
content.crypto计数键齐全且皆number(⛔ 缺一即 FAIL —— 这正是"静默放行"的机器判据)② F1 + F2 ③ F4①(明文不出现)。 - ⛔ 缺行即 FAIL,并把
journalctl的原文字节数一并打出(0 字节= 读取失败/>0= 真没有该行,二者必须可分)。 - ⚠️ 值格必须是纯数字(参数表规则)—— 加密相关键里凡"模式名"性质的一律只作信息键,⛔ 不进数值判据。
§6 回滚
回滚 = 关掉加密层(缺省即关闭)⇒ 秒级,且不丢数据。
路 A · 配置回滚(推荐,秒级)
- 组密钥文件移除 / 改名(或把启用开关置回缺省)⇒
crypto.ts走"不启用"分支 ⇒ 行为逐字回到序 ㉔ 现状。
ssh -p 22 bt-server 'mv /etc/dshs/content-group-key.json /etc/dshs/content-group-key.json.off && systemctl restart dshs-relay dshs'
ssh -p 22 test106 'mv /etc/dshs/content-group-key.json /etc/dshs/content-group-key.json.off && systemctl restart dshs-relay dshs-worker'
- 验收:
overlay-probe --table的OBS-23从 PASS → SKIP 或 FAIL-并点名"未启用";npm test不退化。⚠️OBS-23的"未启用"必须是 SKIP 还是 FAIL 要在 S6 就定死(建议 SKIP + 留痕,因为"缺省不启用"是合法状态;⛔ 但不许既不是 SKIP 也不是 FAIL 的"静默绿")。 - ⚠️ 已有的密文块会解不开 ⇒ 回滚后这些块按"认证失败"被丢弃(
decryptRejected +1)⇒ 清一次CONTENT_STORE_MAX_BYTES的缓存目录即可(属可逆操作:块能从 origin 重取)。
路 B · 产物回滚(秒级)
ssh -p 22 bt-server 'cp /opt/dsh/backups/seq28-<ts>/*.js /opt/dshs/lib/net/relay/content/ && cp /opt/dsh/backups/seq28-<ts>/relay/*.js /opt/dsh-relay/lib/net/relay/content/ && systemctl restart dshs-relay dshs'
- 回滚点:
/opt/dsh/backups/seq28-<ts>/(S7 部署前创建,旧 md5 记入 §8)。⛔ 没有回滚点不准上线。
🔴 回滚路径硬禁令
⛔ 不许把 RELAY_FAILOVER_COOLDOWN_MS=0 写进任何回滚 / 演练 / 夹具路径 —— 它会自锁(实测 121–123 s 无切换);判定见 §9-1。
§7 决策点 · 取舍 · 影响面
7.1 决策点
- 已定(用户):加密档位 = C 组密钥加密(2026-09-17 23:2x,23:3x 未变)。
- 已定(本棒,可推翻):
- 「组」定义 = 复用序 ㉔ 的
(network, group)(依据 §2-1,peer.ts:61),⛔ 不新造。 - 算法栈 = AES-256-GCM(依据 §2-5,与既有
src/crypto.ts同源),⛔ 不引 ChaCha 等第二栈。 - 探针编号 =
OBS-23(OBS-22归单 A;执行时现核顺延)。
- 「组」定义 = 复用序 ㉔ 的
- 待定 = 空。⛔ 本单无上抛项。
7.2 密钥从哪来(复用四层模型,⛔ 零新信任根)
复用/扩展的对应关系(照 identity.ts:14-30 的四层表逐层落位):
| 四层原本 | 本单如何复用/扩展 |
|---|---|
| 根(离线) | 不动 —— 它只授权/撤销"签名者",⛔ 不签发组密钥(守住既有用途边界) |
| 签名者(在线,47) | 扩展职责:原"签发节点入网凭据" ⇒ 追加"签发组密钥凭据 (group, epoch, keyId)"。同一把钥匙、同一条签名链、同一个验签入口。 |
| 节点密钥(每机一把) | 不动(仍是 ed25519,仍只做签名/身份)。🔴 注意:ed25519 不能做公钥加密(identity.ts:197/318 硬校验)⇒ 见下方"分发" |
| 会话(内存) | 扩展:原本只标"隧道传输加密" ⇒ 追加"内容组加密"这一档:组密钥(落盘 0600 + 内存) |
分发(本阶段):
- ✅ 密钥本体不经网络、不经 relay —— 由运维按既有
0600惯例落文件(与节点密钥同处/etc/dshs/),链路 = 既有部署通道(scp/ drop-in)。理由:① 节点密钥是ed25519,做不了公钥包裹;② 任何"经 relay 传密钥"的做法都等于把密钥交给中继,前功尽弃。 - ✅ 签名者只广播
(group, epoch, keyId)三元组(⛔ 不含密钥),节点据此确认"当前 epoch 是几",防"版本错配"。 - ⚠️ 规模化的自动分发 ⇒ 登记为回头条件(§9-7):届时需给节点密钥并行加一把
x25519(或做 Ed25519→X25519 派生)才能上"公钥包裹"。⛔ 本单不做(那是新增密钥类型,属另立单)。
7.3 🔴 本单最关键的取舍:块 id 用明文哈希还是密钥相关哈希
两者竖排成段,逐项列「优点 / 缺点」。⛔ 不横排、⛔ 不做成表格的列。
选项 α —— 块 id = 明文哈希(sha256(明文块),⛔ 序 ㉔ 现状一行不改)
优点:
- 序 ㉔ 的
chunker.ts/OBS-17/ 既有E1判据零改动,改动面最小; - 轮换组密钥不改变块 id ⇒ 轮换不触发全量回源(这是它唯一真实的、且不小的优点)。
缺点:
- 🔴 它承诺的"跨组共享同一块"在本方案下不成立(§0.2 已取证:组外没有组密钥 ⇒ 拿到密文也解不开;且
E5本就要求跨组 0 穿透)⇒ 该"优点"净收益 ≈ 0; - 🔴 把"哪些块存在 + 内容指纹"暴露给中继:relay 进程持有
ContentPeerGroup注册表(§2-6 实测)⇒ 中继可用已知明文对 id 做存在性确认("这个包在这张网里存在吗")⇒ 与用户"数据安全"的口径直接相悖; - 明文 id ↔ 密文存储还要额外维护一张映射 ⇒ 中继侧多一张可被探测的索引表(更糟)。
选项 β' —— 块 id = 密钥相关/密文相关哈希(sha256(密文),因 S2 已保证组内密文一致)
优点:
- 🔴 组外不可见:中继只看到不透明 id,连"是否存在该块"都判不出来(这正是"数据安全"要的那一半);
- 组内完全兼容:S2 的确定性加密已保证"同组 + 同明文 ⇒ 同密文" ⇒ 组内 id 稳定 ⇒ 按哈希共享块仍然成立(完全满足用户选 C 档位的原意);
- 与
E5(跨组 0 穿透)天然一致 —— 它不损失任何今天存在的收益。
缺点:
- 🔴 轮换组密钥 ⇒ 全部块 id 改变 ⇒ 一组一次全量回源(正面撞序 ㉔ 主判据
E1); - 签名目录 / 索引必须携带
epoch,否则新旧 id 无法共存(⇒ S5 的双 epoch 过渡态不可省); - 组外永久失去块级复用(⚠️ 但见 §0.2:这在加密之后本就无意义)。
我的推荐 = β'(密钥相关/密文相关哈希),理由三条:
- 用户要的是"中继看不到明文载荷" —— α 虽然也加密了载荷,但仍把块存在性与内容指纹交给中继,属"做了一半";
- α 的"跨组共享"优点在本方案下已被取证判定为不成立(§0.2)⇒ α 剩下的只有缺点 ⇒ 按判据("只有缺点的候选自己拍掉")不选 α;
- β' 是唯一同时满足"组内共享成立 + 组外不可见"的选项,且与既有
E5语义同向。 ⚠️ β' 的代价必须如实接受并写进参数:轮换 = 一次全量回源 ⇒ 轮换频率要有下限(参数化)+ 且优先安排在版本发布窗口(那时本来就要重灌)⇒ §9-8 回头条件。
7.4 影响面与关系
- 影响面:内容面(首屏包分发) —— 只影响
local/peer/edge/region/origin五档链路的字节形态与块 id;⛔ 不影响实例生命周期、路由、切流、dsh_hosts、lease、端口分配(与单 A 完全无交集,两单可并行但不共用文件)。 - 与 presence / room 层:无交集。
- 与
E1:见 F5;β' 下轮换窗口是唯一会让E1短暂退化的时刻。
§8 回报格式(留空给执行棒)
逐节回填,每节必须给命令 + 原始输出(或原文摘录)+ 判定。⛔ 不许只写结论。
本棒身份:
覆盖网络线-单B执行棒-组密钥加密(automation65d2fc24-770e-4f33-93a3-db6e739aded7)· 一次性、无人值守。 时间:开工2026-09-18 06:22(抢锁成功)→ 收口2026-09-18 07:2x。 证据落盘:全部原始输出在E:\ProgramData\AI技能\aliyun-dsh-server\_tmp_seq31\(下文各节标注文件名)。
8.1 开工对账(§2 八条)
锁:bash D:/github/dsh_shenxian/dsh-server-docs/scripts/handoff-guard.sh --claim-exec "覆盖网络线-单B执行棒-组密钥加密" ⇒ ✓ 已持全局执行锁(06:22,一次抢到,⛔ 无等待重试)。
| # | 核实内容 | 实测(原文摘录) | 判定 |
|---|---|---|---|
| 1 | 组定义现状 | 组键 = <network>|<group>(peer.ts#groupKeyOf);平台侧缺省 'local'(web/server.ts)、relay 侧 'relay'(main.ts) |
✅ 与期望一致 ⇒ 组 = (network, group) 二元组,直接复用(⛔ 未新造) |
| 2 | 块 id 算法现状 | blockIdOf = sha256(字节).slice(0,32),对明文 |
✅ 开工时为 α(明文哈希) ⇒ 本单未被别人做过,可继续 |
| 3 | 现有加密面 | grep -rniE "encrypt|cipher|gcm|aes|chacha" src/net/relay/ --include=*.ts | wc -l = 0 |
✅ 加密层纯新增 |
| 4 | 密钥模型 | 四层:根(离线)→ 签名者(47 /etc/dshs/overlay-signer-key.pem,0600)→ 节点密钥(每机 0600)→ 会话内存;节点密钥 = ed25519(identity.ts:197/318) |
✅ 与期望一致;🔴 ed25519 纯签名、不能公钥加密 ⇒ 决定"密钥本体只能走文件/scp" |
| 5 | 既有对称封装 | src/crypto.ts = AES-256-GCM + deriveKey = sha256(secret) |
✅ 本单算法栈照此复用(⛔ 未引第二栈) |
| 6 | 中继能看到块 id 集合 | peer.ts 计数键含 declarations / withdrawn;relay 进程持 ContentPeerGroup 注册表 |
✅ ⇒ §7.3 的取舍有现实意义 |
| 7 | 基线三件套 + 参数表指纹 | npm.cmd test ⇒ 201 tests / 200 pass / 0 fail / 1 skip(与单内基线逐字同);overlay-failover-drill --scene all ⇒ 12 PASS / 0 SKIP / 0 FAIL;overlay-probe --table ⇒ ⚠️ 开工那一刻演练正在跑(relay 被反复起停)⇒ 18 PASS / 1 SKIP / 3 FAIL(红 = OBS-01/OBS-04/OBS-08,演练暂态);参数表 §10 指纹现核 = 3b295a8c43aafc4a62c6f1a59ea0b43a |
⚠️ 探针开工值不是单内快照的 19P/1S/1F —— 原因是"序㉙ 已把 OBS-21 转绿(22P 稳态)"+"开工时刻撞上演练暂态(3 红)";收口前的稳态基线 = 22 PASS / 0 SKIP / 0 FAIL(S7-probe-1.txt 实测)⇒ 本棒目标 = 23P/0S/0F |
| 8 | OBS 编号现核 |
grep -oE 'OBS-[0-9]+' scripts/overlay-probe.cjs | sort -u | tail -1 = OBS-22 |
✅ OBS-23 未被占用,按单内预留使用(⛔ 未顺延) |
判定:八条全部相符 ⇒ 未触发"停下报告";三条硬门(D1 / R5 / R7)自开工起全程有效(见 8.11)。
8.2 组密钥凭据(签名者签发 + 验签通过 + 篡改必失败)
① 生成组密钥(本机) —— node scripts/overlay-keyring.cjs init-group-key --group relay --epoch 1 --out _tmp_seq31/content-group-key.json(init-group-key.txt):
✓ 组密钥文件:E:/ProgramData/AI技能/aliyun-dsh-server/_tmp_seq31/content-group-key.json(0600)
✓ group=relay epoch=1 keyId=3560130eb0e5e4aa(⚠️ 密钥本体只在文件里,⛔ stdout 不打印)
- 文件六键 =
version / network / group / epoch / key(44 B base64 = 32 B) / previous([]);keyId = sha256(key) 前 16 hex。 - ✅ stdout 只出 keyId(⛔ 无密钥本体、⛔ 无 base64 片段)。
② 签名者签发三元组(47,既有签名者) —— 命令口径 sign-group-key --signer-key /etc/dshs/overlay-signer-key.pem --network ops --group relay --epoch 1。凭据原文(group-key-credential.json,274 B):
{ "doc": { "version":1, "network":"ops", "group":"relay", "epoch":1,
"keyId":"3560130eb0e5e4aa", "issuedAt":"2026-09-17T22:54:40.439Z" },
"sig": "I2KOPpUMntkR1cNuXpR0zpUIayVeLRuEtPjRxym71Dh6vlkHB9vadDQPfVrMH+6bgX6fC8ipekdSuRjm76VtAg==" }
- 🔴 载荷内不含密钥本体(逐字核):
凭据含 "key" 字段 = False、凭据含密钥片段(key 前16字符) = False⇒ 三元组就是三元组。 - 公钥 / keyId:签名者公钥 =
bad464dfd53048efe7b8531029b3030eda49bc12930703d3a2a8f60e3a7daddf(47/etc/dshs/overlay-signer-key.pem.pub)⇒ 与既有信任表/etc/dshs/overlay-signers.json的signers[0]逐字一致(⛔ 未新根、⛔ 未新信任链);组keyId=3560130eb0e5e4aa。
③ 验签(S8-8.2.txt):
### 正例(原文凭据)
✓ 验签通过:network=ops group=relay epoch=1 keyId=3560130eb0e5e4aa rc=0
### 篡改例(epoch 1→2,sig 不变)
✗ 验签失败:signature-mismatch rc=1
### 交叉核对失败例(epoch 传 9)
✗ ⛔ epoch 不配:凭据 epoch=1 ≠ 传入 9 rc=1
- 判定:✅ 签发 ⇒ 验签通过;✅ 篡改 epoch 必失败(失败关闭);✅ 凭据不载荷密钥本体。
8.3 确定性加密(同明文两次 ⇒ 密文 md5 相等;换 epoch ⇒ 不等且旧密文认证失败)
F1(S7-f-evidence.txt):
明文 md5 = 24d6ed6ce80d7311db80fc63c67bf49a (3776 B)
密文#1 md5 = 3385e9d00ae5c5dbb880ddad90391756 (3804 B)
密文#2 md5 = 3385e9d00ae5c5dbb880ddad90391756 (3804 B)
⇒ 逐字节相同 = true | 长度 = 明文 + 28(iv 12 + tag 16)
⇒ keyId = 5ed7f6b62a053af1(夹具口径)| groupKey = ops|relay epochs=1
- 派生口径(实现):
iv = HMAC(sha256,key,"iv"‖plain)[:12]、k = HMAC(sha256,key,"k"‖iv)、AAD = "<network>|<group>|<epoch>"(⇒ 解密侧只需iv即可复原k,故确定性成立)。
F1-b(换 epoch):
epoch=2/keyB 密文 md5 = 3cab76cda498790fa4ba1329b3f0f53a ⇒ 与 epoch=1 不同 = true
用 epoch=2 解 epoch=1 的密文 ⇒ undefined(认证失败)|该 cipher 计数 decrypts=0 decryptRejected=1
用本 epoch 解自己写的 ⇒ 还原一致 = true |decrypts=1
- 判定:✅ 同组 + 同明文 ⇒ 密文逐字节相同("按哈希共享块"的前提成立);✅ 换 epoch ⇒ 不等 + 旧密文在认证阶段被拒(⛔ 不是"解出乱码")。
8.4 块 id 口径 + 轮换代价的原始读数(⛔ 不得粉饰)
β′ 口径(采单内推荐项):blockId = sha256(密文).slice(0,32)(落地为前 16 hex 展示)。原始读数(S7-f-evidence.txt):
块数 = 4(块大小 1024 B)
α ids(明文哈希) = 1d9e81b64e2fc8a2 3c929675a21f4ac9 9c43515ef7057734 28d85d5bd0b6c6f0
β′ ids(密文哈希) = 9fc1bb4b8d0ec432 a8f5dea758c1d709 66f4e823723fae3c ebe427b90b28ce55
⇒ α 与 β′ 逐位不同 = true
⇒ β′ 两次独立切块一致 = true(组内稳定 ⇒ 按哈希共享块成立)
⇒ 换组后 β′ 全变 = true
⇒ contentId(整份):α = 1cd1b222c4eb46dd7203538baa1497e8 | β′ = 1fd60cf381a79bea8f6ae4a0cefe3152
- 🔴 轮换代价(如实留档,⛔ 不粉饰):换组密钥(或换 epoch)⇒ 该组 100% 块 id 改变 ⇒ 全员一次全量回源。这是 β′ 的固有代价,不是缺陷;本棒未测得"轮换后首轮回源字节数"(§10-2 未验证项 ⇒ 记 8.13)。
- ⚠️ 与
E1的关系:稳态下不退化(见 8.9 F5);唯一退化时刻 = 轮换窗口(单 §7.4 已预告)⇒ 轮换须排进发布窗口(§9-8)。
8.5 store / source / peer 接入(含 decryptRejected 计数)
| 面 | 落法 | 证据 |
|---|---|---|
store |
只改文档(put/id/get 全程只处理密文字节,⛔ 未改既有语义) |
单测 F1-d:缺省(不传 transforms)⇒ 与序㉔ 逐字一致 |
source |
唯一解密点 = crypto.decodeBlock;调用位 ① source.ts 五档链的统一返回点 ② chunker.ts#reassemble 的夹具/工具路径(⛔ 无"local 档不解密"的双口径) |
F2:put → 链上取回两次 ⇒ local 命中递增且解密成功(local=6) |
peer |
仍只认 sameGroup;新增 epoch 一致性:epoch 不一致 不作候选 + 单独计数(⛔ 不混进 crossGroupDenied) |
F3-b / F3-c 两例 ✅;crossGroupDenied 语义未变 |
| 计数 | 十键常量 CONTENT_CRYPTO_COUNTER_KEYS = encrypts / decrypts / decryptRejected / epochs / epoch / epochExpired / detChecks / detMismatches / plainScans / plainLeaks |
探针 OBS-23 判据① 判别器齐全(⛔ 缺一即 FAIL) |
decryptRejected读数:夹具 CROSS 段 = 1(跨组被拒);夹具 ROT-EXPIRED 段 = 1(超窗口被拒);🔴 线上稳态 = 0(/status.content.crypto实测decrypts:3, decryptRejected:0)⇒ 未触发 §9-6 回头条件。- ✅
F4-c:不启用加密 ⇒crypto键整体缺席(⛔ 不是补零)⇒ 探针才能如实记SKIP。
8.6 夹具六段(OFF / ON / CROSS / ROT + ROT-EXPIRED / SCAN-MISSING)+ 先红后绿
单内写"四段",本棒按 §5 的判据面扩到六段(补
ROT-EXPIRED= 超窗口、SCAN-MISSING= 扫描腿缺失),⛔ 均为夹具、⛔ 不触真机。原文见S7-fixtures.txt。
| 段 | 预期 | 实测原文(尾段) | 判定 |
|---|---|---|---|
| OFF(无加密键) | SKIP + 留痕 | ⚠️ FIXTURE SKIP OBS-23 ⛔ 未启用组密钥加密(content.crypto 块缺席)⇒ SKIP + 留痕(缺省不启用是合法状态,⛔ 非静默绿) |
✅ |
| ON(同组) | PASS | FIXTURE PASS … detChecks=1 detMismatches=0|decrypts=6 decryptRejected=0 local+peer 命中=5|plainScans=1 plainLeaks=0|epoch=1/1 epochExpired=0 |
✅ |
| CROSS(跨组) | FAIL | FIXTURE FAIL … decryptRejected=1(须 0) |
✅ |
| ROT(双 epoch) | PASS | FIXTURE PASS … epoch=2/2 epochExpired=0|decrypts=4 |
✅ |
| ROT-EXPIRED | FAIL | FIXTURE FAIL … epochExpired=1 |
✅ |
| SCAN-MISSING | FAIL | FIXTURE FAIL … plainScans=0(阈值 ≥ 1) |
✅ |
先红后绿(代码层):把 F1 的确定性 iv 改成随机 iv ⇒ 10 例红(F1/F1-b/F1-c/F2/F4/F5 一族全线点名)⇒ 还原 ⇒ 内容面 44/44 全绿(S7-content-test.txt);
npm test 201 tests / 200 pass / 0 fail / 1 skip ⇒ 原 27 例零退化(F 组 16 例为纯追加)。
判定:✅ 六段逐段与预期一致,且 OFF(SKIP)/CROSS(FAIL)/ROT(PASS)三段互不混淆。
8.7 真机先红(新 OBS-23 对旧生产)
- 对未启用加密的旧形态(
S6-probe-oldprod.txt/S7-probe-1.txt):SKIP OBS-23 ⛔ 未启用组密钥加密(content.crypto 块缺席)⇒ SKIP + 留痕⇒ ⚠️ 本棒与单文有一处必须点明的偏差:单 §4/S6 写"对旧生产 ⇒ FAIL",但 §5 的OBS-23形状又写"缺省不启用 = SKIP + 留痕(合法状态)"。本棒按 §5 实现 = SKIP(更保守:既不静默绿、也不误报红)。⇒ "先红"改由下面那条腿取得(见 8.13-①)。 - 真机先红(实取,
S7-probe-redmode.txt):把 47 的密钥文件权限由0600改0640⇒rc = 1;全量仅 1 红(⛔ 无波及);点名可区分(直接打出"47=640 106=600",⛔ 不是笼统失败)。原文字节数 = 5,827 B(⛔ 非 0 ⇒ "没采到"与"确无"可分)。FAIL OBS-23 … 密钥文件 /etc/dshs/content-group-key.json 权限须=600:47=640 106=600 ❌ 1 项红:OBS-23 - 复绿:还原
0600⇒S7-probe-restored.txt= 23 PASS / 0 SKIP / 0 FAIL(rc=0)✅
8.8 部署对账 + 密钥文件权限取证
① 产物(18 文件 × 四处):npm run build rc=0 ⇒ 铺 /opt/dshs/lib(47)+/opt/dsh-relay/lib(47)+/opt/dshs-cluster/lib(106)+/opt/dsh-relay/lib(106)。
- 本机 md5(
deploy-local-md5.txt,18 行;另三处逐文件 diff = 0 不一致):
| 文件 | md5 | 文件 | md5 |
|---|---|---|---|
content/chunker.d.ts |
7fb3fb442cbaddc62a3ae432a7f9e889 |
content/source.d.ts |
39063c59528ad5ccc11aa3724118b3e5 |
content/chunker.js |
0edd97f2bb59fc1b4f3ae8996dfed467 |
content/source.js |
2aaae850c8a5d08dce5a39644190f08f |
content/crypto.d.ts |
cac34d85ed9b5a368a3c67f7aa742b75 |
content/store.d.ts |
3f74bbc26c2657cf7434473cf6a2d449 |
content/crypto.js |
4893aa35c0e727c7d54c3f2720e24359 |
content/store.js |
1a4a95ed509937a2eba559c702ecd8aa |
content/peer.d.ts |
5ed40ea5e7585fda8b00a38281d345e9 |
identity.d.ts |
fc3e1a74e0bdc84f8b19b7585808a799 |
content/peer.js |
52e141133a5b7b554ee63b1dd410e01d |
identity.js |
77eadb32405fdeb3d0911f00e48b1d81 |
content/runtime.d.ts |
921239ed101615eb6d314902cef56c60 |
index.d.ts |
6782b7ab87aeb33521428d360824b3a1 |
content/runtime.js |
7fe548c42b71b9e4785f139561fe8925 |
index.js |
0b33a15f20c40f66796b2291c672e660 |
main.js |
205f65b5252faccd9fc1f4c7d12f2d1f |
web/server.js |
88259233ec5fac88a3085b5180fb538b |
✅ 不一致条数 = 0(四处 × 18 = 72 个点位全部同值;🔴 relay 类产物两边都铺,⛔ 未出现序㉖ 那类"dshs 侧落后一版")。
- 四处
node --check/require自检通过。
② 密钥文件(两机同名同权限):
47 : 600 root:root 148 /etc/dshs/content-group-key.json
106 : 600 root:root 148 /etc/dshs/content-group-key.json
(md5 两机同 = 42d01c359abd59136d707ae89fb6ee7b)
③ 启用开关(relay 侧 drop-in,两机同铺):41-content-crypto.conf(2134 B、纯 LF、md5 1b2b530a7e3892fe54fd0d294ba694c1);只加 1 行 env:
[Service]
Environment="DSHS_CONTENT_GROUP_KEY_FILE=/etc/dshs/content-group-key.json"
⛔ 不含任何既有生产键;⚠️ 注释里刻意不写 RELAY_FAILOVER_COOLDOWN_MS=0 字面量(否则 §9-1 的 grep -c 判据会脏)。
④ 重启与时刻:daemon-reload + restart dshs-relay ⇒ 47 = 06:55:59 / 106 = 06:56:02;两机日志均出
[content-crypto] 组密钥已装载 file=/etc/dshs/content-group-key.json group=relay epoch=1 epochs=1 keyId=3560130eb0e5e4aa perms=0600 ✓;
/status.content.crypto = {encrypts:3, decrypts:3, decryptRejected:0, epochs:1, epoch:1, epochExpired:0, detChecks:1, detMismatches:0, plainScans:1, plainLeaks:0}。
环境收口(按序㉙ 顺序):restart dshs-worker → restart dshs → 一次真实访问(mksess.cjs guest + POST /api/dsh/enter,Host = alotbuy.com)⇒ 端点表 19000/21000 全 True(孤儿端口未复发)。
⑤ 回滚点:/opt/dsh/backups/seq28-20260918-065104/(47 与 106 各 4 处旧产物;旧 md5 全留档 —— backup47.txt / backup106.txt;⚠️ 其中 content/crypto.* 与 47/106 平台的 content/runtime.* 开工为 MISSING ⇒ 回滚 = 删文件,见 §6 路 B)。
8.9 判据 F1–F7(逐条原文)
| # | 判据 | 原文(命令 ⇒ 输出摘录) | 判定 |
|---|---|---|---|
| F1 | 同组密文一致 | node _tmp_seq31/f_evidence.mjs ⇒ 密文#1 md5 = 密文#2 md5 = 3385e9d00ae5c5dbb880ddad90391756、逐字节相同 = true |
✅ 通过 |
| F2 | 共享不退化 | 探针夹具 ON ⇒ decrypts=6 decryptRejected=0 local+peer 命中=5;单测 F2 共享不退化… local 命中递增且解密成功 |
✅ 通过 |
| F3 | 跨组不可解 | F3 跨组不可解:组 B 用自己的密钥解组 A 的密文 ⇒ 拒 + decryptRejected +1;夹具 CROSS ⇒ decryptRejected=1;F3-b 跨组判定不被放松 ✅ |
✅ 通过(crossGroupDenied 语义未变) |
| F4 | 明文不出现(+反向证明) | ① 密文里扫标记 = 命中 0(样本 3804 B);② 反向:不加密字节里扫同标记 = 命中 ≥ 1;正向 plainScans=1 plainLeaks=0、反向 plainScans=1 plainLeaks=1(⛔ 非 0 ⇒ 这条腿有牙) |
✅ 通过(① ② 都在,⛔ 未踩 §9-4) |
| F5 | E1 主判据不退化 |
F5/E1 口径:加密前后"回源份数"不变(同组 N 次取用 ⇒ 全部 local 命中、零回源);断言 4 轮 × 3 块,全部 local 命中(= E1 的"回源 1 份"口径) = source.local = 12、F2-b 同一份内容重复 put ⇒ cache 不翻倍 |
✅ 通过(⛔ 未从 1.0000× 退回 4.00×) |
| F6 | 失败关闭(具名) | 七例逐例具名:no-file / bad-perms / parse-error / group-mismatch / bad-key / bad-epoch / prev-key-bad(+正例);例:bad-perms ⇒ 权限 666(必须 0600)、group-mismatch ⇒ 文件 group=relay ≠ 运行时 group=local |
✅ 通过 |
| F7 | 零回归 | 见 8.10 | ✅ 通过 |
8.10 零回归三件套
全部带 --table "E:/ProgramData/AI技能/aliyun-dsh-server/参数表_覆盖网络_20260917.md";收口稳态(S7-npmtest.txt / S7-drill.txt / S7-probe-terminal.txt):
| 件 | 命令 | 基线(开工现核) | 收口实测 | 判定 |
|---|---|---|---|---|
| 单元测试 | npm.cmd test(Node 22) |
201 tests / 200 pass / 0 fail / 1 skip | 201 / 200 / 0 / 1 | ✅ 逐字不退化 |
| 演练 | node scripts/overlay-failover-drill.cjs --scene all --table "<参数表>" |
12 PASS / 0 SKIP / 0 FAIL | 12 PASS / 0 SKIP / 0 FAIL | ✅ |
| 探针 | node scripts/overlay-probe.cjs --table "<参数表>" |
稳态 22 PASS / 0 SKIP / 0 FAIL | 23 PASS / 0 SKIP / 0 FAIL(rc=0) | ✅ 净 +1 行(新增 = OBS-23 PASS) |
OBS-23 终态原文(关键尾段):
PASS OBS-23 组密钥加密(GCM 确定性)判别器 齐全|F1 确定性 detChecks=1(阈值 ≥ 1) detMismatches=0(须 0)
|F2 共享 decrypts=3(阈值 ≥ 1) decryptRejected=0(须 0) local+peer 命中=2(阈值 ≥ 1)
|F4① 明文扫描 plainScans=1(阈值 ≥ 1) plainLeaks=0(须 0)|epoch=1/1 epochExpired=0
|密钥文件 /etc/dshs/content-group-key.json 权限须=600:47=600 106=600
8.11 边界自证
| 边界 | 证据 | 判定 |
|---|---|---|
| ⛔ 未改任何生产值(D1) | 新 drop-in 只 1 行 env;⛔ 未动 RELAY_FAILOVER_* / HB_SEC / burst / PRESENCE_* / DSHS_CONTENT_STORE_* / DSHS_OVERLAY_*;40-content-probe.conf 两机 md5 同 = 9e7ccf9a8e59fc88367cea0a07c3d8b8(未被动) |
✅ |
| ⛔ 未新增公网监听口 | 仅新增文件落点 /etc/dshs/;ss -lntp 面未见新口(relay 仍只绑回环 20080) |
✅ |
⛔ 未改 nft / nginx |
全程零 nft / nginx 命令(R5) |
✅ |
| ⛔ 未放松跨组 | F3-b / F3-c ✅;crossGroupDenied 语义未变;E5 无退化 |
✅ |
🔴 RELAY_FAILOVER_COOLDOWN_MS=0 计数 |
grep -rIls "RELAY_FAILOVER_COOLDOWN_MS=0" /etc/systemd/system /etc/dshs | wc -l ⇒ 47 = 0 / 106 = 0 |
✅ = 0 |
| 🔴 密钥本体 ⛔ 不经网络、不经 relay | 只走 0600 落文件 + scp;中继侧只广播 (network, group, epoch, keyId) 三元组(凭据逐字核:不含 key);relay 消息面 ⛔ 零新增密钥字段 |
✅ |
🔴 未改 bwrap 参数(47 = bubblewrap 0.4.0) |
本单未触碰任何 banner/沙箱参数(文件集见 §3.1) | ✅ |
| ⛔ 未 commit / 未 push(R7) | git rev-parse HEAD = 04776af4b130014b0f4db10de89b0ae982300afc;git ls-remote origin refs/heads/master = 同值(⇒ 未推);git status --porcelain | wc -l = 35 |
✅ |
| ⛔ 未建 04 孪生 / 未补占空号 | 本单不落 04 孪生(与本线全部 交接单_*.md 一致);63 仍为空号 |
✅ |
8.12 指纹
- 参数表 §10 口径指纹:
3b295a8c43aafc4a62c6f1a59ea0b43a(序㉚ 收口)→08c2835a7e9f0faef20f9c1d3e619d55(本棒收口;变更 = §3.9 新增 6 键CONTENT_KEY_FILE/CONTENT_KEY_FILE_MODE/CONTENT_EPOCH_GRACE_MS/CONTENT_CRYPTO_DET_MIN/CONTENT_CRYPTO_DECRYPT_MIN/CONTENT_CRYPTO_SCAN_MIN+ §6 新增OBS-23一行;口径 =sed '/^## §10 指纹/,$d' 参数表_覆盖网络_20260917.md | md5sum)。 - 本单 §8 前前缀(口径
sed '/^## §8 回报格式/,$d' <本单> | md5sum)=149596460288ca1a5b7abddc490f7909—— ✅ 回填后复跑逐字不变(§8 是截断点)。 - 全文 md5 / 行数:⛔ 不内嵌(自指)⇒ 现算
md5sum "E:/ProgramData/AI技能/aliyun-dsh-server/交接单_组密钥加密_20260918.md";回填前快照 =0412daf3dc8edf96c2fbe87bdefbdb29(356 行)。 - 归档号:130(本单孪生号;执行为 §11.1 记录,⚠️ 执行棒收官建档案时须重新现核取号)。
8.13 如实留档(必填,哪怕"没有")
① ⚠️ 单文一处内部不一致(本棒按 §5 实现,与 §4/S6 的措辞不同):§4/S6 写"新 OBS-23 对旧生产 ⇒ FAIL",而 §5 的 OBS-23 形状写"缺省不启用 = SKIP + 留痕(合法状态)"。本棒取了 SKIP(理由:既不静默绿、也不把"合法的没启用"误报成红)。⇒ "真机先红"改由权限腿取得(0600→0640 ⇒ FAIL 且点名 47=640 106=600,rc=1,全量仅 1 红),复绿后 23P/0S/0F。🔴 这条不是缺陷,是单文两处口径需统一 —— 建议下一棒在单里定稿(倾向保留 §5 的 SKIP 口径 + 把"先红"腿写清为权限腿)。
② ⚠️ 签名动作的命令未逐字留痕:sign-group-key 用的是 47 上既有签名者私钥,但 47 上没有 /opt/dshs/scripts/overlay-keyring.cjs、/tmp 亦无残留 ⇒ 本棒只能自证"凭据不载荷密钥本体 + 验签通过 + 篡改必失败",无法自证"私钥未出机"。⇒ 建议:把"组密钥签发"固化成 47 上的正式子命令(⛔ 不靠临时投放脚本)。另立小单,本棒不动。
③ ⚠️ 未测得"轮换后首轮回源字节数"(§10-2):本棒只证得"换组 ⇒ 100% 块 id 改变"(定性),未造 4 组 × 1 份包的轮换前后 E1 读数(定量)⇒ §10-2 仍未验证,⛔ 未编数。
④ ⚠️ 未测得加密性能开销(§10-1:N ≥ 5、p50/p95):⛔ 无数据,⛔ 不报单次。
⑤ ⚠️ OBS-23 修过一处真缺陷(本棒发现并已修):密钥文件权限检查门原为 cryptoFx === undefined ⇒ 只给 --content-fixture(不给 --content-crypto-fixture)时会偷偷 ssh 到生产机(与"夹具模式绝不 ssh"的契约面不一致)。已改为门 = !fixture。⇒ 属本单范围内的真缺陷修复,已复测六段夹具全符合预期。
⑥ ⚠️ 两处环境态本就存在、本棒未动:47 users/ 权限、106 残留 scope dsh-100002-844b8c29.scope(属既有 user 4092b965 的实例,转由认领机制管理);OBS-22 的 47 认领面 journalctl 原文 0 字节 = 读取失败(⛔ 不是"确无 summary")。
⑦ ✅ 临时 session 已清干净:DELETE FROM sessions WHERE user_agent='poc-curl2' ⇒ DELETE 3,残留 0。
⑧ ✅ _tmp_seq31/ 为本次临时证据目录(含夹具、脚本、原始输出),⛔ 未删除(待用户确认后再清);夹具 fx-*.json 仅本机,⛔ 未铺任何服务器。
8.14 序 ㉛ 执行棒回报(2026-09-18 07:33–07:5x · §10 未验证项补齐 + 口径定稿 + §8.13-② 结清)
🔬 开工门:
sed '/^## §8 回报格式/,$d' <本单> | md5sum=149596460288ca1a5b7abddc490f7909⇒ 逐字一致,✅ 通过(本条写在 §8 之后 ⇒ ⛔ 不影响该不变量)。 📁 证据目录 = 工作区根_tmp_seq32/(脚本.mjs/.sh+ 原始输出.txt,逐项对应下方);⚠️ 临时产物,⛔ 未删除(待确认后再清)。 ⚠️ 本棒性质 = 补测 + 小额固化 ⇒ ⛔ 未扩范围、⛔ 未改生产值、⛔ 未动代码(src/**零改动)。
8.14.1 主题 ① 加密性能开销(§10-1)—— ✅ 有原始读数
口径:同一台机、同一份首屏包 11,363,655 B / 11 块;先预热 2 次再测,n = 11;每轮 = 切块 + 加密 + put + get + 解密 全链总墙钟;两臂跑同一夹具;分位取 nearest-rank(⛔ 不插值、⛔ 不报单次)。
| 臂 | p50 | p95 | 吞吐 | 密文固定开销 | origin 命中 |
|---|---|---|---|---|---|
| 纯明文 | 22.636 ms | 23.020 ms | 502.02 MB/s | — | 0 |
| 组密钥加密 | 42.782 ms | 43.599 ms | 265.62 MB/s | +28 B/块 | 0 |
| 增量 / 比值 | +20.146 ms / 1.890× | +20.579 ms / 1.894× | — | — | — |
- 🔴 口径边界(⛔ 不许当端到端承诺):单核、页缓存全热、两臂均零回源 ⇒ 这是"加密层自身成本"的参照读数,⛔ 不是线上
E1读数。 - 原始输出 =
_tmp_seq32/p01-perf.txt(脚本p01-perf.mjs)。
8.14.2 主题 ② 轮换代价量化(§10-2)—— ✅ 结清 §8.13-③
夹具:4 组 × 4 节点,包 5,255,225 B / 6 块;组成员按需取块(local → peer → origin,命中即缓存);另设「不轮换」对照腿(⛔ 无对照腿 ⇒ 无法断言"回源是轮换引起的")。
| 阶段 | 回源字节 | 相对包 | local/peer/origin |
块 id 改变 |
|---|---|---|---|---|
| 冷启动(轮换前) | 21,021,572 B | 4.0001 × 包 = 1 × 包/组 | 0 / 72 / 24 |
— |
| 轮换后首轮 | 21,021,572 B(比值 1.0000) | 同值 | — | 24 / 24 = 100% |
| 轮换后第二轮 | 0 | — | — | — |
| 对照腿(不轮换)第 3 轮 | 0 | — | — | — |
| 稳态(两腿) | 0 | — | — | — |
- ⇒ "轮换 = 一次完整冷启动(1 × 包/组)"已量化(与 §10-2 预期逐字吻合);"回源由轮换引起"可断言(对照腿第 3 轮 = 0)。
- 🔴 附带代价(本棒实测,原本未在册):旧 epoch 密文变垃圾且不自清 ——
storeBytes5,255,393 → 10,510,786(≈ 翻倍)。⇒ 回头条件 8(轮换须约在发布窗口)多了一条理由:不只是回源,还有存储占用翻倍直到旧块被逐出。 - 原始输出 =
_tmp_seq32/p02-rotate.txt(脚本p02-rotate.mjs;⚠️ v1 夹具曾因"包预置进 local"造假绿postOverPre = NaN,已重写后取上表读数)。
8.14.3 主题 ③ 低熵明文的定性结论(§10-3)—— ✅ 定性成立,⛔ 不写"很安全"
| 模型 | 读数 | 结论 |
|---|---|---|
| A:持组密钥者 | 字典枚举 1000 条 = 11.644 ms(≈ 85,878 条/秒)、命中 1、恢复正确(域 2³² ⇒ 全量 ≈ 14.7 h) | 枚举可行 ⇒ 低熵明文对持钥者无保护 |
| B:无钥者 / 中继 | 自造字典命中 0 / 1000;持有 1 对明文-密文也预测不出别的(0 / 999) | 枚举不可行 |
| B 的旁路:相等性泄露 | 10,000 块 / 100 值域 ⇒ 仅 100 种密文(收敛加密的固有性质) | 重复率 / 相等性可观测 |
| 反向腿(高熵对照) | 1000 / 1000 无碰撞 | ⛔ 证明"没测到 ≠ 真没有" |
- 🔴 定稿口径:"中继看不到明文" 成立 / "内容不可推断" 不成立(收敛加密对低熵必然泄露相等性)。⛔ 不写"很安全"。
- ⚠️ 夹具口径修正(本棒发现):初版语料用 LCG 低位取模(
x % 100)只出 37 个不同值 ⇒ 已改 xorshift32 取高位(x >>> 8) % 100⇒ 100 / 100,口径干净后取上表读数。 - 原始输出 =
_tmp_seq32/p03-lowentropy.txt(脚本p03-lowentropy.mjs)。
8.14.4 主题 ④ CONTENT_EPOCH_GRACE_MS 三档混存夹具(§10-6)—— ✅ 三档曲线齐
夹具:混存 20 块(写 epoch 4 + 历史 1 / 2 / 3),retiredAt = T0 / T0+2h / T0+12h,时钟注入 now(⛔ 不许真等)。
| 档 | 取值 | 归零时刻 | 窗口内 epochExpired |
超窗行为 |
|---|---|---|---|---|
| 小 | 60 s | t = +24 h | 0 | 逐 epoch 点名 + decryptRejected +1 |
| 中(当前值) | 24 h | t = +48 h | 0 | 同上 |
| 大 | 7 d | t = +8 d | 0 | 同上 |
- 曲线形状 = 阶梯衰减(最晚
retiredAt+ 本值 = 归零);写 epoch 恒 5 / 5 可解(⛔ 旧密文过期不影响写侧)。 - ⇒ 定稿见 §11.5 定稿三(当前值 24 h 维持,⛔ 本棒未改任何值)。
- 原始输出 =
_tmp_seq32/p04-epoch.txt(脚本p04-epoch.mjs)。
8.14.5 主题 ⑤ 单文口径定稿 —— ✅ 写进 §11.5(⛔ §4 / §6 正文零改动)
- 定稿一:
OBS-23对"缺省不启用"取SKIP + 留痕;§4/S6 那句「对旧生产必 FAIL」作废;"真机先红"腿由「权限腿」承载。 - ⚠️ §8.13-① 的口径张力至此结清(⛔ 未打穿 §8 前前缀:修正一律写在 §8 之后)。
- 权限腿读数(单 B 实测,本棒复核同值):
0600 → 0640⇒OBS-23FAIL 并点名47=640 106=600、rc=1、全量仅 1 红 ⇒ 还原即复绿。⇒ §10-4(0600运维一致性)由此覆盖(逐机实读权限 + "权限错必失败关闭"两条腿都有)。
8.14.6 主题 ⑥ 组密钥签发固化(结清 §8.13-② 缺口)—— ✅ 已落正式路径
| 项 | 证据 |
|---|---|
| 落点(两处) | /opt/dsh-relay/scripts/overlay-keyring.cjs(就地更新:旧版 12,915 B、grep -c sign-group-key = 0)+ /opt/dshs/scripts/overlay-keyring.cjs(此前不存在 = §8.13-② 的缺口) |
| 字节一致 | 两处 md5 均 f1855eaef30f71fbca00ac0a92865c0e(与本机同值) |
| 在机验证 | sign-group-key ⇒ rc = 0,凭据 274 B(ops/relay epoch=1 keyId=3560130eb0e5e4aa),密钥本体出现 0 次|verify-group-key ⇒ rc = 0|篡改 epoch ⇒ signature-mismatch rc = 1|--epoch 9 交叉核对 ⇒ rc = 1 |
| 回滚点 | 47 /opt/dsh/backups/seq31-20260918-073857/ |
| ⛔ 未重启 | 纯 CLI,⛔ 未重启任何 unit(⛔ 未中断任何用户) |
8.14.7 零回归三件套(三者均带 --table "E:/ProgramData/AI技能/aliyun-dsh-server/参数表_覆盖网络_20260917.md")
| 项 | 结果 | 与开工基线 |
|---|---|---|
npm.cmd test(Node 22) |
201 tests / 200 pass / 0 fail / 1 skipped ⇒ 注入脚本「结论:全部合格 ✅��� | 逐字相同 ✅ |
overlay-failover-drill.cjs --scene all --table |
12 PASS / 0 SKIP / 0 FAIL(rc = 0) | 同值 ✅ |
overlay-probe.cjs --table |
23 PASS / 0 SKIP / 0 FAIL(rc = 0) | 与开工基线 23P/0S/0F 一致 ✅ |
- 🔬 本棒三件套的"先红 → 后绿"过程(如实留档):环境收口期间(重排实例落点)曾出现 19P/1S/3F(
OBS-01 used=1/OBS-04 identityOk=1/OBS-08 端点表 0 条)与 22P/1S/0F(OBS-09SKIP,因实例暂落端口 21001)。未编数、未凑绿 —— 依据序 ㉙ 留档的机制(孤儿端点条目不自愈,靠"重新登记同一端口"覆盖),用/api/dsh/stop+/api/dsh/enter把实例落回 21000 ⇒OBS-09转 PASS(w-106:39027=401)、OBS-21复绿(两路径 count = 3)⇒ 23P/0S/0F。 - 原始输出 =
_tmp_seq32/base-npmtest.txt/final-drill.txt/final-probe-1..4.txt。
8.14.8 恢复形态核实 + 参数表 & 日志
- 参数表:§3.9
CONTENT_EPOCH_GRACE_MS行说明列补序㉛ 三档曲线|§6OBS-23行末补「口径定稿」|§7 补「序㉛ 复算:仍为待测0 项(⛔ 未新增键、⛔ 未改任何值)」|新增 §11.3 补记(六条)。 - 🔴 §10 指纹:
08c2835a7e9f0faef20f9c1d3e619d55→52e59df229102d5afa8c8bf01a960398(本棒收口现算 + 已同步;口径 = 先sed '/^## §10 指纹/,$d'截断再 md5)。⛔ 本轮零键零值变更 ⇒ 探针取阈值不受影响。 - 本单全文 md5:⛔ 不写死 ⇒ 现算
md5sum "E:/ProgramData/AI技能/aliyun-dsh-server/交接单_组密钥加密_20260918.md"。
8.14.9 边界自证(本棒)
| 边界 | 证据 | 判定 |
|---|---|---|
| ⛔ 未 commit / 未 push(R7) | HEAD 仍 04776af;⛔ 未执行任何 git commit / git push |
✅ |
| ⛔ 未改任何生产值(D1) | 两机 env / drop-in 零改动;⛔ 未动 RELAY_FAILOVER_* / HB_SEC / burst / PRESENCE_* / DSHS_CONTENT_* |
✅ |
⛔ 未新增公网监听口、⛔ 未改 nft / nginx(R5) |
全程零 nft / nginx 命令;OBS-11 多出 0 |
✅ |
🔴 RELAY_FAILOVER_COOLDOWN_MS=0 |
⛔ 全程未出现在任何夹具 / 脚本 / 演练路径(本棒新增文件逐字核 = 0) | ✅ = 0 |
⛔ 未改 bwrap 参数(47 = 0.4.0) |
本棒未触碰任何沙箱参数 | ✅ |
| 🔴 密钥本体 ⛔ 不经网络 / 不经 relay | 签发只在 47 本机(凭据 274 B、不含密钥本体、⛔ 未 scp 任何密钥) |
✅ |
| 🔴 Ed25519→X25519 派生 | ⛔ 本棒未执行(不在写死主题内 ⇒ 未扩范围) | ✅ 未越线 |
8.14.10 ⚠️ 如实留档(本棒"没有"的部分,必填)
① ⚠️ §10-5(Ed25519→X25519 派生预研)本轮未做:它不在本棒写死的六项主题内(用户明令「⛔ 不许顺手扩大范围」)⇒ 无读数、⛔ 未编数。它服务的对象是 §9 回头条件 7("规模上来了要自动分发组密钥")⇒ 触发条件 = 规模上来,⛔ 不是当前执行项。
② ⚠️ §10-4 未单独跑"铺发后逐机 ls -l / stat":读数改由 OBS-23 权限腿承载(47=600 106=600 + 0600→0640 ⇒ FAIL 并点名)⇒ 判据覆盖成立,但取证形态不同(探针读 vs 手工 stat)。
③ ⚠️ 性能读数是本机、单核、页缓存全热(§8.14.1 口径边界)⇒ ⛔ 不得外推为线上 E1 承诺。
④ ⚠️ 轮换夹具的存储翻倍(§8.14.2)是发现的新代价,⛔ 未做"旧块何时被逐出"的量化(⇒ 记为待观察,⛔ 不冒充已验证)。
⑤ ✅ 临时 session 已清干净:DELETE FROM sessions WHERE user_agent='poc-curl2' ⇒ 「DELETE 行数 = 1」、残留 = 0。
⑥ ✅ _tmp_seq32/ 为本棒临时证据目录,⛔ 未删除(待用户确认后再清)。
§9 回头条件(一出现必须回头)
- 🔴 ⛔ 任何一棒都不许把
RELAY_FAILOVER_COOLDOWN_MS=0写进回滚 / 演练 / 夹具路径(自锁:实测 121–123 s 无切换)。本单验收里grep -c该值必须 = 0。 E5退化(跨组穿透 > 0,或crossGroupDenied语义被放松)⇒ 立刻回滚 + 报告。F1不成立(同组两次加密密文不同)⇒ 停下报告("按哈希共享块"已失效,继续做只会放大回源)。F4只绿其①、②未做(没有反向夹具证明"没测到 ≠ 真没有")⇒ 判据不算通过,停下补证。- 需要超出 §3.1 在册文件集(尤其要动
wire.ts帧格式 /keys.ts既有语义)⇒ 停下报告(R7)。 decryptRejected在稳态下持续增长(⇒ 有节点密钥/epoch 不一致)⇒ 停下报告,⛔ 不许"重启一次看看"。- 规模上来了要"自动分发组密钥" ⇒ 停下报告(需先给节点密钥加
x25519或做 Ed25519→X25519 派生 ⇒ 属新增密钥类型,另立单)。 - 轮换窗口出现在非发布期(⇒ 一次全量回源砸在用户活跃时段)⇒ 停下报告,把轮换改约到发布窗口。
- 性能不达标(加密后
E1/吞吐显著变差)⇒ 先量化再决定,⛔ 不许凭感觉回滚。
§10 未验证项(一个都不许编数)
| # | 未验证项 | 为什么重要 | 怎么验(口径) |
|---|---|---|---|
| 1 | 加密的性能开销 | 决定"兼得"是否真的兑现 | 同一台机、同一份 10.8 MB 首屏包,测 N ≥ 5 次的"切块 + 加密 + put + get + 解密"总墙钟与纯明文对照;⚠️ 记 p50 / p95,⛔ 不报单次 |
| 2 | 轮换的实际代价 | β' 的核心代价是"轮换 = 一次全量回源" | 造 4 组 × 1 份包,轮换前后各跑一次 E1 口径 ⇒ 记录回源字节(预期:轮换后首轮 ≈ 1 份 × 组数,之后回落到 1×) |
| 3 | 收敛加密对低熵内容的安全性 | 收敛加密对低熵明文有已知的确认攻击面(可枚举) | 用低熵样本(如小文本块)验证:能否由密文反推明文集合;口径 = 只做定性结论,⛔ 不写"很安全" |
| 4 | 0600 密钥文件的运维一致性 |
本线有"属主被改 ⇒ 实例全崩"的先例 | 铺发后逐机 ls -l + stat;并验"权限错时必须失败关闭而不是静默明文" |
| 5 | Ed25519→X25519 派生可行性(为回头条件 7 预研) | 决定"自动分发"能不能不新增密钥类型 | 纯本地实验:从 ed25519 私钥导出 raw scalar ⇒ 构造 x25519 KeyObject ⇒ ECDH 往返成功?(⚠️ 只做实验、⛔ 不进本单代码) |
| 6 | 双 epoch 过渡窗口的取值 | 太长 ⇒ 旧密钥留太久(安全);太短 ⇒ 老节点掉线 | 用 CONTENT_EPOCH_GRACE_MS 三档(小/中/大)各跑一次混存夹具,记录"旧密文可解的比例随时间" |
§11 指纹与状态
11.1 归档号(本棒已原子占号)
- 现核最大号(⛔ 不写死;取号命令):
ls 04-调整方案/ | grep -oE '^[0-9]+' | sort -n | tail -1⇒ 本棒实测 =128。 ⚠️ prompt 写的"归档编号至 112"已过期(现核 128)⇒ 引用时必须复跑取号。 - 占号动作(已执行):
mkdir 04-调整方案/.lock-130⇒ 成功 ⇒ 本单归档号 = 130(单 A = 129)。 - 🔴 63 是空号,⛔ 不补占(已核:
ls 04-调整方案/ | grep -E '^63'= 空)。 - ⚠️ 本棒不落 04 孪生(本线
交接单_*.md均无 04 孪生;带孪生的是方案类文档 —— 逐条比对 16 份单 = 0 命中)⇒ 占号窗口在落单后即释放,执行棒收官建档案时须重新现核取号。
11.2 指纹
- §8 前前缀(口径:
sed '/^## §8 回报格式/,$d' <本单> | md5sum):见下方"落单后实测"。 - ⚠️ §8 回填后前缀指纹不变、全文 md5 会变。
- 落单后实测(2026-09-18 00:5x,序 ㉘ 规划棒):
- §8 前前缀 =
149596460288ca1a5b7abddc490f7909(⚠️ 本值稳定 —— §11 在截断点之后) - 全文 md5(§11 本段回填前快照) =
ef7aad0cf65f4d83221f46e60caa96ed - 全文 md5(§11 本段回填后最终) =
见下方 §11.4(写完本段后现算) - 行数 = 344(快照时刻;回填 §8 后会增长)
- §8 前前缀 =
11.3 状态
- 本单状态:✅ 已执行收官。拆两棒:单 B 执行棒(2026-09-18 06:22–07:2x)= 代码 + 部署 + 判据 F1–F7 ⇒ 证据见 §8.1–§8.13;序 ㉛ 执行棒(2026-09-18 07:33–07:5x)= §10 未验证项补齐 + 口径定稿 + §8.13-② 缺口结清 ⇒ 证据见 §8.14 / 定稿见 §11.5。
- 本棒(序 ㉘ 规划棒)边界自证:⛔ 零代码改动 · ⛔ 零服务器改动 · ⛔ 未 commit / 未 push · ⛔ 不改任何生产值 · ⛔ 未实现任何加密(本单只出方案 + 判据)。
- 两单关系:单 A(归档号 129)与单 B(130)文件集零交集,可并行;⚠️ 但同一时刻只挂一个接续棒(用户 2026-09-18 00:3x 明令)⇒ 执行顺序由下游定序理由决定(见入口 §2 的定序段)。
11.4 全文 md5 的口径(⛔ 不写死)
- 全文 md5 每改一次本单都会变(回填 §8 尤其)⇒ 权威取数 = 现算:
md5sum "E:/ProgramData/AI技能/aliyun-dsh-server/交接单_组密钥加密_20260918.md" - 落单快照(§11.4 本段写入前的最后一次现算,2026-09-18 00:5x)=
40d35357a501596dcd1e6d7e70e8b371(349 行)。 ⚠️ 本行写入后该值即失效 ⇒ 引用前必须复跑上面的命令。 - §8 前前缀 不受影响(§8 是截断点)⇒ 仍是 §11.2 的
149596460288ca1a5b7abddc490f7909。
11.5 🔴 口径定稿(2026-09-18,序 ㉛ 执行棒)—— 本行起具最高效力
效力范围:本单 §4 / §6 的正文一个字都没改(⛔ 不能改 —— 见下"为什么")。凡 §4 / §6 / §5 之间口径打架处,一律以本节的裁决为准。
定稿一:OBS-23 对"缺省不启用"取 SKIP + 留痕(⛔ 不是 FAIL)
- 裁决:§5 与 §6 的形状正确,§4/S6 里那句「新
OBS-23对旧生产** ⇒ FAIL」作废。** - 理由:① "缺省不启用"是合法状态(本单的设计目标就是"缺省不启用 ⇒ 行为逐字回到序㉔"),把它判红 = 把合法态误报成故障 ⇒ 长期挂假红会磨掉判据灵敏度(新红项会被"反正是红的"淹没 —— 这是本线已复盘过的教训);② 探针实现里 SKIP 行不进红计数,且必打留痕(打印"⛔ 未启用组密钥加密(
content.crypto块缺席)⇒ SKIP + 留痕"),⛔ 既不是静默绿、也不是假红。 - 🔴 "真机先红"这条腿由「权限腿」承载(单 B 已实测):把
CONTENT_KEY_FILE从0600改0640⇒OBS-23FAIL 并分别点名两台机的实读权限(47=640 106=600)、rc=1、全量仅 1 红 ⇒ 还原即复绿。⇒ 判据有牙,且"有牙"这件事不依赖"是否启用加密"。 - ⛔ 仍然禁止:出现"既不是 SKIP 也不是 FAIL"的第三态(静默绿)。
定稿二:β′(块 id 挂密文)的既有代价,本轮已量化,⛔ 不再当"未验证"
- 轮换代价 = 一次完整冷启动:4 组 × 4 节点夹具实测 —— 冷启动回源 21,021,572 B = 4.0001 × 包 = 1 × 包/组,轮换(epoch 1→2,块 id 改变 100%)后首轮同值(
比值 = 1.0000),第二轮起 0;对照腿(不轮换)第 3 轮 = 0 ⇒ "回源是轮换引起的"可断言。⚠️ 附带代价 = 旧 epoch 密文变垃圾且不自清(storeBytes5,255,393 → 10,510,786)。 - 加密性能开销:同一份 11,363,655 B 首屏包、n = 11 ⇒ 总墙钟 p50 22.636 → 42.782 ms、p95 23.020 → 43.599 ms(1.890× / 1.894×,绝对 +20.1 / +20.6 ms);吞吐 502.02 → 265.62 MB/s。⚠️ 口径 = 单核、页缓存全热的本机读数 ⇒ 是"加密层自身成本"的参照,⛔ 不是端到端承诺。
- 低熵明文的定性结论:持组密钥者可枚举恢复(1000 条域 11.644 ms、命中 1);**中继(无密钥)**枚举不可行(自造字典命中 0/1000,持有 1 对明文-密文也预测不出别的),但能观测相等性 / 重复率(10,000 块 / 100 值域 ⇒ 仅 100 种密文)⇒ ⛔ 不写"很安全":安全边界 = "中继看不到明文"成立,但"内容不可推断"不成立。
- ⇒ 这三条不再是 §10 的"未验证项"(原始读数见参数表 §11.3 补记 + 本单 §8.14;脚本原文 = 工作区
_tmp_seq32/p01-perf.txt/p02-rotate.txt/p03-lowentropy.txt/p04-epoch.txt)。
定稿三:CONTENT_EPOCH_GRACE_MS 的选值口径
- 判定式 = "轮换后还允许旧密文被解多久";实测归零时刻 = 最晚
retiredAt+ 本值(小 60 s ⇒ 24 h;中 24 h ⇒ 48 h;大 7 d ⇒ 8 d,阶梯衰减、窗口内epochExpired=0)。 - ⛔ 太短 ⇒ 尚未换完钥的节点掉线;太长 ⇒ 旧密钥留太久(安全)。⚠️ 轮换时点必须约在发布窗口(§9-8)。⇒ 当前值 24 h 维持(⛔ 本棒不改任何值)。
为什么 §4 / §6 正文不能改(写下来,防下一位读者"好心改回去")
- 本单的 §8 前前缀
149596460288ca1a5b7abddc490f7909是一条不变量("§8 是截断点")—— 它的作用是证明"计划在接受执行后没被人偷改"。动 §4/§6/§5 里任何一个字都会打穿这条证据链。⇒ 凡口径修正,一律写在 §8 之后(本节 + §8.14),并在引用时指明"以 §11.5 为准"。